From 25e9006a0b69d14fc7083979c6b764e3cf39addc Mon Sep 17 00:00:00 2001 From: Pierre8rTeam Date: Fri, 9 Mar 2018 16:43:19 +0100 Subject: [PATCH] First commit [09/03/2018] --- .gitignore | 3 + Experts/Advisors/ExpertMACD.mq5 | 168 + Experts/Advisors/ExpertMAMA.mq5 | 175 + Experts/Advisors/ExpertMAPSAR.mq5 | 171 + .../Advisors/ExpertMAPSARSizeOptimized.mq5 | 176 + .../Examples/ChartInChart/ChartInChart.mq5 | 353 + Experts/Examples/Controls/Controls.mq5 | 45 + Experts/Examples/Controls/ControlsDialog.mqh | 427 + Experts/Examples/MACD/MACD Sample.mq5 | 451 + .../Moving Average/Moving Average.mq5 | 233 + Images/dollar.bmp | Bin 0 -> 4152 bytes Images/euro.bmp | Bin 0 -> 4152 bytes Include/Arrays/Array.mqh | 182 + Include/Arrays/ArrayChar.mqh | 771 + Include/Arrays/ArrayDouble.mqh | 777 + Include/Arrays/ArrayFloat.mqh | 778 + Include/Arrays/ArrayInt.mqh | 770 + Include/Arrays/ArrayLong.mqh | 770 + Include/Arrays/ArrayObj.mqh | 759 + Include/Arrays/ArrayShort.mqh | 770 + Include/Arrays/ArrayString.mqh | 780 + Include/Arrays/List.mqh | 657 + Include/Arrays/Tree.mqh | 415 + Include/Arrays/TreeNode.mqh | 174 + Include/Canvas/Canvas.mqh | 4804 ++ Include/Canvas/Charts/ChartCanvas.mqh | 1041 + Include/Canvas/Charts/HistogramChart.mqh | 347 + Include/Canvas/Charts/LineChart.mqh | 383 + Include/Canvas/Charts/PieChart.mqh | 414 + Include/Canvas/FlameCanvas.mqh | 751 + Include/ChartObjects/ChartObject.mqh | 1000 + Include/ChartObjects/ChartObjectPanel.mqh | 198 + Include/ChartObjects/ChartObjectSubChart.mqh | 397 + Include/ChartObjects/ChartObjectsArrows.mqh | 486 + .../ChartObjects/ChartObjectsBmpControls.mqh | 512 + Include/ChartObjects/ChartObjectsChannels.mqh | 246 + Include/ChartObjects/ChartObjectsElliott.mqh | 201 + Include/ChartObjects/ChartObjectsFibo.mqh | 365 + Include/ChartObjects/ChartObjectsGann.mqh | 390 + Include/ChartObjects/ChartObjectsLines.mqh | 335 + Include/ChartObjects/ChartObjectsShapes.mqh | 142 + .../ChartObjects/ChartObjectsTxtControls.mqh | 887 + Include/Charts/Chart.mqh | 1549 + Include/Controls/BmpButton.mqh | 268 + Include/Controls/Button.mqh | 146 + Include/Controls/CheckBox.mqh | 183 + Include/Controls/CheckGroup.mqh | 377 + Include/Controls/ComboBox.mqh | 324 + Include/Controls/DateDropList.mqh | 413 + Include/Controls/DatePicker.mqh | 264 + Include/Controls/Defines.mqh | 190 + Include/Controls/Dialog.mqh | 971 + Include/Controls/Edit.mqh | 187 + Include/Controls/Label.mqh | 93 + Include/Controls/ListView.mqh | 544 + Include/Controls/Panel.mqh | 124 + Include/Controls/Picture.mqh | 125 + Include/Controls/RadioButton.mqh | 160 + Include/Controls/RadioGroup.mqh | 361 + Include/Controls/Rect.mqh | 279 + Include/Controls/Scrolls.mqh | 675 + Include/Controls/SpinEdit.mqh | 265 + Include/Controls/Wnd.mqh | 755 + Include/Controls/WndClient.mqh | 307 + Include/Controls/WndContainer.mqh | 472 + Include/Controls/WndObj.mqh | 262 + Include/Controls/res/CheckBoxOff.bmp | Bin 0 -> 576 bytes Include/Controls/res/CheckBoxOn.bmp | Bin 0 -> 576 bytes Include/Controls/res/Close.bmp | Bin 0 -> 1080 bytes Include/Controls/res/DateDropOff.bmp | Bin 0 -> 2104 bytes Include/Controls/res/DateDropOn.bmp | Bin 0 -> 2104 bytes Include/Controls/res/Down.bmp | Bin 0 -> 824 bytes Include/Controls/res/DownTransp.bmp | Bin 0 -> 1080 bytes Include/Controls/res/DropOff.bmp | Bin 0 -> 1080 bytes Include/Controls/res/DropOn.bmp | Bin 0 -> 1080 bytes Include/Controls/res/Left.bmp | Bin 0 -> 824 bytes Include/Controls/res/LeftTransp.bmp | Bin 0 -> 1080 bytes Include/Controls/res/RadioButtonOff.bmp | Bin 0 -> 632 bytes Include/Controls/res/RadioButtonOn.bmp | Bin 0 -> 632 bytes Include/Controls/res/Restore.bmp | Bin 0 -> 1080 bytes Include/Controls/res/Right.bmp | Bin 0 -> 824 bytes Include/Controls/res/RightTransp.bmp | Bin 0 -> 1080 bytes Include/Controls/res/SpinDec.bmp | Bin 0 -> 568 bytes Include/Controls/res/SpinInc.bmp | Bin 0 -> 568 bytes Include/Controls/res/ThumbHor.bmp | Bin 0 -> 1144 bytes Include/Controls/res/ThumbVert.bmp | Bin 0 -> 1112 bytes Include/Controls/res/Turn.bmp | Bin 0 -> 1080 bytes Include/Controls/res/Up.bmp | Bin 0 -> 824 bytes Include/Controls/res/UpTransp.bmp | Bin 0 -> 1080 bytes Include/Expert/Expert.mqh | 1606 + Include/Expert/ExpertBase.mqh | 715 + Include/Expert/ExpertMoney.mqh | 124 + Include/Expert/ExpertSignal.mqh | 464 + Include/Expert/ExpertTrade.mqh | 171 + Include/Expert/ExpertTrailing.mqh | 33 + Include/Expert/Money/MoneyFixedLot.mqh | 73 + Include/Expert/Money/MoneyFixedMargin.mqh | 76 + Include/Expert/Money/MoneyFixedRisk.mqh | 109 + Include/Expert/Money/MoneyNone.mqh | 71 + Include/Expert/Money/MoneySizeOptimized.mqh | 155 + Include/Expert/Signal/SignalAC.mqh | 173 + Include/Expert/Signal/SignalAMA.mqh | 265 + Include/Expert/Signal/SignalAO.mqh | 339 + Include/Expert/Signal/SignalBearsPower.mqh | 289 + Include/Expert/Signal/SignalBullsPower.mqh | 289 + Include/Expert/Signal/SignalCCI.mqh | 382 + Include/Expert/Signal/SignalDEMA.mqh | 257 + Include/Expert/Signal/SignalDeMarker.mqh | 378 + Include/Expert/Signal/SignalEnvelopes.mqh | 193 + Include/Expert/Signal/SignalFrAMA.mqh | 257 + Include/Expert/Signal/SignalITF.mqh | 91 + Include/Expert/Signal/SignalMA.mqh | 261 + Include/Expert/Signal/SignalMACD.mqh | 408 + Include/Expert/Signal/SignalRSI.mqh | 400 + Include/Expert/Signal/SignalRVI.mqh | 180 + Include/Expert/Signal/SignalSAR.mqh | 168 + Include/Expert/Signal/SignalStoch.mqh | 426 + Include/Expert/Signal/SignalTEMA.mqh | 257 + Include/Expert/Signal/SignalTRIX.mqh | 395 + Include/Expert/Signal/SignalWPR.mqh | 371 + Include/Expert/Trailing/TrailingFixedPips.mqh | 132 + Include/Expert/Trailing/TrailingMA.mqh | 156 + Include/Expert/Trailing/TrailingNone.mqh | 40 + .../Expert/Trailing/TrailingParabolicSAR.mqh | 123 + Include/Files/File.mqh | 292 + Include/Files/FileBin.mqh | 517 + Include/Files/FilePipe.mqh | 347 + Include/Files/FileTxt.mqh | 64 + Include/Generic/ArrayList.mqh | Bin 0 -> 50304 bytes Include/Generic/HashMap.mqh | 616 + Include/Generic/HashSet.mqh | 974 + Include/Generic/Interfaces/ICollection.mqh | 24 + Include/Generic/Interfaces/IComparable.mqh | 19 + Include/Generic/Interfaces/IComparer.mqh | 17 + .../Interfaces/IEqualityComparable.mqh | 19 + .../Generic/Interfaces/IEqualityComparer.mqh | 19 + Include/Generic/Interfaces/IList.mqh | 26 + Include/Generic/Interfaces/IMap.mqh | 27 + Include/Generic/Interfaces/ISet.mqh | 37 + Include/Generic/Internal/ArrayFunction.mqh | 135 + Include/Generic/Internal/CompareFunction.mqh | 209 + Include/Generic/Internal/DefaultComparer.mqh | 22 + .../Internal/DefaultEqualityComparer.mqh | 25 + Include/Generic/Internal/EqualFunction.mqh | 26 + Include/Generic/Internal/HashFunction.mqh | 176 + Include/Generic/Internal/Introsort.mqh | 251 + Include/Generic/Internal/PrimeGenerator.mqh | 79 + Include/Generic/LinkedList.mqh | 563 + Include/Generic/Queue.mqh | Bin 0 -> 23370 bytes Include/Generic/RedBlackTree.mqh | Bin 0 -> 74814 bytes Include/Generic/SortedMap.mqh | 341 + Include/Generic/SortedSet.mqh | 671 + Include/Generic/Stack.mqh | 227 + Include/Graphics/Axis.mqh | 260 + Include/Graphics/ColorGenerator.mqh | 74 + Include/Graphics/Curve.mqh | 700 + Include/Graphics/Graphic.mqh | Bin 0 -> 172684 bytes Include/Indicators/BillWilliams.mqh | 761 + Include/Indicators/Custom.mqh | 194 + Include/Indicators/Indicator.mqh | 512 + Include/Indicators/Indicators.mqh | 385 + Include/Indicators/Oscilators.mqh | 1722 + Include/Indicators/Series.mqh | 299 + Include/Indicators/TimeSeries.mqh | 1547 + Include/Indicators/Trend.mqh | 1717 + Include/Indicators/Volumes.mqh | 424 + Include/Math/Alglib/alglib.mqh | 23023 ++++++++ Include/Math/Alglib/alglibinternal.mqh | 9732 ++++ Include/Math/Alglib/alglibmisc.mqh | 1493 + Include/Math/Alglib/ap.mqh | 2175 + Include/Math/Alglib/arrayresize.mqh | 143 + Include/Math/Alglib/bitconvert.mqh | 531 + Include/Math/Alglib/complex.mqh | 345 + Include/Math/Alglib/dataanalysis.mqh | 15237 ++++++ Include/Math/Alglib/delegatefunctions.mqh | 412 + Include/Math/Alglib/diffequations.mqh | 928 + Include/Math/Alglib/fasttransforms.mqh | 2418 + Include/Math/Alglib/integration.mqh | 3092 ++ Include/Math/Alglib/interpolation.mqh | 13407 +++++ Include/Math/Alglib/linalg.mqh | 20339 +++++++ Include/Math/Alglib/matrix.mqh | 629 + Include/Math/Alglib/optimization.mqh | 12279 +++++ Include/Math/Alglib/solvers.mqh | 3829 ++ Include/Math/Alglib/specialfunctions.mqh | 6599 +++ Include/Math/Alglib/statistics.mqh | 13972 +++++ Include/Math/Fuzzy/dictionary.mqh | 197 + Include/Math/Fuzzy/fuzzyrule.mqh | 371 + Include/Math/Fuzzy/fuzzyterm.mqh | 69 + Include/Math/Fuzzy/fuzzyvariable.mqh | 113 + Include/Math/Fuzzy/genericfuzzysystem.mqh | 333 + Include/Math/Fuzzy/helper.mqh | 158 + Include/Math/Fuzzy/inferencemethod.mqh | 125 + Include/Math/Fuzzy/mamdanifuzzysystem.mqh | 552 + Include/Math/Fuzzy/membershipfunction.mqh | 1008 + Include/Math/Fuzzy/ruleparser.mqh | 1019 + Include/Math/Fuzzy/sugenofuzzysystem.mqh | 327 + Include/Math/Fuzzy/sugenovariable.mqh | 254 + Include/Math/Stat/Beta.mqh | 774 + Include/Math/Stat/Binomial.mqh | 876 + Include/Math/Stat/Cauchy.mqh | 541 + Include/Math/Stat/ChiSquare.mqh | 533 + Include/Math/Stat/Exponential.mqh | 522 + Include/Math/Stat/F.mqh | 565 + Include/Math/Stat/Gamma.mqh | 767 + Include/Math/Stat/Geometric.mqh | 569 + Include/Math/Stat/Hypergeometric.mqh | 756 + Include/Math/Stat/Logistic.mqh | 594 + Include/Math/Stat/Lognormal.mqh | 637 + Include/Math/Stat/Math.mqh | Bin 0 -> 434722 bytes Include/Math/Stat/NegativeBinomial.mqh | 645 + Include/Math/Stat/NoncentralBeta.mqh | 957 + Include/Math/Stat/NoncentralChiSquare.mqh | 914 + Include/Math/Stat/NoncentralF.mqh | 792 + Include/Math/Stat/NoncentralT.mqh | 1194 + Include/Math/Stat/Normal.mqh | 917 + Include/Math/Stat/Poisson.mqh | 793 + Include/Math/Stat/Stat.mqh | 29 + Include/Math/Stat/T.mqh | 656 + Include/Math/Stat/Uniform.mqh | 541 + Include/Math/Stat/Weibull.mqh | 576 + Include/MovingAverages.mqh | 240 + Include/Object.mqh | 33 + Include/OpenCL/OpenCL.mqh | 454 + Include/StdLibErr.mqh | 10 + Include/Strings/String.mqh | 377 + Include/Tools/DateTime.mqh | 581 + Include/Trade/AccountInfo.mqh | 378 + Include/Trade/DealInfo.mqh | 352 + Include/Trade/HistoryOrderInfo.mqh | 443 + Include/Trade/OrderInfo.mqh | 518 + Include/Trade/PositionInfo.mqh | 374 + Include/Trade/SymbolInfo.mqh | 749 + Include/Trade/TerminalInfo.mqh | 225 + Include/Trade/Trade.mqh | 1661 + Include/VirtualKeys.mqh | 201 + Indicators/Examples/AD.mq5 | 89 + Indicators/Examples/ADX.mq5 | 152 + Indicators/Examples/ADXW.mq5 | 184 + Indicators/Examples/AMA.mq5 | 130 + Indicators/Examples/ASI.mq5 | 112 + Indicators/Examples/ATR.mq5 | 96 + Indicators/Examples/Accelerator.mq5 | 140 + Indicators/Examples/Alligator.mq5 | 145 + Indicators/Examples/Awesome_Oscillator.mq5 | 120 + Indicators/Examples/BB.mq5 | 140 + Indicators/Examples/BW-ZoneTrade.mq5 | 132 + Indicators/Examples/Bears.mq5 | 93 + Indicators/Examples/Bulls.mq5 | 93 + Indicators/Examples/CCI.mq5 | 94 + Indicators/Examples/CHO.mq5 | 129 + Indicators/Examples/CHV.mq5 | 120 + Indicators/Examples/Canvas/FlameChart.mq5 | 73 + Indicators/Examples/ColorBars.mq5 | 80 + Indicators/Examples/ColorCandlesDaily.mq5 | 79 + Indicators/Examples/ColorLine.mq5 | 130 + Indicators/Examples/Custom Moving Average.mq5 | 183 + Indicators/Examples/DEMA.mq5 | 71 + Indicators/Examples/DPO.mq5 | 69 + Indicators/Examples/DeMarker.mq5 | 100 + Indicators/Examples/Envelopes.mq5 | 106 + Indicators/Examples/Force_Index.mq5 | 98 + Indicators/Examples/FrAMA.mq5 | 143 + Indicators/Examples/Fractals.mq5 | 87 + Indicators/Examples/Gator.mq5 | 260 + Indicators/Examples/Gator_2.mq5 | 248 + Indicators/Examples/Heiken_Ashi.mq5 | 88 + Indicators/Examples/Ichimoku.mq5 | 131 + Indicators/Examples/MACD.mq5 | 119 + Indicators/Examples/MFI.mq5 | 117 + Indicators/Examples/MI.mq5 | 118 + .../Examples/MarketFacilitationIndex.mq5 | 125 + Indicators/Examples/Momentum.mq5 | 70 + Indicators/Examples/OBV.mq5 | 91 + Indicators/Examples/OsMA.mq5 | 126 + Indicators/Examples/PVT.mq5 | 92 + .../Examples/Panels/ChartPanel/ChartPanel.mq5 | 64 + .../Panels/ChartPanel/PanelDialog.mqh | 375 + .../Panels/SimplePanel/PanelDialog.mqh | 346 + .../Panels/SimplePanel/SimplePanel.mq5 | 64 + Indicators/Examples/ParabolicSAR.mq5 | 199 + Indicators/Examples/Price_Channel.mq5 | 113 + Indicators/Examples/ROC.mq5 | 67 + Indicators/Examples/RSI.mq5 | 118 + Indicators/Examples/RVI.mq5 | 101 + Indicators/Examples/StdDev.mq5 | 129 + Indicators/Examples/Stochastic.mq5 | 132 + Indicators/Examples/TEMA.mq5 | 75 + Indicators/Examples/TRIX.mq5 | 83 + Indicators/Examples/Ultimate_Oscillator.mq5 | 179 + Indicators/Examples/VIDYA.mq5 | 98 + Indicators/Examples/VROC.mq5 | 98 + Indicators/Examples/Volumes.mq5 | 89 + Indicators/Examples/WPR.mq5 | 112 + Indicators/Examples/W_AD.mq5 | 95 + Indicators/Examples/ZigZag.mq5 | 297 + Indicators/Examples/ZigzagColor.mq5 | 288 + Profiles/Charts/British Pound/chart01.chr | Bin 0 -> 4434 bytes Profiles/Charts/British Pound/chart02.chr | Bin 0 -> 4432 bytes Profiles/Charts/British Pound/chart03.chr | Bin 0 -> 4432 bytes Profiles/Charts/British Pound/chart04.chr | Bin 0 -> 4434 bytes Profiles/Charts/British Pound/order.wnd | Bin 0 -> 106 bytes Profiles/Charts/Default/chart01.chr | Bin 0 -> 39022 bytes Profiles/Charts/Default/chart02.chr | Bin 0 -> 19600 bytes Profiles/Charts/Default/chart03.chr | Bin 0 -> 25378 bytes Profiles/Charts/Default/chart04.chr | Bin 0 -> 26646 bytes Profiles/Charts/Default/order.wnd | Bin 0 -> 106 bytes Profiles/Charts/Euro/chart01.chr | Bin 0 -> 4434 bytes Profiles/Charts/Euro/chart02.chr | Bin 0 -> 4432 bytes Profiles/Charts/Euro/chart03.chr | Bin 0 -> 4432 bytes Profiles/Charts/Euro/chart04.chr | Bin 0 -> 4434 bytes Profiles/Charts/Euro/order.wnd | Bin 0 -> 106 bytes Profiles/Charts/Market Overview/chart01.chr | Bin 0 -> 5652 bytes Profiles/Charts/Market Overview/chart02.chr | Bin 0 -> 3166 bytes Profiles/Charts/Market Overview/chart03.chr | Bin 0 -> 3022 bytes Profiles/Charts/Market Overview/chart04.chr | Bin 0 -> 3168 bytes Profiles/Charts/Market Overview/order.wnd | Bin 0 -> 106 bytes Profiles/SymbolSets/forex.all.set | Bin 0 -> 288 bytes Profiles/SymbolSets/forex.crosses.set | Bin 0 -> 218 bytes Profiles/SymbolSets/forex.major.set | Bin 0 -> 64 bytes Profiles/Templates/ADX.tpl | Bin 0 -> 4082 bytes Profiles/Templates/BollingerBands.tpl | Bin 0 -> 4866 bytes Profiles/Templates/Momentum.tpl | Bin 0 -> 7214 bytes Profiles/Templates/ReportHistory.htm | Bin 0 -> 28548 bytes Profiles/Templates/ReportTester.htm | Bin 0 -> 29422 bytes Profiles/Templates/ReportTrade.htm | Bin 0 -> 16510 bytes .../AccountInfo/AccountInfoSample.mq5 | 143 + .../AccountInfo/AccountInfoSampleInit.mqh | 17 + .../ArrayDouble/ArrayDoubleSample.mq5 | 102 + Scripts/Examples/Canvas/CanvasSample.mq5 | 211 + .../Canvas/Charts/HistogramChartSample.mq5 | 66 + .../Canvas/Charts/LineChartSample.mq5 | 66 + .../Examples/Canvas/Charts/PieChartSample.mq5 | 97 + .../Examples/ObjectChart/ChartSampleInit.mqh | 163 + .../Examples/ObjectChart/ObjChartSample.mq5 | 775 + Scripts/Examples/ObjectSphere/Sphere.mqh | 187 + .../Examples/ObjectSphere/SphereSample.mq5 | 81 + .../Examples/OpenCL/Double/BitonicSort.mq5 | 217 + Scripts/Examples/OpenCL/Double/FFT.mq5 | 311 + .../OpenCL/Double/Kernels/bitonicsort.cl | 31 + Scripts/Examples/OpenCL/Double/Kernels/fft.cl | 156 + .../OpenCL/Double/Kernels/matrixmult.cl | 69 + .../Examples/OpenCL/Double/Kernels/wavelet.cl | 51 + Scripts/Examples/OpenCL/Double/MatrixMult.mq5 | 225 + Scripts/Examples/OpenCL/Double/Wavelet.mq5 | 419 + Scripts/Examples/OpenCL/Float/BitonicSort.mq5 | 213 + Scripts/Examples/OpenCL/Float/FFT.mq5 | 306 + .../OpenCL/Float/Kernels/bitonicsort.cl | 28 + Scripts/Examples/OpenCL/Float/Kernels/fft.cl | 153 + .../OpenCL/Float/Kernels/matrixmult.cl | 66 + .../Examples/OpenCL/Float/Kernels/wavelet.cl | 48 + Scripts/Examples/OpenCL/Float/MatrixMult.mq5 | 219 + Scripts/Examples/OpenCL/Float/Wavelet.mq5 | 436 + .../Examples/OrderInfo/OrderInfoSample.mq5 | 200 + .../OrderInfo/OrderInfoSampleInit.mqh | 17 + .../PositionInfo/PositionInfoSample.mq5 | 196 + .../PositionInfo/PositionInfoSampleInit.mqh | 16 + .../Examples/SymbolInfo/SymbolInfoSample.mq5 | 214 + .../SymbolInfo/SymbolInfoSampleInit.mqh | 40 + Scripts/UnitTests/Alglib/TestClasses.mq5 | 427 + Scripts/UnitTests/Alglib/TestClasses.mqh | 43857 ++++++++++++++++ Scripts/UnitTests/Alglib/TestInterfaces.mq5 | 148 + Scripts/UnitTests/Alglib/TestInterfaces.mqh | 11821 +++++ Scripts/UnitTests/Fuzzy/TestFuzzy.mq5 | 661 + Scripts/UnitTests/Generic/TestArrayList.mq5 | 987 + Scripts/UnitTests/Generic/TestHashMap.mq5 | 186 + Scripts/UnitTests/Generic/TestHashSet.mq5 | 147 + Scripts/UnitTests/Generic/TestLinkedList.mq5 | 1991 + Scripts/UnitTests/Generic/TestQueue.mq5 | 259 + .../UnitTests/Generic/TestRedBlackTree.mq5 | 361 + Scripts/UnitTests/Generic/TestSortedMap.mq5 | 187 + Scripts/UnitTests/Generic/TestSortedSet.mq5 | 147 + Scripts/UnitTests/Generic/TestStack.mq5 | 259 + Scripts/UnitTests/Stat/TestStat.mq5 | 4855 ++ Scripts/UnitTests/Stat/TestStatBenchmark.mq5 | 1590 + Scripts/UnitTests/Stat/TestStatPrecision.mq5 | 288 + 375 files changed, 294601 insertions(+) create mode 100644 .gitignore create mode 100644 Experts/Advisors/ExpertMACD.mq5 create mode 100644 Experts/Advisors/ExpertMAMA.mq5 create mode 100644 Experts/Advisors/ExpertMAPSAR.mq5 create mode 100644 Experts/Advisors/ExpertMAPSARSizeOptimized.mq5 create mode 100644 Experts/Examples/ChartInChart/ChartInChart.mq5 create mode 100644 Experts/Examples/Controls/Controls.mq5 create mode 100644 Experts/Examples/Controls/ControlsDialog.mqh create mode 100644 Experts/Examples/MACD/MACD Sample.mq5 create mode 100644 Experts/Examples/Moving Average/Moving Average.mq5 create mode 100644 Images/dollar.bmp create mode 100644 Images/euro.bmp create mode 100644 Include/Arrays/Array.mqh create mode 100644 Include/Arrays/ArrayChar.mqh create mode 100644 Include/Arrays/ArrayDouble.mqh create mode 100644 Include/Arrays/ArrayFloat.mqh create mode 100644 Include/Arrays/ArrayInt.mqh create mode 100644 Include/Arrays/ArrayLong.mqh create mode 100644 Include/Arrays/ArrayObj.mqh create mode 100644 Include/Arrays/ArrayShort.mqh create mode 100644 Include/Arrays/ArrayString.mqh create mode 100644 Include/Arrays/List.mqh create mode 100644 Include/Arrays/Tree.mqh create mode 100644 Include/Arrays/TreeNode.mqh create mode 100644 Include/Canvas/Canvas.mqh create mode 100644 Include/Canvas/Charts/ChartCanvas.mqh create mode 100644 Include/Canvas/Charts/HistogramChart.mqh create mode 100644 Include/Canvas/Charts/LineChart.mqh create mode 100644 Include/Canvas/Charts/PieChart.mqh create mode 100644 Include/Canvas/FlameCanvas.mqh create mode 100644 Include/ChartObjects/ChartObject.mqh create mode 100644 Include/ChartObjects/ChartObjectPanel.mqh create mode 100644 Include/ChartObjects/ChartObjectSubChart.mqh create mode 100644 Include/ChartObjects/ChartObjectsArrows.mqh create mode 100644 Include/ChartObjects/ChartObjectsBmpControls.mqh create mode 100644 Include/ChartObjects/ChartObjectsChannels.mqh create mode 100644 Include/ChartObjects/ChartObjectsElliott.mqh create mode 100644 Include/ChartObjects/ChartObjectsFibo.mqh create mode 100644 Include/ChartObjects/ChartObjectsGann.mqh create mode 100644 Include/ChartObjects/ChartObjectsLines.mqh create mode 100644 Include/ChartObjects/ChartObjectsShapes.mqh create mode 100644 Include/ChartObjects/ChartObjectsTxtControls.mqh create mode 100644 Include/Charts/Chart.mqh create mode 100644 Include/Controls/BmpButton.mqh create mode 100644 Include/Controls/Button.mqh create mode 100644 Include/Controls/CheckBox.mqh create mode 100644 Include/Controls/CheckGroup.mqh create mode 100644 Include/Controls/ComboBox.mqh create mode 100644 Include/Controls/DateDropList.mqh create mode 100644 Include/Controls/DatePicker.mqh create mode 100644 Include/Controls/Defines.mqh create mode 100644 Include/Controls/Dialog.mqh create mode 100644 Include/Controls/Edit.mqh create mode 100644 Include/Controls/Label.mqh create mode 100644 Include/Controls/ListView.mqh create mode 100644 Include/Controls/Panel.mqh create mode 100644 Include/Controls/Picture.mqh create mode 100644 Include/Controls/RadioButton.mqh create mode 100644 Include/Controls/RadioGroup.mqh create mode 100644 Include/Controls/Rect.mqh create mode 100644 Include/Controls/Scrolls.mqh create mode 100644 Include/Controls/SpinEdit.mqh create mode 100644 Include/Controls/Wnd.mqh create mode 100644 Include/Controls/WndClient.mqh create mode 100644 Include/Controls/WndContainer.mqh create mode 100644 Include/Controls/WndObj.mqh create mode 100644 Include/Controls/res/CheckBoxOff.bmp create mode 100644 Include/Controls/res/CheckBoxOn.bmp create mode 100644 Include/Controls/res/Close.bmp create mode 100644 Include/Controls/res/DateDropOff.bmp create mode 100644 Include/Controls/res/DateDropOn.bmp create mode 100644 Include/Controls/res/Down.bmp create mode 100644 Include/Controls/res/DownTransp.bmp create mode 100644 Include/Controls/res/DropOff.bmp create mode 100644 Include/Controls/res/DropOn.bmp create mode 100644 Include/Controls/res/Left.bmp create mode 100644 Include/Controls/res/LeftTransp.bmp create mode 100644 Include/Controls/res/RadioButtonOff.bmp create mode 100644 Include/Controls/res/RadioButtonOn.bmp create mode 100644 Include/Controls/res/Restore.bmp create mode 100644 Include/Controls/res/Right.bmp create mode 100644 Include/Controls/res/RightTransp.bmp create mode 100644 Include/Controls/res/SpinDec.bmp create mode 100644 Include/Controls/res/SpinInc.bmp create mode 100644 Include/Controls/res/ThumbHor.bmp create mode 100644 Include/Controls/res/ThumbVert.bmp create mode 100644 Include/Controls/res/Turn.bmp create mode 100644 Include/Controls/res/Up.bmp create mode 100644 Include/Controls/res/UpTransp.bmp create mode 100644 Include/Expert/Expert.mqh create mode 100644 Include/Expert/ExpertBase.mqh create mode 100644 Include/Expert/ExpertMoney.mqh create mode 100644 Include/Expert/ExpertSignal.mqh create mode 100644 Include/Expert/ExpertTrade.mqh create mode 100644 Include/Expert/ExpertTrailing.mqh create mode 100644 Include/Expert/Money/MoneyFixedLot.mqh create mode 100644 Include/Expert/Money/MoneyFixedMargin.mqh create mode 100644 Include/Expert/Money/MoneyFixedRisk.mqh create mode 100644 Include/Expert/Money/MoneyNone.mqh create mode 100644 Include/Expert/Money/MoneySizeOptimized.mqh create mode 100644 Include/Expert/Signal/SignalAC.mqh create mode 100644 Include/Expert/Signal/SignalAMA.mqh create mode 100644 Include/Expert/Signal/SignalAO.mqh create mode 100644 Include/Expert/Signal/SignalBearsPower.mqh create mode 100644 Include/Expert/Signal/SignalBullsPower.mqh create mode 100644 Include/Expert/Signal/SignalCCI.mqh create mode 100644 Include/Expert/Signal/SignalDEMA.mqh create mode 100644 Include/Expert/Signal/SignalDeMarker.mqh create mode 100644 Include/Expert/Signal/SignalEnvelopes.mqh create mode 100644 Include/Expert/Signal/SignalFrAMA.mqh create mode 100644 Include/Expert/Signal/SignalITF.mqh create mode 100644 Include/Expert/Signal/SignalMA.mqh create mode 100644 Include/Expert/Signal/SignalMACD.mqh create mode 100644 Include/Expert/Signal/SignalRSI.mqh create mode 100644 Include/Expert/Signal/SignalRVI.mqh create mode 100644 Include/Expert/Signal/SignalSAR.mqh create mode 100644 Include/Expert/Signal/SignalStoch.mqh create mode 100644 Include/Expert/Signal/SignalTEMA.mqh create mode 100644 Include/Expert/Signal/SignalTRIX.mqh create mode 100644 Include/Expert/Signal/SignalWPR.mqh create mode 100644 Include/Expert/Trailing/TrailingFixedPips.mqh create mode 100644 Include/Expert/Trailing/TrailingMA.mqh create mode 100644 Include/Expert/Trailing/TrailingNone.mqh create mode 100644 Include/Expert/Trailing/TrailingParabolicSAR.mqh create mode 100644 Include/Files/File.mqh create mode 100644 Include/Files/FileBin.mqh create mode 100644 Include/Files/FilePipe.mqh create mode 100644 Include/Files/FileTxt.mqh create mode 100644 Include/Generic/ArrayList.mqh create mode 100644 Include/Generic/HashMap.mqh create mode 100644 Include/Generic/HashSet.mqh create mode 100644 Include/Generic/Interfaces/ICollection.mqh create mode 100644 Include/Generic/Interfaces/IComparable.mqh create mode 100644 Include/Generic/Interfaces/IComparer.mqh create mode 100644 Include/Generic/Interfaces/IEqualityComparable.mqh create mode 100644 Include/Generic/Interfaces/IEqualityComparer.mqh create mode 100644 Include/Generic/Interfaces/IList.mqh create mode 100644 Include/Generic/Interfaces/IMap.mqh create mode 100644 Include/Generic/Interfaces/ISet.mqh create mode 100644 Include/Generic/Internal/ArrayFunction.mqh create mode 100644 Include/Generic/Internal/CompareFunction.mqh create mode 100644 Include/Generic/Internal/DefaultComparer.mqh create mode 100644 Include/Generic/Internal/DefaultEqualityComparer.mqh create mode 100644 Include/Generic/Internal/EqualFunction.mqh create mode 100644 Include/Generic/Internal/HashFunction.mqh create mode 100644 Include/Generic/Internal/Introsort.mqh create mode 100644 Include/Generic/Internal/PrimeGenerator.mqh create mode 100644 Include/Generic/LinkedList.mqh create mode 100644 Include/Generic/Queue.mqh create mode 100644 Include/Generic/RedBlackTree.mqh create mode 100644 Include/Generic/SortedMap.mqh create mode 100644 Include/Generic/SortedSet.mqh create mode 100644 Include/Generic/Stack.mqh create mode 100644 Include/Graphics/Axis.mqh create mode 100644 Include/Graphics/ColorGenerator.mqh create mode 100644 Include/Graphics/Curve.mqh create mode 100644 Include/Graphics/Graphic.mqh create mode 100644 Include/Indicators/BillWilliams.mqh create mode 100644 Include/Indicators/Custom.mqh create mode 100644 Include/Indicators/Indicator.mqh create mode 100644 Include/Indicators/Indicators.mqh create mode 100644 Include/Indicators/Oscilators.mqh create mode 100644 Include/Indicators/Series.mqh create mode 100644 Include/Indicators/TimeSeries.mqh create mode 100644 Include/Indicators/Trend.mqh create mode 100644 Include/Indicators/Volumes.mqh create mode 100644 Include/Math/Alglib/alglib.mqh create mode 100644 Include/Math/Alglib/alglibinternal.mqh create mode 100644 Include/Math/Alglib/alglibmisc.mqh create mode 100644 Include/Math/Alglib/ap.mqh create mode 100644 Include/Math/Alglib/arrayresize.mqh create mode 100644 Include/Math/Alglib/bitconvert.mqh create mode 100644 Include/Math/Alglib/complex.mqh create mode 100644 Include/Math/Alglib/dataanalysis.mqh create mode 100644 Include/Math/Alglib/delegatefunctions.mqh create mode 100644 Include/Math/Alglib/diffequations.mqh create mode 100644 Include/Math/Alglib/fasttransforms.mqh create mode 100644 Include/Math/Alglib/integration.mqh create mode 100644 Include/Math/Alglib/interpolation.mqh create mode 100644 Include/Math/Alglib/linalg.mqh create mode 100644 Include/Math/Alglib/matrix.mqh create mode 100644 Include/Math/Alglib/optimization.mqh create mode 100644 Include/Math/Alglib/solvers.mqh create mode 100644 Include/Math/Alglib/specialfunctions.mqh create mode 100644 Include/Math/Alglib/statistics.mqh create mode 100644 Include/Math/Fuzzy/dictionary.mqh create mode 100644 Include/Math/Fuzzy/fuzzyrule.mqh create mode 100644 Include/Math/Fuzzy/fuzzyterm.mqh create mode 100644 Include/Math/Fuzzy/fuzzyvariable.mqh create mode 100644 Include/Math/Fuzzy/genericfuzzysystem.mqh create mode 100644 Include/Math/Fuzzy/helper.mqh create mode 100644 Include/Math/Fuzzy/inferencemethod.mqh create mode 100644 Include/Math/Fuzzy/mamdanifuzzysystem.mqh create mode 100644 Include/Math/Fuzzy/membershipfunction.mqh create mode 100644 Include/Math/Fuzzy/ruleparser.mqh create mode 100644 Include/Math/Fuzzy/sugenofuzzysystem.mqh create mode 100644 Include/Math/Fuzzy/sugenovariable.mqh create mode 100644 Include/Math/Stat/Beta.mqh create mode 100644 Include/Math/Stat/Binomial.mqh create mode 100644 Include/Math/Stat/Cauchy.mqh create mode 100644 Include/Math/Stat/ChiSquare.mqh create mode 100644 Include/Math/Stat/Exponential.mqh create mode 100644 Include/Math/Stat/F.mqh create mode 100644 Include/Math/Stat/Gamma.mqh create mode 100644 Include/Math/Stat/Geometric.mqh create mode 100644 Include/Math/Stat/Hypergeometric.mqh create mode 100644 Include/Math/Stat/Logistic.mqh create mode 100644 Include/Math/Stat/Lognormal.mqh create mode 100644 Include/Math/Stat/Math.mqh create mode 100644 Include/Math/Stat/NegativeBinomial.mqh create mode 100644 Include/Math/Stat/NoncentralBeta.mqh create mode 100644 Include/Math/Stat/NoncentralChiSquare.mqh create mode 100644 Include/Math/Stat/NoncentralF.mqh create mode 100644 Include/Math/Stat/NoncentralT.mqh create mode 100644 Include/Math/Stat/Normal.mqh create mode 100644 Include/Math/Stat/Poisson.mqh create mode 100644 Include/Math/Stat/Stat.mqh create mode 100644 Include/Math/Stat/T.mqh create mode 100644 Include/Math/Stat/Uniform.mqh create mode 100644 Include/Math/Stat/Weibull.mqh create mode 100644 Include/MovingAverages.mqh create mode 100644 Include/Object.mqh create mode 100644 Include/OpenCL/OpenCL.mqh create mode 100644 Include/StdLibErr.mqh create mode 100644 Include/Strings/String.mqh create mode 100644 Include/Tools/DateTime.mqh create mode 100644 Include/Trade/AccountInfo.mqh create mode 100644 Include/Trade/DealInfo.mqh create mode 100644 Include/Trade/HistoryOrderInfo.mqh create mode 100644 Include/Trade/OrderInfo.mqh create mode 100644 Include/Trade/PositionInfo.mqh create mode 100644 Include/Trade/SymbolInfo.mqh create mode 100644 Include/Trade/TerminalInfo.mqh create mode 100644 Include/Trade/Trade.mqh create mode 100644 Include/VirtualKeys.mqh create mode 100644 Indicators/Examples/AD.mq5 create mode 100644 Indicators/Examples/ADX.mq5 create mode 100644 Indicators/Examples/ADXW.mq5 create mode 100644 Indicators/Examples/AMA.mq5 create mode 100644 Indicators/Examples/ASI.mq5 create mode 100644 Indicators/Examples/ATR.mq5 create mode 100644 Indicators/Examples/Accelerator.mq5 create mode 100644 Indicators/Examples/Alligator.mq5 create mode 100644 Indicators/Examples/Awesome_Oscillator.mq5 create mode 100644 Indicators/Examples/BB.mq5 create mode 100644 Indicators/Examples/BW-ZoneTrade.mq5 create mode 100644 Indicators/Examples/Bears.mq5 create mode 100644 Indicators/Examples/Bulls.mq5 create mode 100644 Indicators/Examples/CCI.mq5 create mode 100644 Indicators/Examples/CHO.mq5 create mode 100644 Indicators/Examples/CHV.mq5 create mode 100644 Indicators/Examples/Canvas/FlameChart.mq5 create mode 100644 Indicators/Examples/ColorBars.mq5 create mode 100644 Indicators/Examples/ColorCandlesDaily.mq5 create mode 100644 Indicators/Examples/ColorLine.mq5 create mode 100644 Indicators/Examples/Custom Moving Average.mq5 create mode 100644 Indicators/Examples/DEMA.mq5 create mode 100644 Indicators/Examples/DPO.mq5 create mode 100644 Indicators/Examples/DeMarker.mq5 create mode 100644 Indicators/Examples/Envelopes.mq5 create mode 100644 Indicators/Examples/Force_Index.mq5 create mode 100644 Indicators/Examples/FrAMA.mq5 create mode 100644 Indicators/Examples/Fractals.mq5 create mode 100644 Indicators/Examples/Gator.mq5 create mode 100644 Indicators/Examples/Gator_2.mq5 create mode 100644 Indicators/Examples/Heiken_Ashi.mq5 create mode 100644 Indicators/Examples/Ichimoku.mq5 create mode 100644 Indicators/Examples/MACD.mq5 create mode 100644 Indicators/Examples/MFI.mq5 create mode 100644 Indicators/Examples/MI.mq5 create mode 100644 Indicators/Examples/MarketFacilitationIndex.mq5 create mode 100644 Indicators/Examples/Momentum.mq5 create mode 100644 Indicators/Examples/OBV.mq5 create mode 100644 Indicators/Examples/OsMA.mq5 create mode 100644 Indicators/Examples/PVT.mq5 create mode 100644 Indicators/Examples/Panels/ChartPanel/ChartPanel.mq5 create mode 100644 Indicators/Examples/Panels/ChartPanel/PanelDialog.mqh create mode 100644 Indicators/Examples/Panels/SimplePanel/PanelDialog.mqh create mode 100644 Indicators/Examples/Panels/SimplePanel/SimplePanel.mq5 create mode 100644 Indicators/Examples/ParabolicSAR.mq5 create mode 100644 Indicators/Examples/Price_Channel.mq5 create mode 100644 Indicators/Examples/ROC.mq5 create mode 100644 Indicators/Examples/RSI.mq5 create mode 100644 Indicators/Examples/RVI.mq5 create mode 100644 Indicators/Examples/StdDev.mq5 create mode 100644 Indicators/Examples/Stochastic.mq5 create mode 100644 Indicators/Examples/TEMA.mq5 create mode 100644 Indicators/Examples/TRIX.mq5 create mode 100644 Indicators/Examples/Ultimate_Oscillator.mq5 create mode 100644 Indicators/Examples/VIDYA.mq5 create mode 100644 Indicators/Examples/VROC.mq5 create mode 100644 Indicators/Examples/Volumes.mq5 create mode 100644 Indicators/Examples/WPR.mq5 create mode 100644 Indicators/Examples/W_AD.mq5 create mode 100644 Indicators/Examples/ZigZag.mq5 create mode 100644 Indicators/Examples/ZigzagColor.mq5 create mode 100644 Profiles/Charts/British Pound/chart01.chr create mode 100644 Profiles/Charts/British Pound/chart02.chr create mode 100644 Profiles/Charts/British Pound/chart03.chr create mode 100644 Profiles/Charts/British Pound/chart04.chr create mode 100644 Profiles/Charts/British Pound/order.wnd create mode 100644 Profiles/Charts/Default/chart01.chr create mode 100644 Profiles/Charts/Default/chart02.chr create mode 100644 Profiles/Charts/Default/chart03.chr create mode 100644 Profiles/Charts/Default/chart04.chr create mode 100644 Profiles/Charts/Default/order.wnd create mode 100644 Profiles/Charts/Euro/chart01.chr create mode 100644 Profiles/Charts/Euro/chart02.chr create mode 100644 Profiles/Charts/Euro/chart03.chr create mode 100644 Profiles/Charts/Euro/chart04.chr create mode 100644 Profiles/Charts/Euro/order.wnd create mode 100644 Profiles/Charts/Market Overview/chart01.chr create mode 100644 Profiles/Charts/Market Overview/chart02.chr create mode 100644 Profiles/Charts/Market Overview/chart03.chr create mode 100644 Profiles/Charts/Market Overview/chart04.chr create mode 100644 Profiles/Charts/Market Overview/order.wnd create mode 100644 Profiles/SymbolSets/forex.all.set create mode 100644 Profiles/SymbolSets/forex.crosses.set create mode 100644 Profiles/SymbolSets/forex.major.set create mode 100644 Profiles/Templates/ADX.tpl create mode 100644 Profiles/Templates/BollingerBands.tpl create mode 100644 Profiles/Templates/Momentum.tpl create mode 100644 Profiles/Templates/ReportHistory.htm create mode 100644 Profiles/Templates/ReportTester.htm create mode 100644 Profiles/Templates/ReportTrade.htm create mode 100644 Scripts/Examples/AccountInfo/AccountInfoSample.mq5 create mode 100644 Scripts/Examples/AccountInfo/AccountInfoSampleInit.mqh create mode 100644 Scripts/Examples/ArrayDouble/ArrayDoubleSample.mq5 create mode 100644 Scripts/Examples/Canvas/CanvasSample.mq5 create mode 100644 Scripts/Examples/Canvas/Charts/HistogramChartSample.mq5 create mode 100644 Scripts/Examples/Canvas/Charts/LineChartSample.mq5 create mode 100644 Scripts/Examples/Canvas/Charts/PieChartSample.mq5 create mode 100644 Scripts/Examples/ObjectChart/ChartSampleInit.mqh create mode 100644 Scripts/Examples/ObjectChart/ObjChartSample.mq5 create mode 100644 Scripts/Examples/ObjectSphere/Sphere.mqh create mode 100644 Scripts/Examples/ObjectSphere/SphereSample.mq5 create mode 100644 Scripts/Examples/OpenCL/Double/BitonicSort.mq5 create mode 100644 Scripts/Examples/OpenCL/Double/FFT.mq5 create mode 100644 Scripts/Examples/OpenCL/Double/Kernels/bitonicsort.cl create mode 100644 Scripts/Examples/OpenCL/Double/Kernels/fft.cl create mode 100644 Scripts/Examples/OpenCL/Double/Kernels/matrixmult.cl create mode 100644 Scripts/Examples/OpenCL/Double/Kernels/wavelet.cl create mode 100644 Scripts/Examples/OpenCL/Double/MatrixMult.mq5 create mode 100644 Scripts/Examples/OpenCL/Double/Wavelet.mq5 create mode 100644 Scripts/Examples/OpenCL/Float/BitonicSort.mq5 create mode 100644 Scripts/Examples/OpenCL/Float/FFT.mq5 create mode 100644 Scripts/Examples/OpenCL/Float/Kernels/bitonicsort.cl create mode 100644 Scripts/Examples/OpenCL/Float/Kernels/fft.cl create mode 100644 Scripts/Examples/OpenCL/Float/Kernels/matrixmult.cl create mode 100644 Scripts/Examples/OpenCL/Float/Kernels/wavelet.cl create mode 100644 Scripts/Examples/OpenCL/Float/MatrixMult.mq5 create mode 100644 Scripts/Examples/OpenCL/Float/Wavelet.mq5 create mode 100644 Scripts/Examples/OrderInfo/OrderInfoSample.mq5 create mode 100644 Scripts/Examples/OrderInfo/OrderInfoSampleInit.mqh create mode 100644 Scripts/Examples/PositionInfo/PositionInfoSample.mq5 create mode 100644 Scripts/Examples/PositionInfo/PositionInfoSampleInit.mqh create mode 100644 Scripts/Examples/SymbolInfo/SymbolInfoSample.mq5 create mode 100644 Scripts/Examples/SymbolInfo/SymbolInfoSampleInit.mqh create mode 100644 Scripts/UnitTests/Alglib/TestClasses.mq5 create mode 100644 Scripts/UnitTests/Alglib/TestClasses.mqh create mode 100644 Scripts/UnitTests/Alglib/TestInterfaces.mq5 create mode 100644 Scripts/UnitTests/Alglib/TestInterfaces.mqh create mode 100644 Scripts/UnitTests/Fuzzy/TestFuzzy.mq5 create mode 100644 Scripts/UnitTests/Generic/TestArrayList.mq5 create mode 100644 Scripts/UnitTests/Generic/TestHashMap.mq5 create mode 100644 Scripts/UnitTests/Generic/TestHashSet.mq5 create mode 100644 Scripts/UnitTests/Generic/TestLinkedList.mq5 create mode 100644 Scripts/UnitTests/Generic/TestQueue.mq5 create mode 100644 Scripts/UnitTests/Generic/TestRedBlackTree.mq5 create mode 100644 Scripts/UnitTests/Generic/TestSortedMap.mq5 create mode 100644 Scripts/UnitTests/Generic/TestSortedSet.mq5 create mode 100644 Scripts/UnitTests/Generic/TestStack.mq5 create mode 100644 Scripts/UnitTests/Stat/TestStat.mq5 create mode 100644 Scripts/UnitTests/Stat/TestStatBenchmark.mq5 create mode 100644 Scripts/UnitTests/Stat/TestStatPrecision.mq5 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d61dd24 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.dat +*.ex5 +*.log diff --git a/Experts/Advisors/ExpertMACD.mq5 b/Experts/Advisors/ExpertMACD.mq5 new file mode 100644 index 0000000..1968c87 --- /dev/null +++ b/Experts/Advisors/ExpertMACD.mq5 @@ -0,0 +1,168 @@ +//+------------------------------------------------------------------+ +//| ExpertMACD.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +#property version "1.00" +//+------------------------------------------------------------------+ +//| Include | +//+------------------------------------------------------------------+ +#include +#include +#include +#include +//+------------------------------------------------------------------+ +//| Inputs | +//+------------------------------------------------------------------+ +//--- inputs for expert +input string Inp_Expert_Title ="ExpertMACD"; +int Expert_MagicNumber =10981; +bool Expert_EveryTick =false; +//--- inputs for signal +input int Inp_Signal_MACD_PeriodFast =12; +input int Inp_Signal_MACD_PeriodSlow =24; +input int Inp_Signal_MACD_PeriodSignal=9; +input int Inp_Signal_MACD_TakeProfit =50; +input int Inp_Signal_MACD_StopLoss =20; +//+------------------------------------------------------------------+ +//| Global expert object | +//+------------------------------------------------------------------+ +CExpert ExtExpert; +//+------------------------------------------------------------------+ +//| Initialization function of the expert | +//+------------------------------------------------------------------+ +int OnInit(void) + { +//--- Initializing expert + if(!ExtExpert.Init(Symbol(),Period(),Expert_EveryTick,Expert_MagicNumber)) + { + //--- failed + printf(__FUNCTION__+": error initializing expert"); + ExtExpert.Deinit(); + return(-1); + } +//--- Creation of signal object + CSignalMACD *signal=new CSignalMACD; + if(signal==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating signal"); + ExtExpert.Deinit(); + return(-2); + } +//--- Add signal to expert (will be deleted automatically)) + if(!ExtExpert.InitSignal(signal)) + { + //--- failed + printf(__FUNCTION__+": error initializing signal"); + ExtExpert.Deinit(); + return(-3); + } +//--- Set signal parameters + signal.PeriodFast(Inp_Signal_MACD_PeriodFast); + signal.PeriodSlow(Inp_Signal_MACD_PeriodSlow); + signal.PeriodSignal(Inp_Signal_MACD_PeriodSignal); + signal.TakeLevel(Inp_Signal_MACD_TakeProfit); + signal.StopLevel(Inp_Signal_MACD_StopLoss); +//--- Check signal parameters + if(!signal.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error signal parameters"); + ExtExpert.Deinit(); + return(-4); + } +//--- Creation of trailing object + CTrailingNone *trailing=new CTrailingNone; + if(trailing==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating trailing"); + ExtExpert.Deinit(); + return(-5); + } +//--- Add trailing to expert (will be deleted automatically)) + if(!ExtExpert.InitTrailing(trailing)) + { + //--- failed + printf(__FUNCTION__+": error initializing trailing"); + ExtExpert.Deinit(); + return(-6); + } +//--- Set trailing parameters +//--- Check trailing parameters + if(!trailing.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error trailing parameters"); + ExtExpert.Deinit(); + return(-7); + } +//--- Creation of money object + CMoneyNone *money=new CMoneyNone; + if(money==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating money"); + ExtExpert.Deinit(); + return(-8); + } +//--- Add money to expert (will be deleted automatically)) + if(!ExtExpert.InitMoney(money)) + { + //--- failed + printf(__FUNCTION__+": error initializing money"); + ExtExpert.Deinit(); + return(-9); + } +//--- Set money parameters +//--- Check money parameters + if(!money.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error money parameters"); + ExtExpert.Deinit(); + return(-10); + } +//--- Tuning of all necessary indicators + if(!ExtExpert.InitIndicators()) + { + //--- failed + printf(__FUNCTION__+": error initializing indicators"); + ExtExpert.Deinit(); + return(-11); + } +//--- succeed + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Deinitialization function of the expert | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { + ExtExpert.Deinit(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "tick" | +//+------------------------------------------------------------------+ +void OnTick(void) + { + ExtExpert.OnTick(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "trade" | +//+------------------------------------------------------------------+ +void OnTrade(void) + { + ExtExpert.OnTrade(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "timer" | +//+------------------------------------------------------------------+ +void OnTimer(void) + { + ExtExpert.OnTimer(); + } +//+------------------------------------------------------------------+ diff --git a/Experts/Advisors/ExpertMAMA.mq5 b/Experts/Advisors/ExpertMAMA.mq5 new file mode 100644 index 0000000..f255476 --- /dev/null +++ b/Experts/Advisors/ExpertMAMA.mq5 @@ -0,0 +1,175 @@ +//+------------------------------------------------------------------+ +//| ExpertMAMA.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +#property version "1.00" +//+------------------------------------------------------------------+ +//| Include | +//+------------------------------------------------------------------+ +#include +#include +#include +#include +//+------------------------------------------------------------------+ +//| Inputs | +//+------------------------------------------------------------------+ +//--- inputs for expert +input string Inp_Expert_Title ="ExpertMAMA"; +int Expert_MagicNumber =12003; +bool Expert_EveryTick =false; +//--- inputs for signal +input int Inp_Signal_MA_Period =12; +input int Inp_Signal_MA_Shift =6; +input ENUM_MA_METHOD Inp_Signal_MA_Method =MODE_SMA; +input ENUM_APPLIED_PRICE Inp_Signal_MA_Applied =PRICE_CLOSE; +//--- inputs for trailing +input int Inp_Trailing_MA_Period =12; +input int Inp_Trailing_MA_Shift =0; +input ENUM_MA_METHOD Inp_Trailing_MA_Method =MODE_SMA; +input ENUM_APPLIED_PRICE Inp_Trailing_MA_Applied=PRICE_CLOSE; +//+------------------------------------------------------------------+ +//| Global expert object | +//+------------------------------------------------------------------+ +CExpert ExtExpert; +//+------------------------------------------------------------------+ +//| Initialization function of the expert | +//+------------------------------------------------------------------+ +int OnInit(void) + { +//--- Initializing expert + if(!ExtExpert.Init(Symbol(),Period(),Expert_EveryTick,Expert_MagicNumber)) + { + //--- failed + printf(__FUNCTION__+": error initializing expert"); + ExtExpert.Deinit(); + return(-1); + } +//--- Creation of signal object + CSignalMA *signal=new CSignalMA; + if(signal==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating signal"); + ExtExpert.Deinit(); + return(-2); + } +//--- Add signal to expert (will be deleted automatically)) + if(!ExtExpert.InitSignal(signal)) + { + //--- failed + printf(__FUNCTION__+": error initializing signal"); + ExtExpert.Deinit(); + return(-3); + } +//--- Set signal parameters + signal.PeriodMA(Inp_Signal_MA_Period); + signal.Shift(Inp_Signal_MA_Shift); + signal.Method(Inp_Signal_MA_Method); + signal.Applied(Inp_Signal_MA_Applied); +//--- Check signal parameters + if(!signal.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error signal parameters"); + ExtExpert.Deinit(); + return(-4); + } +//--- Creation of trailing object + CTrailingMA *trailing=new CTrailingMA; + if(trailing==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating trailing"); + ExtExpert.Deinit(); + return(-5); + } +//--- Add trailing to expert (will be deleted automatically)) + if(!ExtExpert.InitTrailing(trailing)) + { + //--- failed + printf(__FUNCTION__+": error initializing trailing"); + ExtExpert.Deinit(); + return(-6); + } +//--- Set trailing parameters + trailing.Period(Inp_Trailing_MA_Period); + trailing.Shift(Inp_Trailing_MA_Shift); + trailing.Method(Inp_Trailing_MA_Method); + trailing.Applied(Inp_Trailing_MA_Applied); +//--- Check trailing parameters + if(!trailing.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error trailing parameters"); + ExtExpert.Deinit(); + return(-7); + } +//--- Creation of money object + CMoneyNone *money=new CMoneyNone; + if(money==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating money"); + ExtExpert.Deinit(); + return(-8); + } +//--- Add money to expert (will be deleted automatically)) + if(!ExtExpert.InitMoney(money)) + { + //--- failed + printf(__FUNCTION__+": error initializing money"); + ExtExpert.Deinit(); + return(-9); + } +//--- Set money parameters +//--- Check money parameters + if(!money.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error money parameters"); + ExtExpert.Deinit(); + return(-10); + } +//--- Tuning of all necessary indicators + if(!ExtExpert.InitIndicators()) + { + //--- failed + printf(__FUNCTION__+": error initializing indicators"); + ExtExpert.Deinit(); + return(-11); + } +//--- succeed + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Deinitialization function of the expert | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { + ExtExpert.Deinit(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "tick" | +//+------------------------------------------------------------------+ +void OnTick(void) + { + ExtExpert.OnTick(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "trade" | +//+------------------------------------------------------------------+ +void OnTrade(void) + { + ExtExpert.OnTrade(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "timer" | +//+------------------------------------------------------------------+ +void OnTimer(void) + { + ExtExpert.OnTimer(); + } +//+------------------------------------------------------------------+ diff --git a/Experts/Advisors/ExpertMAPSAR.mq5 b/Experts/Advisors/ExpertMAPSAR.mq5 new file mode 100644 index 0000000..4fb0815 --- /dev/null +++ b/Experts/Advisors/ExpertMAPSAR.mq5 @@ -0,0 +1,171 @@ +//+------------------------------------------------------------------+ +//| ExpertMAPSAR.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +#property version "1.00" +//+------------------------------------------------------------------+ +//| Include | +//+------------------------------------------------------------------+ +#include +#include +#include +#include +//+------------------------------------------------------------------+ +//| Inputs | +//+------------------------------------------------------------------+ +//--- inputs for expert +input string Inp_Expert_Title ="ExpertMAPSAR"; +int Expert_MagicNumber =14598; +bool Expert_EveryTick =false; +//--- inputs for signal +input int Inp_Signal_MA_Period =12; +input int Inp_Signal_MA_Shift =6; +input ENUM_MA_METHOD Inp_Signal_MA_Method =MODE_SMA; +input ENUM_APPLIED_PRICE Inp_Signal_MA_Applied =PRICE_CLOSE; +//--- inputs for trailing +input double Inp_Trailing_ParabolicSAR_Step =0.02; +input double Inp_Trailing_ParabolicSAR_Maximum=0.2; +//+------------------------------------------------------------------+ +//| Global expert object | +//+------------------------------------------------------------------+ +CExpert ExtExpert; +//+------------------------------------------------------------------+ +//| Initialization function of the expert | +//+------------------------------------------------------------------+ +int OnInit(void) + { +//--- Initializing expert + if(!ExtExpert.Init(Symbol(),Period(),Expert_EveryTick,Expert_MagicNumber)) + { + //--- failed + printf(__FUNCTION__+": error initializing expert"); + ExtExpert.Deinit(); + return(-1); + } +//--- Creation of signal object + CSignalMA *signal=new CSignalMA; + if(signal==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating signal"); + ExtExpert.Deinit(); + return(-2); + } +//--- Add signal to expert (will be deleted automatically)) + if(!ExtExpert.InitSignal(signal)) + { + //--- failed + printf(__FUNCTION__+": error initializing signal"); + ExtExpert.Deinit(); + return(-3); + } +//--- Set signal parameters + signal.PeriodMA(Inp_Signal_MA_Period); + signal.Shift(Inp_Signal_MA_Shift); + signal.Method(Inp_Signal_MA_Method); + signal.Applied(Inp_Signal_MA_Applied); +//--- Check signal parameters + if(!signal.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error signal parameters"); + ExtExpert.Deinit(); + return(-4); + } +//--- Creation of trailing object + CTrailingPSAR *trailing=new CTrailingPSAR; + if(trailing==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating trailing"); + ExtExpert.Deinit(); + return(-5); + } +//--- Add trailing to expert (will be deleted automatically)) + if(!ExtExpert.InitTrailing(trailing)) + { + //--- failed + printf(__FUNCTION__+": error initializing trailing"); + ExtExpert.Deinit(); + return(-6); + } +//--- Set trailing parameters + trailing.Step(Inp_Trailing_ParabolicSAR_Step); + trailing.Maximum(Inp_Trailing_ParabolicSAR_Maximum); +//--- Check trailing parameters + if(!trailing.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error trailing parameters"); + ExtExpert.Deinit(); + return(-7); + } +//--- Creation of money object + CMoneyNone *money=new CMoneyNone; + if(money==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating money"); + ExtExpert.Deinit(); + return(-8); + } +//--- Add money to expert (will be deleted automatically)) + if(!ExtExpert.InitMoney(money)) + { + //--- failed + printf(__FUNCTION__+": error initializing money"); + ExtExpert.Deinit(); + return(-9); + } +//--- Set money parameters +//--- Check money parameters + if(!money.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error money parameters"); + ExtExpert.Deinit(); + return(-10); + } +//--- Tuning of all necessary indicators + if(!ExtExpert.InitIndicators()) + { + //--- failed + printf(__FUNCTION__+": error initializing indicators"); + ExtExpert.Deinit(); + return(-11); + } +//--- succeed + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Deinitialization function of the expert | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { + ExtExpert.Deinit(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "tick" | +//+------------------------------------------------------------------+ +void OnTick(void) + { + ExtExpert.OnTick(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "trade" | +//+------------------------------------------------------------------+ +void OnTrade(void) + { + ExtExpert.OnTrade(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "timer" | +//+------------------------------------------------------------------+ +void OnTimer(void) + { + ExtExpert.OnTimer(); + } +//+------------------------------------------------------------------+ diff --git a/Experts/Advisors/ExpertMAPSARSizeOptimized.mq5 b/Experts/Advisors/ExpertMAPSARSizeOptimized.mq5 new file mode 100644 index 0000000..b233fd2 --- /dev/null +++ b/Experts/Advisors/ExpertMAPSARSizeOptimized.mq5 @@ -0,0 +1,176 @@ +//+------------------------------------------------------------------+ +//| ExpertMAPSARSizeOptimized.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +#property version "1.00" +//+------------------------------------------------------------------+ +//| Include | +//+------------------------------------------------------------------+ +#include +#include +#include +#include +//+------------------------------------------------------------------+ +//| Inputs | +//+------------------------------------------------------------------+ +//--- inputs for expert +input string Inp_Expert_Title ="ExpertMAPSARSizeOptimized"; +int Expert_MagicNumber =27893; +bool Expert_EveryTick =false; +//--- inputs for signal +input int Inp_Signal_MA_Period =12; +input int Inp_Signal_MA_Shift =6; +input ENUM_MA_METHOD Inp_Signal_MA_Method =MODE_SMA; +input ENUM_APPLIED_PRICE Inp_Signal_MA_Applied =PRICE_CLOSE; +//--- inputs for trailing +input double Inp_Trailing_ParabolicSAR_Step =0.02; +input double Inp_Trailing_ParabolicSAR_Maximum =0.2; +//--- inputs for money +input double Inp_Money_SizeOptimized_DecreaseFactor=3.0; +input double Inp_Money_SizeOptimized_Percent =10.0; +//+------------------------------------------------------------------+ +//| Global expert object | +//+------------------------------------------------------------------+ +CExpert ExtExpert; +//+------------------------------------------------------------------+ +//| Initialization function of the expert | +//+------------------------------------------------------------------+ +int OnInit(void) + { +//--- Initializing expert + if(!ExtExpert.Init(Symbol(),Period(),Expert_EveryTick,Expert_MagicNumber)) + { + //--- failed + printf(__FUNCTION__+": error initializing expert"); + ExtExpert.Deinit(); + return(-1); + } +//--- Creation of signal object + CSignalMA *signal=new CSignalMA; + if(signal==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating signal"); + ExtExpert.Deinit(); + return(-2); + } +//--- Add signal to expert (will be deleted automatically)) + if(!ExtExpert.InitSignal(signal)) + { + //--- failed + printf(__FUNCTION__+": error initializing signal"); + ExtExpert.Deinit(); + return(-3); + } +//--- Set signal parameters + signal.PeriodMA(Inp_Signal_MA_Period); + signal.Shift(Inp_Signal_MA_Shift); + signal.Method(Inp_Signal_MA_Method); + signal.Applied(Inp_Signal_MA_Applied); +//--- Check signal parameters + if(!signal.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error signal parameters"); + ExtExpert.Deinit(); + return(-4); + } +//--- Creation of trailing object + CTrailingPSAR *trailing=new CTrailingPSAR; + if(trailing==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating trailing"); + ExtExpert.Deinit(); + return(-5); + } +//--- Add trailing to expert (will be deleted automatically)) + if(!ExtExpert.InitTrailing(trailing)) + { + //--- failed + printf(__FUNCTION__+": error initializing trailing"); + ExtExpert.Deinit(); + return(-6); + } +//--- Set trailing parameters + trailing.Step(Inp_Trailing_ParabolicSAR_Step); + trailing.Maximum(Inp_Trailing_ParabolicSAR_Maximum); +//--- Check trailing parameters + if(!trailing.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error trailing parameters"); + ExtExpert.Deinit(); + return(-7); + } +//--- Creation of money object + CMoneySizeOptimized *money=new CMoneySizeOptimized; + if(money==NULL) + { + //--- failed + printf(__FUNCTION__+": error creating money"); + ExtExpert.Deinit(); + return(-8); + } +//--- Add money to expert (will be deleted automatically)) + if(!ExtExpert.InitMoney(money)) + { + //--- failed + printf(__FUNCTION__+": error initializing money"); + ExtExpert.Deinit(); + return(-9); + } +//--- Set money parameters + money.DecreaseFactor(Inp_Money_SizeOptimized_DecreaseFactor); + money.Percent(Inp_Money_SizeOptimized_Percent); +//--- Check money parameters + if(!money.ValidationSettings()) + { + //--- failed + printf(__FUNCTION__+": error money parameters"); + ExtExpert.Deinit(); + return(-10); + } +//--- Tuning of all necessary indicators + if(!ExtExpert.InitIndicators()) + { + //--- failed + printf(__FUNCTION__+": error initializing indicators"); + ExtExpert.Deinit(); + return(-11); + } +//--- succeed + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Deinitialization function of the expert | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { + ExtExpert.Deinit(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "tick" | +//+------------------------------------------------------------------+ +void OnTick(void) + { + ExtExpert.OnTick(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "trade" | +//+------------------------------------------------------------------+ +void OnTrade(void) + { + ExtExpert.OnTrade(); + } +//+------------------------------------------------------------------+ +//| Function-event handler "timer" | +//+------------------------------------------------------------------+ +void OnTimer(void) + { + ExtExpert.OnTimer(); + } +//+------------------------------------------------------------------+ diff --git a/Experts/Examples/ChartInChart/ChartInChart.mq5 b/Experts/Examples/ChartInChart/ChartInChart.mq5 new file mode 100644 index 0000000..384ee0b --- /dev/null +++ b/Experts/Examples/ChartInChart/ChartInChart.mq5 @@ -0,0 +1,353 @@ +//+------------------------------------------------------------------+ +//| ChartInChart.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +//--- inputs +input color TextColor=White; +input color BGColor=SteelBlue; +input int XPosition=10; +input int YPosition=10; +input int XSize=450; +input int YSize=300; +//--- variables +int xsize=450; +int ysize=300; +int xdist=10; +int ydist=10; +int scale=1; +int show=1; +int showdates =0; +int showprices=0; +//--- +string curr_symbol; +string curr_period_str; +ENUM_TIMEFRAMES curr_period; +ENUM_TIMEFRAMES enper; +//+------------------------------------------------------------------+ +//| Initialize expert | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- default value for symbol and period + curr_symbol=Symbol(); + curr_period=Period(); + PeriodToStr(curr_period,curr_period_str); +//--- copy sizes + xsize=XSize; + ysize=YSize; + xdist=XPosition; + ydist=YPosition; +//--- create objects + PIPCreate(); + PIPSetParams(); +//--- + ChartRedraw(); + } +//+------------------------------------------------------------------+ +//| Process chart events | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id,const long& lparam,const double& dparam,const string& sparam) + { + if(id==CHARTEVENT_OBJECT_ENDEDIT && sparam=="PIPSymbol") + { + curr_symbol=ObjectGetString(0,"PIPSymbol",OBJPROP_TEXT); + ObjectSetString(0,"PIPChart",OBJPROP_SYMBOL,curr_symbol); + ChartRedraw(); + //--- check symbol + curr_symbol=ObjectGetString(0,"PIPChart",OBJPROP_SYMBOL); + ObjectSetString(0,"PIPSymbol",OBJPROP_TEXT,curr_symbol); + } + else + if(id==CHARTEVENT_OBJECT_ENDEDIT && sparam=="PIPPeriod") + { + string per=ObjectGetString(0,"PIPPeriod",OBJPROP_TEXT); + if(StrToPeriod(per,enper)) + { + if(enper) curr_period=enper; + PeriodToStr(curr_period,curr_period_str); + ObjectSetInteger(0,"PIPChart",OBJPROP_PERIOD,curr_period); + ChartRedraw(); + } + } + else + if(id==CHARTEVENT_OBJECT_CLICK && sparam=="PIPPricesButton") + { + showprices=(int)ObjectGetInteger(0,"PIPPricesButton",OBJPROP_STATE); + ObjectSetInteger(0,"PIPChart",OBJPROP_PRICE_SCALE,showprices); + ChartRedraw(); + } + else + if(id==CHARTEVENT_OBJECT_CLICK && sparam=="PIPDatesButton") + { + showdates=(int)ObjectGetInteger(0,"PIPDatesButton",OBJPROP_STATE); + ObjectSetInteger(0,"PIPChart",OBJPROP_DATE_SCALE,showdates); + ChartRedraw(); + } + else + if(id==CHARTEVENT_OBJECT_CLICK && sparam=="PIPPlusButton") + { + ObjectSetInteger(0,"PIPPlusButton",OBJPROP_STATE,0); + if(scale<5) + { + scale++; + ObjectSetInteger(0,"PIPChart",OBJPROP_CHART_SCALE,scale); + } + ChartRedraw(); + } + else + if(id==CHARTEVENT_OBJECT_CLICK && sparam=="PIPMinusButton") + { + ObjectSetInteger(0,"PIPMinusButton",OBJPROP_STATE,0); + if(scale>0) + { + scale--; + ObjectSetInteger(0,"PIPChart",OBJPROP_CHART_SCALE,scale); + } + ChartRedraw(); + } + else + if(id==CHARTEVENT_OBJECT_CLICK && sparam=="PIPHideButton") + { + ObjectSetInteger(0,"PIPHideButton",OBJPROP_STATE,0); + if(show) + { + //--- hide chart + ObjectSetString(0,"PIPHideButton",OBJPROP_TEXT,"\n"); + PIPHideChart(); + } + else + { + //--- restore chart + PIPSetParams(); + } + //--- change state + show=1-show; + ChartRedraw(); + } + } +//+------------------------------------------------------------------+ +//| Deinitialize expert | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- delete all our objects + PIPDelete(); +//--- + ChartRedraw(); + } +//+------------------------------------------------------------------+ +//| Create objects | +//+------------------------------------------------------------------+ +void PIPCreate() + { + ObjectCreate(0,"PIPSymbol",OBJ_EDIT,0,0,0,0,0); + ObjectCreate(0,"PIPPeriod",OBJ_EDIT,0,0,0,0,0); + ObjectCreate(0,"PIPPlusButton",OBJ_BUTTON,0,0,0,0,0); + ObjectCreate(0,"PIPMinusButton",OBJ_BUTTON,0,0,0,0,0); + ObjectCreate(0,"PIPHideButton",OBJ_BUTTON,0,0,0,0,0); + ObjectCreate(0,"PIPDatesButton",OBJ_BUTTON,0,0,0,0,0); + ObjectCreate(0,"PIPPricesButton",OBJ_BUTTON,0,0,0,0,0); + ObjectCreate(0,"PIPChart",OBJ_CHART,0,0,0,0,0); + } +//+------------------------------------------------------------------+ +//| Delete objects | +//+------------------------------------------------------------------+ +void PIPDelete() + { + ObjectDelete(0,"PIPSymbol"); + ObjectDelete(0,"PIPPeriod"); + ObjectDelete(0,"PIPPlusButton"); + ObjectDelete(0,"PIPMinusButton"); + ObjectDelete(0,"PIPHideButton"); + ObjectDelete(0,"PIPDatesButton"); + ObjectDelete(0,"PIPPricesButton"); + ObjectDelete(0,"PIPChart"); + } +//+------------------------------------------------------------------+ +//| Set objects params | +//+------------------------------------------------------------------+ +void PIPSetParams() + { +//--- check size + if(xsize<250) xsize=250; + if(ysize<100) ysize=100; +//--- Symbol + ObjectSetInteger(0,"PIPSymbol",OBJPROP_COLOR,TextColor); + ObjectSetInteger(0,"PIPSymbol",OBJPROP_BGCOLOR,BGColor); + ObjectSetInteger(0,"PIPSymbol",OBJPROP_XDISTANCE,xdist); + ObjectSetInteger(0,"PIPSymbol",OBJPROP_YDISTANCE,ydist); + ObjectSetInteger(0,"PIPSymbol",OBJPROP_XSIZE,xsize-198); + ObjectSetInteger(0,"PIPSymbol",OBJPROP_YSIZE,18); + ObjectSetString(0,"PIPSymbol",OBJPROP_FONT,"Arial"); + ObjectSetString(0,"PIPSymbol",OBJPROP_TEXT,curr_symbol); + ObjectSetInteger(0,"PIPSymbol",OBJPROP_FONTSIZE,10); + ObjectSetInteger(0,"PIPSymbol",OBJPROP_SELECTABLE,0); +//--- Period + ObjectSetInteger(0,"PIPPeriod",OBJPROP_COLOR,TextColor); + ObjectSetInteger(0,"PIPPeriod",OBJPROP_BGCOLOR,BGColor); + ObjectSetInteger(0,"PIPPeriod",OBJPROP_XDISTANCE,xdist+xsize-197); + ObjectSetInteger(0,"PIPPeriod",OBJPROP_YDISTANCE,ydist); + ObjectSetInteger(0,"PIPPeriod",OBJPROP_XSIZE,40); + ObjectSetInteger(0,"PIPPeriod",OBJPROP_YSIZE,18); + ObjectSetString(0,"PIPPeriod",OBJPROP_FONT,"Arial"); + ObjectSetString(0,"PIPPeriod",OBJPROP_TEXT,curr_period_str); + ObjectSetInteger(0,"PIPPeriod",OBJPROP_FONTSIZE,10); + ObjectSetInteger(0,"PIPPeriod",OBJPROP_SELECTABLE,0); +//--- Dates + ObjectSetInteger(0,"PIPDatesButton",OBJPROP_COLOR,TextColor); + ObjectSetInteger(0,"PIPDatesButton",OBJPROP_BGCOLOR,BGColor); + ObjectSetInteger(0,"PIPDatesButton",OBJPROP_XDISTANCE,xdist+xsize-156); + ObjectSetInteger(0,"PIPDatesButton",OBJPROP_YDISTANCE,ydist); + ObjectSetInteger(0,"PIPDatesButton",OBJPROP_XSIZE,49); + ObjectSetInteger(0,"PIPDatesButton",OBJPROP_YSIZE,18); + ObjectSetString(0,"PIPDatesButton",OBJPROP_TEXT,"Dates"); + ObjectSetString(0,"PIPDatesButton",OBJPROP_FONT,"Arial"); + ObjectSetInteger(0,"PIPDatesButton",OBJPROP_FONTSIZE,10); + ObjectSetInteger(0,"PIPDatesButton",OBJPROP_STATE,showdates); + ObjectSetInteger(0,"PIPDatesButton",OBJPROP_SELECTABLE,0); +//--- Prices + ObjectSetInteger(0,"PIPPricesButton",OBJPROP_COLOR,TextColor); + ObjectSetInteger(0,"PIPPricesButton",OBJPROP_BGCOLOR,BGColor); + ObjectSetInteger(0,"PIPPricesButton",OBJPROP_XDISTANCE,xdist+xsize-106); + ObjectSetInteger(0,"PIPPricesButton",OBJPROP_YDISTANCE,ydist); + ObjectSetInteger(0,"PIPPricesButton",OBJPROP_XSIZE,49); + ObjectSetInteger(0,"PIPPricesButton",OBJPROP_YSIZE,18); + ObjectSetString(0,"PIPPricesButton",OBJPROP_TEXT,"Prices"); + ObjectSetString(0,"PIPPricesButton",OBJPROP_FONT,"Arial"); + ObjectSetInteger(0,"PIPPricesButton",OBJPROP_FONTSIZE,10); + ObjectSetInteger(0,"PIPPricesButton",OBJPROP_STATE,showprices); + ObjectSetInteger(0,"PIPPricesButton",OBJPROP_SELECTABLE,0); +//--- Scale + + ObjectSetInteger(0,"PIPPlusButton",OBJPROP_COLOR,TextColor); + ObjectSetInteger(0,"PIPPlusButton",OBJPROP_BGCOLOR,BGColor); + ObjectSetInteger(0,"PIPPlusButton",OBJPROP_XDISTANCE,xdist+xsize-56); + ObjectSetInteger(0,"PIPPlusButton",OBJPROP_YDISTANCE,ydist); + ObjectSetInteger(0,"PIPPlusButton",OBJPROP_XSIZE,18); + ObjectSetInteger(0,"PIPPlusButton",OBJPROP_YSIZE,18); + ObjectSetString(0,"PIPPlusButton",OBJPROP_TEXT,"+"); + ObjectSetString(0,"PIPPlusButton",OBJPROP_FONT,"Arial"); + ObjectSetInteger(0,"PIPPlusButton",OBJPROP_FONTSIZE,10); + ObjectSetInteger(0,"PIPPlusButton",OBJPROP_STATE,0); + ObjectSetInteger(0,"PIPPlusButton",OBJPROP_SELECTABLE,0); +//--- Scale - + ObjectSetInteger(0,"PIPMinusButton",OBJPROP_COLOR,TextColor); + ObjectSetInteger(0,"PIPMinusButton",OBJPROP_BGCOLOR,BGColor); + ObjectSetInteger(0,"PIPMinusButton",OBJPROP_XDISTANCE,xdist+xsize-37); + ObjectSetInteger(0,"PIPMinusButton",OBJPROP_YDISTANCE,ydist); + ObjectSetInteger(0,"PIPMinusButton",OBJPROP_XSIZE,18); + ObjectSetInteger(0,"PIPMinusButton",OBJPROP_YSIZE,18); + ObjectSetString(0,"PIPMinusButton",OBJPROP_TEXT,"-"); + ObjectSetString(0,"PIPMinusButton",OBJPROP_FONT,"Arial"); + ObjectSetInteger(0,"PIPMinusButton",OBJPROP_FONTSIZE,10); + ObjectSetInteger(0,"PIPMinusButton",OBJPROP_STATE,0); + ObjectSetInteger(0,"PIPMinusButton",OBJPROP_SELECTABLE,0); +//--- Hide/Show + ObjectSetInteger(0,"PIPHideButton",OBJPROP_COLOR,TextColor); + ObjectSetInteger(0,"PIPHideButton",OBJPROP_BGCOLOR,BGColor); + ObjectSetInteger(0,"PIPHideButton",OBJPROP_XDISTANCE,xdist+xsize-18); + ObjectSetInteger(0,"PIPHideButton",OBJPROP_YDISTANCE,ydist); + ObjectSetInteger(0,"PIPHideButton",OBJPROP_XSIZE,18); + ObjectSetInteger(0,"PIPHideButton",OBJPROP_YSIZE,18); + ObjectSetString(0,"PIPHideButton",OBJPROP_TEXT,"_"); + ObjectSetString(0,"PIPHideButton",OBJPROP_FONT,"Arial"); + ObjectSetInteger(0,"PIPHideButton",OBJPROP_FONTSIZE,8); + ObjectSetInteger(0,"PIPHideButton",OBJPROP_STATE,0); + ObjectSetInteger(0,"PIPHideButton",OBJPROP_SELECTABLE,0); +//--- Chart + ObjectSetString(0,"PIPChart",OBJPROP_SYMBOL,curr_symbol); + ObjectSetInteger(0,"PIPChart",OBJPROP_PERIOD,curr_period); + ObjectSetInteger(0,"PIPChart",OBJPROP_XDISTANCE,xdist); + ObjectSetInteger(0,"PIPChart",OBJPROP_YDISTANCE,ydist+20); + ObjectSetInteger(0,"PIPChart",OBJPROP_XSIZE,xsize); + ObjectSetInteger(0,"PIPChart",OBJPROP_YSIZE,ysize); + ObjectSetInteger(0,"PIPChart",OBJPROP_DATE_SCALE,showdates); + ObjectSetInteger(0,"PIPChart",OBJPROP_PRICE_SCALE,showprices); + ObjectSetInteger(0,"PIPChart",OBJPROP_SELECTABLE,0); + ObjectSetInteger(0,"PIPChart",OBJPROP_CHART_SCALE,scale); + } +//+------------------------------------------------------------------+ +//| Hide chart object | +//+------------------------------------------------------------------+ +void PIPHideChart() + { + ObjectSetInteger(0,"PIPChart",OBJPROP_XDISTANCE,-1); + ObjectSetInteger(0,"PIPChart",OBJPROP_YDISTANCE,-1); + ObjectSetInteger(0,"PIPChart",OBJPROP_XSIZE,0); + ObjectSetInteger(0,"PIPChart",OBJPROP_YSIZE,0); + } +//+------------------------------------------------------------------+ +//| Convert string to history period | +//+------------------------------------------------------------------+ +bool StrToPeriod(const string strper,ENUM_TIMEFRAMES& period) + { + bool res=true; +//--- ìåñÿö + if(strper=="MN" || strper=="MN1" || strper=="MONTH" || strper=="MONTHLY") period=PERIOD_MN1; +//--- íåäåëÿ + else if(strper=="W" || strper=="W1" || strper=="WEEK" || strper=="10080" || strper=="WEEKLY") period=PERIOD_W1; +//--- äåíü + else if(strper=="D" || strper=="D1" || strper=="DAY" || strper=="1440" || strper=="DAILY") period=PERIOD_D1; +//--- ÷àñîâêè + else if(strper=="H" || strper=="H1" || strper=="HOUR" || strper=="60") period=PERIOD_H1; + else if(strper=="H12" || strper=="720") period=PERIOD_H12; + else if(strper=="H8" || strper=="480") period=PERIOD_H8; + else if(strper=="H6" || strper=="360") period=PERIOD_H6; + else if(strper=="H4" || strper=="240") period=PERIOD_H4; + else if(strper=="H3" || strper=="180") period=PERIOD_H3; + else if(strper=="H2" || strper=="120") period=PERIOD_H2; +//--- ìèíóòêè + else if(strper=="M" || strper=="M1" || strper=="MIN" || strper=="1" || strper=="MINUTE") period=PERIOD_M1; + else if(strper=="M30" || strper=="30") period=PERIOD_M30; + else if(strper=="M20" || strper=="20") period=PERIOD_M20; + else if(strper=="M15" || strper=="15") period=PERIOD_M15; + else if(strper=="M12" || strper=="12") period=PERIOD_M12; + else if(strper=="M10" || strper=="10") period=PERIOD_M10; + else if(strper=="M6" || strper=="6") period=PERIOD_M6; + else if(strper=="M5" || strper=="5") period=PERIOD_M5; + else if(strper=="M4" || strper=="4") period=PERIOD_M4; + else if(strper=="M3" || strper=="3") period=PERIOD_M3; + else if(strper=="M2" || strper=="2") period=PERIOD_M2; +//--- íå ïîëó÷èëîñü + else res=false; +//--- + return(res); + } +//+------------------------------------------------------------------+ +//| Convert history period to string | +//+------------------------------------------------------------------+ +bool PeriodToStr(ENUM_TIMEFRAMES period,string& strper) + { + bool res=true; +//--- + switch(period) + { + case PERIOD_MN1 : strper="MN1"; break; + case PERIOD_W1 : strper="W1"; break; + case PERIOD_D1 : strper="D1"; break; + case PERIOD_H1 : strper="H1"; break; + case PERIOD_H2 : strper="H2"; break; + case PERIOD_H3 : strper="H3"; break; + case PERIOD_H4 : strper="H4"; break; + case PERIOD_H6 : strper="H6"; break; + case PERIOD_H8 : strper="H8"; break; + case PERIOD_H12 : strper="H12"; break; + case PERIOD_M1 : strper="M1"; break; + case PERIOD_M2 : strper="M2"; break; + case PERIOD_M3 : strper="M3"; break; + case PERIOD_M4 : strper="M4"; break; + case PERIOD_M5 : strper="M5"; break; + case PERIOD_M6 : strper="M6"; break; + case PERIOD_M10 : strper="M10"; break; + case PERIOD_M12 : strper="M12"; break; + case PERIOD_M15 : strper="M15"; break; + case PERIOD_M20 : strper="M20"; break; + case PERIOD_M30 : strper="M30"; break; + default : res=false; + } +//--- + return(res); + } +//+------------------------------------------------------------------+ diff --git a/Experts/Examples/Controls/Controls.mq5 b/Experts/Examples/Controls/Controls.mq5 new file mode 100644 index 0000000..0f8d1ff --- /dev/null +++ b/Experts/Examples/Controls/Controls.mq5 @@ -0,0 +1,45 @@ +//+------------------------------------------------------------------+ +//| Controls.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +#property version "1.00" +#include "ControlsDialog.mqh" +//+------------------------------------------------------------------+ +//| Global Variables | +//+------------------------------------------------------------------+ +CControlsDialog ExtDialog; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create application dialog + if(!ExtDialog.Create(0,"Controls",0,20,20,360,324)) + return(INIT_FAILED); +//--- run application + ExtDialog.Run(); +//--- succeed + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy dialog + ExtDialog.Destroy(reason); + } +//+------------------------------------------------------------------+ +//| Expert chart event function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, // event ID + const long& lparam, // event parameter of the long type + const double& dparam, // event parameter of the double type + const string& sparam) // event parameter of the string type + { + ExtDialog.ChartEvent(id,lparam,dparam,sparam); + } +//+------------------------------------------------------------------+ diff --git a/Experts/Examples/Controls/ControlsDialog.mqh b/Experts/Examples/Controls/ControlsDialog.mqh new file mode 100644 index 0000000..8ae555d --- /dev/null +++ b/Experts/Examples/Controls/ControlsDialog.mqh @@ -0,0 +1,427 @@ +//+------------------------------------------------------------------+ +//| ControlsDialog.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include +#include +#include +#include +#include +#include +#include +#include +//+------------------------------------------------------------------+ +//| defines | +//+------------------------------------------------------------------+ +//--- indents and gaps +#define INDENT_LEFT (11) // indent from left (with allowance for border width) +#define INDENT_TOP (11) // indent from top (with allowance for border width) +#define INDENT_RIGHT (11) // indent from right (with allowance for border width) +#define INDENT_BOTTOM (11) // indent from bottom (with allowance for border width) +#define CONTROLS_GAP_X (5) // gap by X coordinate +#define CONTROLS_GAP_Y (5) // gap by Y coordinate +//--- for buttons +#define BUTTON_WIDTH (100) // size by X coordinate +#define BUTTON_HEIGHT (20) // size by Y coordinate +//--- for the indication area +#define EDIT_HEIGHT (20) // size by Y coordinate +//--- for group controls +#define GROUP_WIDTH (150) // size by X coordinate +#define LIST_HEIGHT (179) // size by Y coordinate +#define RADIO_HEIGHT (56) // size by Y coordinate +#define CHECK_HEIGHT (93) // size by Y coordinate +//+------------------------------------------------------------------+ +//| Class CControlsDialog | +//| Usage: main dialog of the Controls application | +//+------------------------------------------------------------------+ +class CControlsDialog : public CAppDialog + { +private: + CEdit m_edit; // the display field object + CButton m_button1; // the button object + CButton m_button2; // the button object + CButton m_button3; // the fixed button object + CSpinEdit m_spin_edit; // the up-down object + CDatePicker m_date; // the datepicker object + CListView m_list_view; // the list object + CComboBox m_combo_box; // the dropdown list object + CRadioGroup m_radio_group; // the radio buttons group object + CCheckGroup m_check_group; // the check box group object + +public: + CControlsDialog(void); + ~CControlsDialog(void); + //--- create + virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2); + //--- chart event handler + virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam); + +protected: + //--- create dependent controls + bool CreateEdit(void); + bool CreateButton1(void); + bool CreateButton2(void); + bool CreateButton3(void); + bool CreateSpinEdit(void); + bool CreateDate(void); + bool CreateListView(void); + bool CreateComboBox(void); + bool CreateRadioGroup(void); + bool CreateCheckGroup(void); + //--- handlers of the dependent controls events + void OnClickButton1(void); + void OnClickButton2(void); + void OnClickButton3(void); + void OnChangeSpinEdit(void); + void OnChangeDate(void); + void OnChangeListView(void); + void OnChangeComboBox(void); + void OnChangeRadioGroup(void); + void OnChangeCheckGroup(void); + }; +//+------------------------------------------------------------------+ +//| Event Handling | +//+------------------------------------------------------------------+ +EVENT_MAP_BEGIN(CControlsDialog) + ON_EVENT(ON_CLICK,m_button1,OnClickButton1) + ON_EVENT(ON_CLICK,m_button2,OnClickButton2) + ON_EVENT(ON_CLICK,m_button3,OnClickButton3) + ON_EVENT(ON_CHANGE,m_spin_edit,OnChangeSpinEdit) + ON_EVENT(ON_CHANGE,m_date,OnChangeDate) + ON_EVENT(ON_CHANGE,m_list_view,OnChangeListView) + ON_EVENT(ON_CHANGE,m_combo_box,OnChangeComboBox) + ON_EVENT(ON_CHANGE,m_radio_group,OnChangeRadioGroup) + ON_EVENT(ON_CHANGE,m_check_group,OnChangeCheckGroup) +EVENT_MAP_END(CAppDialog) +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CControlsDialog::CControlsDialog(void) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CControlsDialog::~CControlsDialog(void) + { + } +//+------------------------------------------------------------------+ +//| Create | +//+------------------------------------------------------------------+ +bool CControlsDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) + { + if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2)) + return(false); +//--- create dependent controls + if(!CreateEdit()) + return(false); + if(!CreateButton1()) + return(false); + if(!CreateButton2()) + return(false); + if(!CreateButton3()) + return(false); + if(!CreateSpinEdit()) + return(false); + if(!CreateListView()) + return(false); + if(!CreateDate()) + return(false); + if(!CreateRadioGroup()) + return(false); + if(!CreateCheckGroup()) + return(false); + if(!CreateComboBox()) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the display field | +//+------------------------------------------------------------------+ +bool CControlsDialog::CreateEdit(void) + { +//--- coordinates + int x1=INDENT_LEFT; + int y1=INDENT_TOP; + int x2=ClientAreaWidth()-INDENT_RIGHT; + int y2=y1+EDIT_HEIGHT; +//--- create + if(!m_edit.Create(m_chart_id,m_name+"Edit",m_subwin,x1,y1,x2,y2)) + return(false); + if(!m_edit.ReadOnly(true)) + return(false); + if(!Add(m_edit)) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "Button1" button | +//+------------------------------------------------------------------+ +bool CControlsDialog::CreateButton1(void) + { +//--- coordinates + int x1=INDENT_LEFT; + int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y); + int x2=x1+BUTTON_WIDTH; + int y2=y1+BUTTON_HEIGHT; +//--- create + if(!m_button1.Create(m_chart_id,m_name+"Button1",m_subwin,x1,y1,x2,y2)) + return(false); + if(!m_button1.Text("Button1")) + return(false); + if(!Add(m_button1)) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "Button2" button | +//+------------------------------------------------------------------+ +bool CControlsDialog::CreateButton2(void) + { +//--- coordinates + int x1=INDENT_LEFT+(BUTTON_WIDTH+CONTROLS_GAP_X); + int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y); + int x2=x1+BUTTON_WIDTH; + int y2=y1+BUTTON_HEIGHT; +//--- create + if(!m_button2.Create(m_chart_id,m_name+"Button2",m_subwin,x1,y1,x2,y2)) + return(false); + if(!m_button2.Text("Button2")) + return(false); + if(!Add(m_button2)) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "Button3" fixed button | +//+------------------------------------------------------------------+ +bool CControlsDialog::CreateButton3(void) + { +//--- coordinates + int x1=INDENT_LEFT+2*(BUTTON_WIDTH+CONTROLS_GAP_X); + int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y); + int x2=x1+BUTTON_WIDTH; + int y2=y1+BUTTON_HEIGHT; +//--- create + if(!m_button3.Create(m_chart_id,m_name+"Button3",m_subwin,x1,y1,x2,y2)) + return(false); + if(!m_button3.Text("Locked")) + return(false); + if(!Add(m_button3)) + return(false); + m_button3.Locking(true); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "SpinEdit" element | +//+------------------------------------------------------------------+ +bool CControlsDialog::CreateSpinEdit(void) + { +//--- coordinates + int x1=INDENT_LEFT; + int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y)+(BUTTON_HEIGHT+CONTROLS_GAP_Y); + int x2=x1+GROUP_WIDTH; + int y2=y1+EDIT_HEIGHT; +//--- create + if(!m_spin_edit.Create(m_chart_id,m_name+"SpinEdit",m_subwin,x1,y1,x2,y2)) + return(false); + if(!Add(m_spin_edit)) + return(false); + m_spin_edit.MinValue(10); + m_spin_edit.MaxValue(1000); + m_spin_edit.Value(100); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "DatePicker" element | +//+------------------------------------------------------------------+ +bool CControlsDialog::CreateDate(void) + { +//--- coordinates + int x1=INDENT_LEFT+GROUP_WIDTH+2*CONTROLS_GAP_X; + int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y)+(BUTTON_HEIGHT+CONTROLS_GAP_Y); + int x2=x1+GROUP_WIDTH; + int y2=y1+EDIT_HEIGHT; +//--- create + if(!m_date.Create(m_chart_id,m_name+"Date",m_subwin,x1,y1,x2,y2)) + return(false); + if(!Add(m_date)) + return(false); + m_date.Value(TimeCurrent()); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "ListView" element | +//+------------------------------------------------------------------+ +bool CControlsDialog::CreateListView(void) + { +//--- coordinates + int x1=INDENT_LEFT+GROUP_WIDTH+2*CONTROLS_GAP_X; + int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y)+ + (BUTTON_HEIGHT+CONTROLS_GAP_Y)+ + (EDIT_HEIGHT+2*CONTROLS_GAP_Y); + int x2=x1+GROUP_WIDTH; + int y2=y1+LIST_HEIGHT-CONTROLS_GAP_Y; +//--- create + if(!m_list_view.Create(m_chart_id,m_name+"ListView",m_subwin,x1,y1,x2,y2)) + return(false); + if(!Add(m_list_view)) + return(false); +//--- fill out with strings + for(int i=0;i<16;i++) + if(!m_list_view.AddItem("Item "+IntegerToString(i))) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "ComboBox" element | +//+------------------------------------------------------------------+ +bool CControlsDialog::CreateComboBox(void) + { +//--- coordinates + int x1=INDENT_LEFT; + int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y)+ + (BUTTON_HEIGHT+CONTROLS_GAP_Y)+ + (EDIT_HEIGHT+CONTROLS_GAP_Y); + int x2=x1+GROUP_WIDTH; + int y2=y1+EDIT_HEIGHT; +//--- create + if(!m_combo_box.Create(m_chart_id,m_name+"ComboBox",m_subwin,x1,y1,x2,y2)) + return(false); + if(!Add(m_combo_box)) + return(false); +//--- fill out with strings + for(int i=0;i<16;i++) + if(!m_combo_box.ItemAdd("Item "+IntegerToString(i))) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "RadioGroup" element | +//+------------------------------------------------------------------+ +bool CControlsDialog::CreateRadioGroup(void) + { +//--- coordinates + int x1=INDENT_LEFT; + int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y)+ + (BUTTON_HEIGHT+CONTROLS_GAP_Y)+ + (EDIT_HEIGHT+CONTROLS_GAP_Y)+ + (EDIT_HEIGHT+CONTROLS_GAP_Y); + int x2=x1+GROUP_WIDTH; + int y2=y1+RADIO_HEIGHT; +//--- create + if(!m_radio_group.Create(m_chart_id,m_name+"RadioGroup",m_subwin,x1,y1,x2,y2)) + return(false); + if(!Add(m_radio_group)) + return(false); +//--- fill out with strings + for(int i=0;i<3;i++) + if(!m_radio_group.AddItem("Item "+IntegerToString(i),1< +#include +#include +#include +//--- +input double InpLots =0.1; // Lots +input int InpTakeProfit =50; // Take Profit (in pips) +input int InpTrailingStop =30; // Trailing Stop Level (in pips) +input int InpMACDOpenLevel =3; // MACD open level (in pips) +input int InpMACDCloseLevel=2; // MACD close level (in pips) +input int InpMATrendPeriod =26; // MA trend period +//--- +int ExtTimeOut=10; // time out in seconds between trade operations +//+------------------------------------------------------------------+ +//| MACD Sample expert class | +//+------------------------------------------------------------------+ +class CSampleExpert + { +protected: + double m_adjusted_point; // point value adjusted for 3 or 5 points + CTrade m_trade; // trading object + CSymbolInfo m_symbol; // symbol info object + CPositionInfo m_position; // trade position object + CAccountInfo m_account; // account info wrapper + //--- indicators + int m_handle_macd; // MACD indicator handle + int m_handle_ema; // moving average indicator handle + //--- indicator buffers + double m_buff_MACD_main[]; // MACD indicator main buffer + double m_buff_MACD_signal[]; // MACD indicator signal buffer + double m_buff_EMA[]; // EMA indicator buffer + //--- indicator data for processing + double m_macd_current; + double m_macd_previous; + double m_signal_current; + double m_signal_previous; + double m_ema_current; + double m_ema_previous; + //--- + double m_macd_open_level; + double m_macd_close_level; + double m_traling_stop; + double m_take_profit; + +public: + CSampleExpert(void); + ~CSampleExpert(void); + bool Init(void); + void Deinit(void); + bool Processing(void); + +protected: + bool InitCheckParameters(const int digits_adjust); + bool InitIndicators(void); + bool LongClosed(void); + bool ShortClosed(void); + bool LongModified(void); + bool ShortModified(void); + bool LongOpened(void); + bool ShortOpened(void); + }; +//--- global expert +CSampleExpert ExtExpert; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CSampleExpert::CSampleExpert(void) : m_adjusted_point(0), + m_handle_macd(INVALID_HANDLE), + m_handle_ema(INVALID_HANDLE), + m_macd_current(0), + m_macd_previous(0), + m_signal_current(0), + m_signal_previous(0), + m_ema_current(0), + m_ema_previous(0), + m_macd_open_level(0), + m_macd_close_level(0), + m_traling_stop(0), + m_take_profit(0) + { + ArraySetAsSeries(m_buff_MACD_main,true); + ArraySetAsSeries(m_buff_MACD_signal,true); + ArraySetAsSeries(m_buff_EMA,true); + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CSampleExpert::~CSampleExpert(void) + { + } +//+------------------------------------------------------------------+ +//| Initialization and checking for input parameters | +//+------------------------------------------------------------------+ +bool CSampleExpert::Init(void) + { +//--- initialize common information + m_symbol.Name(Symbol()); // symbol + m_trade.SetExpertMagicNumber(MACD_MAGIC); // magic + m_trade.SetMarginMode(); + m_trade.SetTypeFillingBySymbol(Symbol()); +//--- tuning for 3 or 5 digits + int digits_adjust=1; + if(m_symbol.Digits()==3 || m_symbol.Digits()==5) + digits_adjust=10; + m_adjusted_point=m_symbol.Point()*digits_adjust; +//--- set default deviation for trading in adjusted points + m_macd_open_level =InpMACDOpenLevel*m_adjusted_point; + m_macd_close_level=InpMACDCloseLevel*m_adjusted_point; + m_traling_stop =InpTrailingStop*m_adjusted_point; + m_take_profit =InpTakeProfit*m_adjusted_point; +//--- set default deviation for trading in adjusted points + m_trade.SetDeviationInPoints(3*digits_adjust); +//--- + if(!InitCheckParameters(digits_adjust)) + return(false); + if(!InitIndicators()) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Checking for input parameters | +//+------------------------------------------------------------------+ +bool CSampleExpert::InitCheckParameters(const int digits_adjust) + { +//--- initial data checks + if(InpTakeProfit*digits_adjustm_symbol.LotsMax()) + { + printf("Lots amount must be in the range from %f to %f",m_symbol.LotsMin(),m_symbol.LotsMax()); + return(false); + } + if(MathAbs(InpLots/m_symbol.LotsStep()-MathRound(InpLots/m_symbol.LotsStep()))>1.0E-10) + { + printf("Lots amount is not corresponding with lot step %f",m_symbol.LotsStep()); + return(false); + } +//--- warning + if(InpTakeProfit<=InpTrailingStop) + printf("Warning: Trailing Stop must be less than Take Profit"); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Initialization of the indicators | +//+------------------------------------------------------------------+ +bool CSampleExpert::InitIndicators(void) + { +//--- create MACD indicator + if(m_handle_macd==INVALID_HANDLE) + if((m_handle_macd=iMACD(NULL,0,12,26,9,PRICE_CLOSE))==INVALID_HANDLE) + { + printf("Error creating MACD indicator"); + return(false); + } +//--- create EMA indicator and add it to collection + if(m_handle_ema==INVALID_HANDLE) + if((m_handle_ema=iMA(NULL,0,InpMATrendPeriod,0,MODE_EMA,PRICE_CLOSE))==INVALID_HANDLE) + { + printf("Error creating EMA indicator"); + return(false); + } +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Check for long position closing | +//+------------------------------------------------------------------+ +bool CSampleExpert::LongClosed(void) + { + bool res=false; +//--- should it be closed? + if(m_macd_current>0) + if(m_macd_currentm_signal_previous) + if(m_macd_current>m_macd_close_level) + { + //--- close position + if(m_trade.PositionClose(Symbol())) + printf("Long position by %s to be closed",Symbol()); + else + printf("Error closing position by %s : '%s'",Symbol(),m_trade.ResultComment()); + //--- processed and cannot be modified + res=true; + } +//--- result + return(res); + } +//+------------------------------------------------------------------+ +//| Check for short position closing | +//+------------------------------------------------------------------+ +bool CSampleExpert::ShortClosed(void) + { + bool res=false; +//--- should it be closed? + if(m_macd_current<0) + if(m_macd_current>m_signal_current && m_macd_previousm_macd_close_level) + { + //--- close position + if(m_trade.PositionClose(Symbol())) + printf("Short position by %s to be closed",Symbol()); + else + printf("Error closing position by %s : '%s'",Symbol(),m_trade.ResultComment()); + //--- processed and cannot be modified + res=true; + } +//--- result + return(res); + } +//+------------------------------------------------------------------+ +//| Check for long position modifying | +//+------------------------------------------------------------------+ +bool CSampleExpert::LongModified(void) + { + bool res=false; +//--- check for trailing stop + if(InpTrailingStop>0) + { + if(m_symbol.Bid()-m_position.PriceOpen()>m_adjusted_point*InpTrailingStop) + { + double sl=NormalizeDouble(m_symbol.Bid()-m_traling_stop,m_symbol.Digits()); + double tp=m_position.TakeProfit(); + if(m_position.StopLoss()0) + { + if((m_position.PriceOpen()-m_symbol.Ask())>(m_adjusted_point*InpTrailingStop)) + { + double sl=NormalizeDouble(m_symbol.Ask()+m_traling_stop,m_symbol.Digits()); + double tp=m_position.TakeProfit(); + if(m_position.StopLoss()>sl || m_position.StopLoss()==0.0) + { + //--- modify position + if(m_trade.PositionModify(Symbol(),sl,tp)) + printf("Short position by %s to be modified",Symbol()); + else + { + printf("Error modifying position by %s : '%s'",Symbol(),m_trade.ResultComment()); + printf("Modify parameters : SL=%f,TP=%f",sl,tp); + } + //--- modified and must exit from expert + res=true; + } + } + } +//--- result + return(res); + } +//+------------------------------------------------------------------+ +//| Check for long position opening | +//+------------------------------------------------------------------+ +bool CSampleExpert::LongOpened(void) + { + bool res=false; +//--- check for long position (BUY) possibility + if(m_macd_current<0) + if(m_macd_current>m_signal_current && m_macd_previous(m_macd_open_level) && m_ema_current>m_ema_previous) + { + double price=m_symbol.Ask(); + double tp =m_symbol.Bid()+m_take_profit; + //--- check for free money + if(m_account.FreeMarginCheck(Symbol(),ORDER_TYPE_BUY,InpLots,price)<0.0) + printf("We have no money. Free Margin = %f",m_account.FreeMargin()); + else + { + //--- open position + if(m_trade.PositionOpen(Symbol(),ORDER_TYPE_BUY,InpLots,price,0.0,tp)) + printf("Position by %s to be opened",Symbol()); + else + { + printf("Error opening BUY position by %s : '%s'",Symbol(),m_trade.ResultComment()); + printf("Open parameters : price=%f,TP=%f",price,tp); + } + } + //--- in any case we must exit from expert + res=true; + } +//--- result + return(res); + } +//+------------------------------------------------------------------+ +//| Check for short position opening | +//+------------------------------------------------------------------+ +bool CSampleExpert::ShortOpened(void) + { + bool res=false; +//--- check for short position (SELL) possibility + if(m_macd_current>0) + if(m_macd_currentm_signal_previous) + if(m_macd_current>(m_macd_open_level) && m_ema_current=limit_time) + { + //--- check for data + if(Bars(Symbol(),Period())>2*InpMATrendPeriod) + { + //--- change limit time by timeout in seconds if processed + if(ExtExpert.Processing()) + limit_time=TimeCurrent()+ExtTimeOut; + } + } + } +//+------------------------------------------------------------------+ diff --git a/Experts/Examples/Moving Average/Moving Average.mq5 b/Experts/Examples/Moving Average/Moving Average.mq5 new file mode 100644 index 0000000..935780a --- /dev/null +++ b/Experts/Examples/Moving Average/Moving Average.mq5 @@ -0,0 +1,233 @@ +//+------------------------------------------------------------------+ +//| Moving Averages.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +#property version "1.00" + +#include + +input double MaximumRisk = 0.02; // Maximum Risk in percentage +input double DecreaseFactor = 3; // Descrease factor +input int MovingPeriod = 12; // Moving Average period +input int MovingShift = 6; // Moving Average shift +//--- +int ExtHandle=0; +bool ExtHedging=false; +CTrade ExtTrade; + +#define MA_MAGIC 1234501 +//+------------------------------------------------------------------+ +//| Calculate optimal lot size | +//+------------------------------------------------------------------+ +double TradeSizeOptimized(void) + { + double price=0.0; + double margin=0.0; +//--- select lot size + if(!SymbolInfoDouble(_Symbol,SYMBOL_ASK,price)) + return(0.0); + if(!OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,margin)) + return(0.0); + if(margin<=0.0) + return(0.0); + + double lot=NormalizeDouble(AccountInfoDouble(ACCOUNT_MARGIN_FREE)*MaximumRisk/margin,2); +//--- calculate number of losses orders without a break + if(DecreaseFactor>0) + { + //--- select history for access + HistorySelect(0,TimeCurrent()); + //--- + int orders=HistoryDealsTotal(); // total history deals + int losses=0; // number of losses orders without a break + + for(int i=orders-1;i>=0;i--) + { + ulong ticket=HistoryDealGetTicket(i); + if(ticket==0) + { + Print("HistoryDealGetTicket failed, no trade history"); + break; + } + //--- check symbol + if(HistoryDealGetString(ticket,DEAL_SYMBOL)!=_Symbol) + continue; + //--- check Expert Magic number + if(HistoryDealGetInteger(ticket,DEAL_MAGIC)!=MA_MAGIC) + continue; + //--- check profit + double profit=HistoryDealGetDouble(ticket,DEAL_PROFIT); + if(profit>0.0) + break; + if(profit<0.0) + losses++; + } + //--- + if(losses>1) + lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1); + } +//--- normalize and check limits + double stepvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP); + lot=stepvol*NormalizeDouble(lot/stepvol,0); + + double minvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN); + if(lotmaxvol) + lot=maxvol; +//--- return trading volume + return(lot); + } +//+------------------------------------------------------------------+ +//| Check for open position conditions | +//+------------------------------------------------------------------+ +void CheckForOpen(void) + { + MqlRates rt[2]; +//--- go trading only for first ticks of new bar + if(CopyRates(_Symbol,_Period,0,2,rt)!=2) + { + Print("CopyRates of ",_Symbol," failed, no history"); + return; + } + if(rt[1].tick_volume>1) + return; +//--- get current Moving Average + double ma[1]; + if(CopyBuffer(ExtHandle,0,0,1,ma)!=1) + { + Print("CopyBuffer from iMA failed, no data"); + return; + } +//--- check signals + ENUM_ORDER_TYPE signal=WRONG_VALUE; + + if(rt[0].open>ma[0] && rt[0].closema[0]) + signal=ORDER_TYPE_BUY; // buy conditions + } +//--- additional checking + if(signal!=WRONG_VALUE) + { + if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) && Bars(_Symbol,_Period)>100) + ExtTrade.PositionOpen(_Symbol,signal,TradeSizeOptimized(), + SymbolInfoDouble(_Symbol,signal==ORDER_TYPE_SELL ? SYMBOL_BID:SYMBOL_ASK), + 0,0); + } +//--- + } +//+------------------------------------------------------------------+ +//| Check for close position conditions | +//+------------------------------------------------------------------+ +void CheckForClose(void) + { + MqlRates rt[2]; +//--- go trading only for first ticks of new bar + if(CopyRates(_Symbol,_Period,0,2,rt)!=2) + { + Print("CopyRates of ",_Symbol," failed, no history"); + return; + } + if(rt[1].tick_volume>1) + return; +//--- get current Moving Average + double ma[1]; + if(CopyBuffer(ExtHandle,0,0,1,ma)!=1) + { + Print("CopyBuffer from iMA failed, no data"); + return; + } +//--- positions already selected before + bool signal=false; + long type=PositionGetInteger(POSITION_TYPE); + + if(type==(long)POSITION_TYPE_BUY && rt[0].open>ma[0] && rt[0].closema[0]) + signal=true; +//--- additional checking + if(signal) + { + if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) && Bars(_Symbol,_Period)>100) + ExtTrade.PositionClose(_Symbol,3); + } +//--- + } +//+------------------------------------------------------------------+ +//| Position select depending on netting or hedging | +//+------------------------------------------------------------------+ +bool SelectPosition() + { + bool res=false; +//--- check position in Hedging mode + if(ExtHedging) + { + uint total=PositionsTotal(); + for(uint i=0; ic91zijC^#T0qsSzJ zq70(Uv&f*#^C&##*@wt1YNAbJ;=t>JK9#to{8T2)=l@kj{CvuV%3|kHIx6W}`n#n67Qg(WI%OAr zRcV+yCFj*C3e_M#M1$?DgCG40Q5w2=Pxv7a~pDNOAEEk=}5+d$D%S+;ys`wg|hig)PQA@1jDGS%8^x_1i z3d3~B3)Ug)tPbe`6G-!)z-2#el6cTHYT~m`L*$@Ago`?fUh1TsQWN<< zRjQwws6kDc!}I*IixP93l35X)`dO`-2M;cIa(SW=VL%}v6(bs?kZ$09? z^a*#<;nV?b7HnOO@lF?vw;$z=t(G|3>J#TVj?6Qf>*8PgS&`kP+8nCJ7l+5jB~-P-9X~O~n7m6zsm4#dp>-akQC)i;XUu)=y#LW?OW( zxu9z)wB4CSo0f~7j3*;No1*jDlnGCZLN%3MNd0)mSJo=(tco@mWg2rWb~4qmQ>l)d zMpfK&N+YLpC`=x=evaP407P4{7H z`4;hBy23YI;jNA`kE^Gp+4+^PBOGM8#9zF59?rtyiR_#H@$^*5eHndLWGR4M)V3$ec1RGKwVL(xs zE}4Pa#2g=|s$cTAI!jRri={X3BY2W6`_GVumJ(88Q^}t4FMdn6c5l zUoHHVYLz9vB6zP+n>>fwOMj#;WiGWTZwvlA6h*y_x7!Cy+2M$ug)=(qY|-~g!$9@` z^}O#HlhnyLj}$b87cbO5g3b|ic6wm5X)@8C)5s5-K}Ga5O2Q|T9b`nTr(w=0++A3;t2 znBTUH2)2UXr43{Br8SnOGq~XXGTEUfRL1?Dvd9_agiI0p#z@7lO@5s^sou*HcfR0$ zKx6tM8Z#CPeMo)AQfe+QB|mBjc6NV8@2hW_dMu9j<^STX8xMJ-;}Nq4MtHe*1cMd@ z<7End+os^fOYIncWrK&k3F&8Fqbyp|E98bwC*H?c#ji_wYqVa8`zM;NETQqrG8(S@ zO{^=BrLCYcc?H=Kf91UAB1|n7V{CDV$)-D)^w|dVKQUv{w_Z$(sbQw*$8_O`VVwev zZjnoD6Q6wjH=?{>rzrA|g8w>sVXu(j`;v-ZpZXpR=?evG2~Ag*(UkcSOT1i&K$Ao$>#o2x#c01>@^{YRyVbyF_eq_SD`7_X6x(4la_83^7;MJOHW?_o;5rSOjP#F0R<#BV#yD*zXznLn2V}?}ohcss{r&(~DGC!p;>vLr3tH_G{ z6c3k=#lBm~tDCGaGIzpghbuce=o#c8xygtJF9SYuRe!^5+ zPa=HYrz~MH)yaz}jCz;kfH^9DOV-D<=Kh1$yw$YiuBR^3l(NgFm^oOYXCH`xa}xTl z$!G}1?{=PH%x-_wcL$&)q$#e)?eRlvmp>E4zMOk5lQrEB`Fodwk3|39D;Z+ZuI*gC zunbx1a%5tTOJWz25;#}IZ_WLj_WU)p=5L@W*Nm!kGrR-LG2C+sedh!wIK}azwLfax z+?ZzT&tFfcV3tyeWkECM+0A^N*UqNm8+_ex8|z^On|l;&6k6Le!fdZtygWarJoz)~ zuL_BIu1x$3sX_Bp{Pz5{v=?lot#C7qxfWEUne)NEgXoKTb)DlGv;8E--}vHOUQgbG zC*(X-kn~7FgwQ#mfL|1N{j9*{M+FD(DA;#ff%U*+{uEouy8T-zNLWkV)%CRGtPykl z52{m^lM%W=#qTKGNJp`S&~_U0tf)x0;w3wAwmK&==9@sKiF3W=_C1Ca3W}d7$Py}e ztRO?^lHf-_P!KBkKKB$H9e9XM^AJnUrLpS3Zt@bhP?u#vOa2z&?^mL~tEtTp`|09h z6~D8@oa?1lbe7rBT=)$Y8M~P*`aa$%9!<*=gj{RkXNmnU1uY{A8h&|9?BG9fZ|K9m zxS3r!ZJ1xG=8Fp%Ecd;@Cr6#x=V3!xnhgzkyJ;)lrL3)^*j)I$frhLv$c*i+ zATQs;^@_c;me^C1W5>+BKB(D;vDht?pG3U_f~i7t&rMmfW)-U~OtE#^ zgM+UFPJa9G3))Y9ngdP6jGsBiP)U|co|!M-opKRkTQ0HakNJaJuWQE?e zRr(^A`OsbKCFIVHnqzcVJ8+|F9}=gtWSi*2MscQnrsChIvgKy=LGkPnx@E4kmb;Oj z;>7G-4%o+LD)~|lKRtTHa_=Zuu@`lxXbfDEFm#G#uH6aJ)BWhE38JSdgua#_dYc01 zZSbMD-kqM>V^8A?j=X#)ZADwCy!@q#-+j%V9@!Ck>Rh>5??qRwFHL1WM8&u;|Bycq z9zGh)VT2oZeqhb1IL2-|3L9O)(wi5|-7$6dpsF;4{?-Tv+QJxY3udtOH2qCd4sOc$ z5~r(TkC=t6$THTe_%~|~(Oc(CU&9G{8vR5Lr)jASARx>Yt<8to7j;$Tf#k!FKmS5y z+YQba)(})E!#*LOl}^4C7lqN^5yxOh6hj>s7-|b*pv9m5Mo(pYi6eP^z08XGEHf3q zN9IVM@Tsp+w?ynqiAkCgn3{RzdU;KA9+Z*jEp=XyGf4qDSujJ zu?${MW~eis;pJUD(1_}>+mGLD`_cc4wgIzS|oBzre{gG<#Z}tTAa_^@Hs$BfD%QzVwM0e|DhU94scU|Ikm&lbG(+c_0;RM_KL$C~tVf(o_EKdbfSdv74XC}9AW^t!GojW&@7?w*Ogg%`E5ntkT zS0564&6aj?);;_F)m!hXoD<2bq4x6(v`5j~5=&cc3?31I%-!!ts;rI7hECRd26C

N&of zvPXk$XSvmRQS>i{fzCvF+b+@Bc$q7CaqJHX;cK6>Tue`T$#9ah8NHkPbL=Gq*0!p9= z#I6Fu0Z{}56lIfr5dlFE1q9r;%1TY;%=H}g*dNp1b3UIR_rr6}xxc?_yU+9Kv0T8n=l7;8 z&XBU$KC5uZMmkP%nw0m(IiUyzAnRRhULPW_i3Z6$exzQ_2pQi3bbeo0A`7!HEb9j)qup zB*>h@fo7xxm_1ufWi=%&$b{@rmE_EX+(=^zV){}TZ6vug6d8~kVSwU6$-{Ggd0ZcU z&#X)^ry{|U@&o;ZKY+r012`TrfYhM=#QF9k%F~jFtxpxAw%~hr3qsW9A~T{q%sAj@ zM(S=ej)$327^9*jR;A0M!clxE`A}-~oUe;D!AzJIqJC5)4x~KcHA>?Lk+*j+N53CL ztnVP49N*^8wss6~+C#ssaSZT`XP{d==I+s0ZV02_8h?h`I`QS=iFmB-Po#&1_%J6o z%3ShiDlw|Wk1@wWmEL*5uS^tfVt--3Cfvc49vDJ#{4h>L593JiFg!Pp=6{wh$6~|x zm^uVtx?&q$+IwNXO1O5O!f?W3 z=C@eRcgAF?H>T^t>Em&bK3+-maf!xc?QYEMwqs%KiiNEkLl&=Q)0*KV2lOX5x<7?` zEroAJ(hlh{nf>yEtuki%Bzrk{c2@J9qhNC~K1+J*3+F>$t z9R@qI=uz_kE6=i^Cj-QG1r!zERM2O}4?(B_37Peg1S?OOHFk z>XNlX)bNBJb&rJo1lr`j;^(I5td>_&8tCh#VT#>!4h0RB91JBVauCViNuNplWfFgN z%3H!8O?2>wyyhS|mi!q@{fwlZeHN_8;EQDp4#?s!KXo(wu9guJ^U%xPnC9NaaA!KE z&S98s2*%Vk0;4?zymIU+J*w|RyLb?6NDQOun+nrT)aFk#Mg`mOe+m!_US72oAG$8D%LzDGv*+Z4pTMeg1=NZB<+ z&#y=sN0DX%=}{jt`P+r4mUv-Z+lBhx114v;V%714IoGvJlbpVNu#T6+Or!lOw|A0x$=Q7yIhn4F-B`N4#3gX97k~D_A{clMv zM(FrOiSJW+cp`zpGnlx39h2;(?lNB=M`yFL^JiQiXtBShWzl&pE9Cm`1(z|l^`qB3 zH+staz4Fx>`Yv!mwbYY=OI@*AIfKw`9}^q+3GuuBiofp{WJG?ar$N zllE6mNzADsqxJlX)Gx67b|)swJm_t`g_piuP0txlIM;Wv|2Hk+PqbKN)?#4g#NhQo ze3Dqi%+hPvUVnsx_*wMBZ+u>Nk9SkfFvKH{xto@ee{eQ6+4E^QF_*@ZvqUp!JU*4W z%+DxE{)n`&F?xPw`ZR_+dSPU{g@uWE>^^seISF~h+8E(vxngCFXRAE#tnHDCvW7zHu1N*-S5CzdCm# zy%)ODcai)*&zYVx*YLW{8vd*f;eXe9l96afecmcsidS*5H6n29=mS@JmQj?bey+Zy#Q2Z_&>;ZA`hx8IXDhcePp?B>z6AnphNq%1CS+v4_EQ+XT;-5Bi2-~%an2>d>-msicmaXFT6>j|9Z!eol zoB6;m7LCS}3)Mk%p4~%NeIS?XchFV4P3NJ#awBc!-%1_qXv$wi$>AA#erx$US}R;= zDR<*c;Z{D~?D-FBEgP-KVla6Xv+AE!;9~@{twS$-G7$qUd;CJVDa|t_(trYp<*wsb#Zhx#&NZI zAJ>|rxYne22&Ah{YEiRQ>L47cLrc*LYO?0(`5mX#bks<#YIo396G;1+5IiINa7oJH z@#Aj2hk&dSELV8JG)J(KbHHXRs%6_SU+K%P*dQ*}C359_64zQ1xZbj#>&;3Yg1K_m z|5+W>x*S}Td8o^=*7G}Sws5)5m(IEXx*9@huM6jFMFd}aZYS(yrJmm{^Vod#7S7`9 zO{V}1=d0;4YXd#zy7G>bHw6W;!av0I3kSJ*F@YN`l82_Sr*%;F7mhLyt!1le%wPI~ zFZH=xzmqGCL0mo;A=*n@eJmw~(aiJl$1(00KmGDR@8d~#H(j@Xq(WvStEQR#MK%1t zcPMF@QFNR;%+0nV+-yze=7l(}pO2Cp?9uJ7^ueX-&9q7lnhI9v`CYZ%lB4f*^}2pO znyW2wTyE0PTAxHkaXg#94`Sk$U?K}ob6aLk>B-;gNAYH}D~jrpL^_(%g`dH#wnO4U z$wAE1K9Kzt&ZTO#oCi*vFS38ZuiLKc6D3zl&Td@LaO2`(u3b#0qd9|y>Qs*9B(NnS zlqv23O!kUmO?(#Nxz(hfKF6NpCCv5REuT9~*ZHH|Y|rF&`w?!nCjG7kN*`_)zMJsZ z%h|m0cYGgRjjlC^3p-Z4Cv&Skja!$pxpCHo%TuC*TLcE>U9bfoL{QT9{zRc29{gG;An&J=!$gPyPS-qpt4(ytNE z_y^_t8QkqU&fUue+`UrD?JMQn=&GXgVmap +//+------------------------------------------------------------------+ +//| Class CArray | +//| Purpose: Base class of dynamic arrays. | +//| Derives from class CObject. | +//+------------------------------------------------------------------+ +class CArray : public CObject + { +protected: + int m_step_resize; // increment size of the array + int m_data_total; // number of elements + int m_data_max; // maximmum size of the array without memory reallocation + int m_sort_mode; // mode of array sorting + +public: + CArray(void); + ~CArray(void); + //--- methods of access to protected data + int Step(void) const { return(m_step_resize); } + bool Step(const int step); + int Total(void) const { return(m_data_total); } + int Available(void) const { return(m_data_max-m_data_total); } + int Max(void) const { return(m_data_max); } + bool IsSorted(const int mode=0) const { return(m_sort_mode==mode); } + int SortMode(void) const { return(m_sort_mode); } + //--- cleaning method + void Clear(void) { m_data_total=0; } + //--- methods for working with files + virtual bool Save(const int file_handle); + virtual bool Load(const int file_handle); + //--- sorting method + void Sort(const int mode=0); + +protected: + virtual void QuickSort(int beg,int end,const int mode=0) { m_sort_mode=-1; } + //--- templates for methods of searching for minimum and maximum + template + int Minimum(const T &data[],const int start,const int count) const; + template + int Maximum(const T &data[],const int start,const int count) const; + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CArray::CArray(void) : m_step_resize(16), + m_data_total(0), + m_data_max(0), + m_sort_mode(-1) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CArray::~CArray(void) + { + } +//+------------------------------------------------------------------+ +//| Method Set for variable m_step_resize | +//+------------------------------------------------------------------+ +bool CArray::Step(const int step) + { +//--- check + if(step>0) + { + m_step_resize=step; + return(true); + } +//--- failure + return(false); + } +//+------------------------------------------------------------------+ +//| Sorting an array in ascending order | +//+------------------------------------------------------------------+ +void CArray::Sort(const int mode) + { +//--- check + if(IsSorted(mode)) + return; + m_sort_mode=mode; + if(m_data_total<=1) + return; +//--- sort + QuickSort(0,m_data_total-1,mode); + } +//+------------------------------------------------------------------+ +//| Writing header of array to file | +//+------------------------------------------------------------------+ +bool CArray::Save(const int file_handle) + { +//--- check handle + if(file_handle!=INVALID_HANDLE) + { + //--- write start marker - 0xFFFFFFFFFFFFFFFF + if(FileWriteLong(file_handle,-1)==sizeof(long)) + { + //--- write array type + if(FileWriteInteger(file_handle,Type(),INT_VALUE)==INT_VALUE) + return(true); + } + } +//--- failure + return(false); + } +//+------------------------------------------------------------------+ +//| Reading header of array from file | +//+------------------------------------------------------------------+ +bool CArray::Load(const int file_handle) + { +//--- check handle + if(file_handle!=INVALID_HANDLE) + { + //--- read and check start marker - 0xFFFFFFFFFFFFFFFF + if(FileReadLong(file_handle)==-1) + { + //--- read and check array type + if(FileReadInteger(file_handle,INT_VALUE)==Type()) + return(true); + } + } +//--- failure + return(false); + } +//+------------------------------------------------------------------+ +//| Find minimum of array | +//+------------------------------------------------------------------+ +template +int CArray::Minimum(const T &data[],const int start,const int count) const + { + int real_count; +//--- check for empty array + if(m_data_total<1) + { + SetUserError(ERR_USER_ARRAY_IS_EMPTY); + return(-1); + } + //--- check for start is out of range + if(start<0 || start>=m_data_total) + { + SetUserError(ERR_USER_ITEM_NOT_FOUND); + return(-1); + } +//--- compute count of elements + real_count=(count==WHOLE_ARRAY || start+count>m_data_total) ? m_data_total-start : count; +#ifdef __MQL5__ + return(ArrayMinimum(data,start,real_count)); +#else + return(ArrayMinimum(data,real_count,start)); +#endif + } +//+------------------------------------------------------------------+ +//| Find maximum of array | +//+------------------------------------------------------------------+ +template +int CArray::Maximum(const T &data[],const int start,const int count) const + { + int real_count; +//--- check for empty array + if(m_data_total<1) + { + SetUserError(ERR_USER_ARRAY_IS_EMPTY); + return(-1); + } + //--- check for start is out of range + if(start<0 || start>=m_data_total) + { + SetUserError(ERR_USER_ITEM_NOT_FOUND); + return(-1); + } +//--- compute count of elements + real_count=(count==WHOLE_ARRAY || start+count>m_data_total) ? m_data_total-start : count; +#ifdef __MQL5__ + return(ArrayMaximum(data,start,real_count)); +#else + return(ArrayMaximum(data,real_count,start)); +#endif + } +//+------------------------------------------------------------------+ diff --git a/Include/Arrays/ArrayChar.mqh b/Include/Arrays/ArrayChar.mqh new file mode 100644 index 0000000..73bc39e --- /dev/null +++ b/Include/Arrays/ArrayChar.mqh @@ -0,0 +1,771 @@ +//+------------------------------------------------------------------+ +//| ArrayChar.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include "Array.mqh" +//+------------------------------------------------------------------+ +//| Class CArrayChar. | +//| Purpose: Class of dynamic array of variables | +//| of char or uchar type. | +//| Derives from class CArray. | +//+------------------------------------------------------------------+ +class CArrayChar : public CArray + { +protected: + char m_data[]; // data array + +public: + CArrayChar(void); + ~CArrayChar(void); + //--- method of identifying the object + virtual int Type(void) const { return(TYPE_CHAR); } + //--- methods for working with files + virtual bool Save(const int file_handle); + virtual bool Load(const int file_handle); + //--- methods of managing dynamic memory + bool Reserve(const int size); + bool Resize(const int size); + bool Shutdown(void); + //--- methods of filling the array + bool Add(const char element); + bool AddArray(const char &src[]); + bool AddArray(const CArrayChar *src); + bool Insert(const char element,const int pos); + bool InsertArray(const char &src[],const int pos); + bool InsertArray(const CArrayChar *src,const int pos); + bool AssignArray(const char &src[]); + bool AssignArray(const CArrayChar *src); + //--- method of access to the array + char At(const int index) const; + char operator[](const int index) const { return(At(index)); } + //--- methods of searching for minimum and maximum + int Minimum(const int start,const int count) const { return(Minimum(m_data,start,count)); } + int Maximum(const int start,const int count) const { return(Maximum(m_data,start,count)); } + //--- methods of changing + bool Update(const int index,const char element); + bool Shift(const int index,const int shift); + //--- methods of deleting + bool Delete(const int index); + bool DeleteRange(int from,int to); + //--- methods for comparing arrays + bool CompareArray(const char &array[]) const; + bool CompareArray(const CArrayChar *array) const; + //--- methods for working with the sorted array + bool InsertSort(const char element); + int Search(const char element) const; + int SearchGreat(const char element) const; + int SearchLess(const char element) const; + int SearchGreatOrEqual(const char element) const; + int SearchLessOrEqual(const char element) const; + int SearchFirst(const char element) const; + int SearchLast(const char element) const; + int SearchLinear(const char element) const; + +protected: + virtual void QuickSort(int beg,int end,const int mode=0); + int QuickSearch(const char element) const; + int MemMove(const int dest,const int src,int count); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CArrayChar::CArrayChar(void) + { +//--- initialize protected data + m_data_max=ArraySize(m_data); + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CArrayChar::~CArrayChar(void) + { + if(m_data_max!=0) + Shutdown(); + } +//+------------------------------------------------------------------+ +//| Moving the memory within a single array | +//+------------------------------------------------------------------+ +int CArrayChar::MemMove(const int dest,const int src,int count) + { + int i; +//--- check parameters + if(dest<0 || src<0 || count<0) + return(-1); +//--- check count + if(src+count>m_data_total) + count=m_data_total-src; + if(count<0) + return(-1); +//--- no need to copy + if(dest==src || count==0) + return(dest); +//--- check data total + if(dest+count>m_data_total) + { + if(m_data_max=0;i--) + m_data[dest+i]=m_data[src+i]; + } +//--- successful + return(dest); + } +//+------------------------------------------------------------------+ +//| Request for more memory in an array. Checks if the requested | +//| number of free elements already exists; allocates additional | +//| memory with a given step | +//+------------------------------------------------------------------+ +bool CArrayChar::Reserve(const int size) + { + int new_size; +//--- check + if(size<=0) + return(false); +//--- resize array + if(Available()=size); + } +//+------------------------------------------------------------------+ +//| Resizing (with removal of elements on the right) | +//+------------------------------------------------------------------+ +bool CArrayChar::Resize(const int size) + { + int new_size; +//--- check + if(size<0) + return(false); +//--- resize array + new_size=m_step_resize*(1+size/m_step_resize); + if(m_data_max!=new_size) + { + if((m_data_max=ArrayResize(m_data,new_size))==-1) + { + m_data_max=ArraySize(m_data); + return(false); + } + } + if(m_data_total>size) + m_data_total=size; +//--- result + return(m_data_max==new_size); + } +//+------------------------------------------------------------------+ +//| Complete cleaning of the array with the release of memory | +//+------------------------------------------------------------------+ +bool CArrayChar::Shutdown(void) + { +//--- check + if(m_data_max==0) + return(true); +//--- clean + if(ArrayResize(m_data,0)==-1) + return(false); + m_data_total=0; + m_data_max=0; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Adding an element to the end of the array | +//+------------------------------------------------------------------+ +bool CArrayChar::Add(const char element) + { +//--- check/reserve elements of array + if(!Reserve(1)) + return(false); +//--- add + m_data[m_data_total++]=element; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Adding an element to the end of the array from another array | +//+------------------------------------------------------------------+ +bool CArrayChar::AddArray(const char &src[]) + { + int num=ArraySize(src); +//--- check/reserve elements of array + if(!Reserve(num)) + return(false); +//--- add + for(int i=0;i=m_data_total) + return(CHAR_MAX); +//--- result + return(m_data[index]); + } +//+------------------------------------------------------------------+ +//| Updating element in the specified position | +//+------------------------------------------------------------------+ +bool CArrayChar::Update(const int index,const char element) + { +//--- check + if(index<0 || index>=m_data_total) + return(false); +//--- update + m_data[index]=element; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Moving element from the specified position | +//| on the specified shift | +//+------------------------------------------------------------------+ +bool CArrayChar::Shift(const int index,const int shift) + { + char tmp_char; +//--- check + if(index<0 || index+shift<0 || index+shift>=m_data_total) + return(false); + if(shift==0) + return(true); +//--- move + tmp_char=m_data[index]; + if(shift>0) + { + if(MemMove(index,index+1,shift)<0) + return(false); + } + else + { + if(MemMove(index+shift+1,index+shift,-shift)<0) + return(false); + } + m_data[index+shift]=tmp_char; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Deleting element from the specified position | +//+------------------------------------------------------------------+ +bool CArrayChar::Delete(const int index) + { +//--- check + if(index<0 || index>=m_data_total) + return(false); +//--- delete + if(indexto || from>=m_data_total) + return(false); +//--- delete + if(to>=m_data_total-1) + to=m_data_total-1; + if(MemMove(from,to+1,m_data_total-to-1)<0) + return(false); + m_data_total-=to-from+1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Equality comparison of two arrays | +//+------------------------------------------------------------------+ +bool CArrayChar::CompareArray(const char &array[]) const + { +//--- compare + if(m_data_total!=ArraySize(array)) + return(false); + for(int i=0;i>1" is quick division by 2 + p_char=m_data[(beg+end)>>1]; + while(ip_char) + { + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + if(i<=j) + { + t_char=m_data[i]; + m_data[i++]=m_data[j]; + m_data[j]=t_char; + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + } + if(begelement) + Insert(element,pos); + else + Insert(element,pos+1); +//--- restore the sorting flag after Insert(...) + m_sort_mode=0; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Search of position of element in a array | +//+------------------------------------------------------------------+ +int CArrayChar::SearchLinear(const char element) const + { +//--- check + if(m_data_total==0) + return(-1); +//--- + for(int i=0;i=i) + { + //--- ">>1" is quick division by 2 + m=(j+i)>>1; + if(m<0 || m>=m_data_total) + break; + t_char=m_data[m]; + if(t_char==element) + break; + if(t_char>element) + j=m-1; + else + i=m+1; + } +//--- position + return(m); + } +//+------------------------------------------------------------------+ +//| Search of position of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayChar::Search(const char element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is greater than | +//| specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayChar::SearchGreat(const char element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + while(m_data[pos]<=element) + if(++pos==m_data_total) + return(-1); +//--- position + return(pos); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is less than | +//| specified in the sorted array | +//+------------------------------------------------------------------+ +int CArrayChar::SearchLess(const char element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + while(m_data[pos]>=element) + if(pos--==0) + return(-1); +//--- position + return(pos); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is greater than or | +//| equal to the specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayChar::SearchGreatOrEqual(const char element) const + { +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + for(int pos=QuickSearch(element);pos=element) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is less than or equal | +//| to the specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayChar::SearchLessOrEqual(const char element) const + { +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + for(int pos=QuickSearch(element);pos>=0;pos--) + if(m_data[pos]<=element) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Find position of first appearance of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayChar::SearchFirst(const char element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + { + while(m_data[pos]==element) + if(pos--==0) + break; + return(pos+1); + } +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Find position of last appearance of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayChar::SearchLast(const char element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + { + while(m_data[pos]==element) + if(++pos==m_data_total) + break; + return(pos-1); + } +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Writing array to file | +//+------------------------------------------------------------------+ +bool CArrayChar::Save(const int file_handle) + { + int i=0; +//--- check + if(!CArray::Save(file_handle)) + return(false); +//--- write array length + if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE) + return(false); +//--- write array + for(i=0;im_data_total) + count=m_data_total-src; + if(count<0) + return(-1); +//--- no need to copy + if(dest==src || count==0) + return(dest); +//--- check data total + if(dest+count>m_data_total) + { + if(m_data_max=0;i--) + m_data[dest+i]=m_data[src+i]; + } +//--- successful + return(dest); + } +//+------------------------------------------------------------------+ +//| Request for more memory in an array. Checks if the requested | +//| number of free elements already exists; allocates additional | +//| memory with a given step | +//+------------------------------------------------------------------+ +bool CArrayDouble::Reserve(const int size) + { + int new_size; +//--- check + if(size<=0) + return(false); +//--- resize array + if(Available()=size); + } +//+------------------------------------------------------------------+ +//| Resizing (with removal of elements on the right) | +//+------------------------------------------------------------------+ +bool CArrayDouble::Resize(const int size) + { + int new_size; +//--- check + if(size<0) + return(false); +//--- resize array + new_size=m_step_resize*(1+size/m_step_resize); + if(m_data_max!=new_size) + { + if((m_data_max=ArrayResize(m_data,new_size))==-1) + { + m_data_max=ArraySize(m_data); + return(false); + } + } + if(m_data_total>size) + m_data_total=size; +//--- result + return(m_data_max==new_size); + } +//+------------------------------------------------------------------+ +//| Complete cleaning of the array with the release of memory | +//+------------------------------------------------------------------+ +bool CArrayDouble::Shutdown(void) + { +//--- check + if(m_data_max==0) + return(true); +//--- clean + if(ArrayResize(m_data,0)==-1) + return(false); + m_data_total=0; + m_data_max=0; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Adding an element to the end of the array | +//+------------------------------------------------------------------+ +bool CArrayDouble::Add(const double element) + { +//--- check/reserve elements of array + if(!Reserve(1)) + return(false); +//--- add + m_data[m_data_total++]=element; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Adding an element to the end of the array from another array | +//+------------------------------------------------------------------+ +bool CArrayDouble::AddArray(const double &src[]) + { + int num=ArraySize(src); +//--- check/reserve elements of array + if(!Reserve(num)) + return(false); +//--- add + for(int i=0;i=m_data_total) + return(DBL_MAX); +//--- result + return(m_data[index]); + } +//+------------------------------------------------------------------+ +//| Updating element in the specified position | +//+------------------------------------------------------------------+ +bool CArrayDouble::Update(const int index,const double element) + { +//--- check + if(index<0 || index>=m_data_total) + return(false); +//--- update + m_data[index]=element; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Moving element from the specified position | +//| on the specified shift | +//+------------------------------------------------------------------+ +bool CArrayDouble::Shift(const int index,const int shift) + { + double tmp_double; +//--- check + if(index<0 || index+shift<0 || index+shift>=m_data_total) + return(false); + if(shift==0) + return(true); +//--- move + tmp_double=m_data[index]; + if(shift>0) + { + if(MemMove(index,index+1,shift)<0) + return(false); + } + else + { + if(MemMove(index+shift+1,index+shift,-shift)<0) + return(false); + } + m_data[index+shift]=tmp_double; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Deleting element from the specified position | +//+------------------------------------------------------------------+ +bool CArrayDouble::Delete(const int index) + { +//--- check + if(index<0 || index>=m_data_total) + return(false); +//--- delete + if(indexto || from>=m_data_total) + return(false); +//--- delete + if(to>=m_data_total-1) + to=m_data_total-1; + if(MemMove(from,to+1,m_data_total-to-1)<0) + return(false); + m_data_total-=to-from+1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Equality comparison of two arrays | +//+------------------------------------------------------------------+ +bool CArrayDouble::CompareArray(const double &array[]) const + { +//--- compare + if(m_data_total!=ArraySize(array)) + return(false); + for(int i=0;i>1" is quick division by 2 + p_double=m_data[(beg+end)>>1]; + while(ip_double) + { + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + if(i<=j) + { + t_double=m_data[i]; + m_data[i++]=m_data[j]; + m_data[j]=t_double; + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + } + if(begelement) + Insert(element,pos); + else + Insert(element,pos+1); +//--- restore the sorting flag after Insert(...) + m_sort_mode=0; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Search of position of element in a array | +//+------------------------------------------------------------------+ +int CArrayDouble::SearchLinear(const double element) const + { +//--- check + if(m_data_total==0) + return(-1); +//--- + for(int i=0;i=i) + { + //--- ">>1" is quick division by 2 + m=(j+i)>>1; + if(m<0 || m>=m_data_total) + break; + t_double=m_data[m]; + //--- compare with delta + if(MathAbs(t_double-element)<=m_delta) + break; + if(t_double>element) + j=m-1; + else + i=m+1; + } +//--- position + return(m); + } +//+------------------------------------------------------------------+ +//| Search of position of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayDouble::Search(const double element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); +//--- compare with delta + if(MathAbs(m_data[pos]-element)<=m_delta) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is greater than | +//| specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayDouble::SearchGreat(const double element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); +//--- compare with delta + while(m_data[pos]<=element+m_delta) + if(++pos==m_data_total) + return(-1); +//--- position + return(pos); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is less than | +//| specified in the sorted array | +//+------------------------------------------------------------------+ +int CArrayDouble::SearchLess(const double element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); +//--- compare with delta + while(m_data[pos]>=element-m_delta) + if(pos--==0) + return(-1); +//--- position + return(pos); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is greater than or | +//| equal to the specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayDouble::SearchGreatOrEqual(const double element) const + { +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + for(int pos=QuickSearch(element);pos=element) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is less than or equal | +//| to the specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayDouble::SearchLessOrEqual(const double element) const + { +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + for(int pos=QuickSearch(element);pos>=0;pos--) + if(m_data[pos]<=element) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Find position of first appearance of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayDouble::SearchFirst(const double element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + { + //--- compare with delta + while(MathAbs(m_data[pos]-element)<=m_delta) + if(pos--==0) + break; + return(pos+1); + } +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Find position of last appearance of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayDouble::SearchLast(const double element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + { + //--- compare with delta + while(MathAbs(m_data[pos]-element)<=m_delta) + if(++pos==m_data_total) + break; + return(pos-1); + } +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Writing array to file | +//+------------------------------------------------------------------+ +bool CArrayDouble::Save(const int file_handle) + { + int i=0; +//--- check + if(!CArray::Save(file_handle)) + return(false); +//--- write array length + if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE) + return(false); +//--- write array + for(i=0;im_data_total) + count=m_data_total-src; + if(count<0) + return(-1); +//--- no need to copy + if(dest==src || count==0) + return(dest); +//--- check data total + if(dest+count>m_data_total) + { + if(m_data_max=0;i--) + m_data[dest+i]=m_data[src+i]; + } +//--- successful + return(dest); + } +//+------------------------------------------------------------------+ +//| Request for more memory in an array. Checks if the requested | +//| number of free elements already exists; allocates additional | +//| memory with a given step | +//+------------------------------------------------------------------+ +bool CArrayFloat::Reserve(const int size) + { + int new_size; +//--- check + if(size<=0) + return(false); +//--- resize array + if(Available()=size); + } +//+------------------------------------------------------------------+ +//| Resizing (with removal of elements on the right) | +//+------------------------------------------------------------------+ +bool CArrayFloat::Resize(const int size) + { + int new_size; +//--- check + if(size<0) + return(false); +//--- resize array + new_size=m_step_resize*(1+size/m_step_resize); + if(m_data_max!=new_size) + { + if((m_data_max=ArrayResize(m_data,new_size))==-1) + { + m_data_max=ArraySize(m_data); + return(false); + } + } + if(m_data_total>size) + m_data_total=size; +//--- result + return(m_data_max==new_size); + } +//+------------------------------------------------------------------+ +//| Complete cleaning of the array with the release of memory | +//+------------------------------------------------------------------+ +bool CArrayFloat::Shutdown(void) + { +//--- check + if(m_data_max==0) + return(true); +//--- clean + if(ArrayResize(m_data,0)==-1) + return(false); + m_data_total=0; + m_data_max=0; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Adding an element to the end of the array | +//+------------------------------------------------------------------+ +bool CArrayFloat::Add(const float element) + { +//--- check/reserve elements of array + if(!Reserve(1)) + return(false); +//--- add + m_data[m_data_total++]=element; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Adding an element to the end of the array from another array | +//+------------------------------------------------------------------+ +bool CArrayFloat::AddArray(const float &src[]) + { + int num=ArraySize(src); +//--- check/reserve elements of array + if(!Reserve(num)) + return(false); +//--- add + for(int i=0;i=m_data_total) + return(FLT_MAX); +//--- result + return(m_data[index]); + } +//+------------------------------------------------------------------+ +//| Updating element in the specified position | +//+------------------------------------------------------------------+ +bool CArrayFloat::Update(const int index,const float element) + { +//--- check + if(index<0 || index>=m_data_total) + return(false); +//--- update + m_data[index]=element; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Moving element from the specified position | +//| on the specified shift | +//+------------------------------------------------------------------+ +bool CArrayFloat::Shift(const int index,const int shift) + { + float tmp_float; +//--- check + if(index<0 || index+shift<0 || index+shift>=m_data_total) + return(false); + if(shift==0) + return(true); +//--- move + tmp_float=m_data[index]; + if(shift>0) + { + if(MemMove(index,index+1,shift)<0) + return(false); + } + else + { + if(MemMove(index+shift+1,index+shift,-shift)<0) + return(false); + } + m_data[index+shift]=tmp_float; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Deleting element from the specified position | +//+------------------------------------------------------------------+ +bool CArrayFloat::Delete(const int index) + { +//--- check + if(index<0 || index>=m_data_total) + return(false); +//--- delete + if(indexto || from>=m_data_total) + return(false); +//--- delete + if(to>=m_data_total-1) + to=m_data_total-1; + if(MemMove(from,to+1,m_data_total-to-1)<0) + return(false); + m_data_total-=to-from+1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Equality comparison of two arrays | +//+------------------------------------------------------------------+ +bool CArrayFloat::CompareArray(const float &array[]) const + { +//--- compare + if(m_data_total!=ArraySize(array)) + return(false); + for(int i=0;i>1" is quick division by 2 + p_float=m_data[(beg+end)>>1]; + while(ip_float) + { + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + if(i<=j) + { + t_float=m_data[i]; + m_data[i++]=m_data[j]; + m_data[j]=t_float; + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + } + if(begelement) + Insert(element,pos); + else + Insert(element,pos+1); +//--- restore the sorting flag after Insert(...) + m_sort_mode=0; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Search of position of element in a array | +//+------------------------------------------------------------------+ +int CArrayFloat::SearchLinear(const float element) const + { +//--- check + if(m_data_total==0) + return(-1); +//--- + for(int i=0;i=i) + { + //--- ">>1" is quick division by 2 + m=(j+i)>>1; + if(m<0 || m>=m_data_total) + break; + t_float=m_data[m]; + //--- compare with delta + if(MathAbs(t_float-element)<=m_delta) + break; + if(t_float>element) + j=m-1; + else + i=m+1; + } +//--- position + return(m); + } +//+------------------------------------------------------------------+ +//| Search of position of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayFloat::Search(const float element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); +//--- compare with delta + if(MathAbs(m_data[pos]-element)<=m_delta) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is greater than | +//| specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayFloat::SearchGreat(const float element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); +//--- compare with delta + while(m_data[pos]<=element+m_delta) + if(++pos==m_data_total) + return(-1); +//--- position + return(pos); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is less than | +//| specified in the sorted array | +//+------------------------------------------------------------------+ +int CArrayFloat::SearchLess(const float element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); +//--- compare with delta + while(m_data[pos]>=element-m_delta) + if(pos--==0) + return(-1); +//--- position + return(pos); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is greater than or | +//| equal to the specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayFloat::SearchGreatOrEqual(const float element) const + { +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + for(int pos=QuickSearch(element);pos=element) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is less than or equal | +//| to the specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayFloat::SearchLessOrEqual(const float element) const + { +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + for(int pos=QuickSearch(element);pos>=0;pos--) + if(m_data[pos]<=element) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Find position of first appearance of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayFloat::SearchFirst(const float element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + { + //--- compare with delta + while(MathAbs(m_data[pos]-element)<=m_delta) + if(pos--==0) + break; + return(pos+1); + } +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Find position of last appearance of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayFloat::SearchLast(const float element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + { + //--- compare with delta + while(MathAbs(m_data[pos]-element)<=m_delta) + if(++pos==m_data_total) + break; + return(pos-1); + } +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Writing array to file | +//+------------------------------------------------------------------+ +bool CArrayFloat::Save(const int file_handle) + { + int i=0; +//--- check + if(!CArray::Save(file_handle)) + return(false); +//--- write array length + if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE) + return(false); +//--- write array + for(i=0;im_data_total) + count=m_data_total-src; + if(count<0) + return(-1); +//--- no need to copy + if(dest==src || count==0) + return(dest); +//--- check data total + if(dest+count>m_data_total) + { + if(m_data_max=0;i--) + m_data[dest+i]=m_data[src+i]; + } +//--- successful + return(dest); + } +//+------------------------------------------------------------------+ +//| Request for more memory in an array. Checks if the requested | +//| number of free elements already exists; allocates additional | +//| memory with a given step | +//+------------------------------------------------------------------+ +bool CArrayInt::Reserve(const int size) + { + int new_size; +//--- check + if(size<=0) + return(false); +//--- resize array + if(Available()=size); + } +//+------------------------------------------------------------------+ +//| Resizing (with removal of elements on the right) | +//+------------------------------------------------------------------+ +bool CArrayInt::Resize(const int size) + { + int new_size; +//--- check + if(size<0) + return(false); +//--- resize array + new_size=m_step_resize*(1+size/m_step_resize); + if(m_data_max!=new_size) + { + if((m_data_max=ArrayResize(m_data,new_size))==-1) + { + m_data_max=ArraySize(m_data); + return(false); + } + } + if(m_data_total>size) + m_data_total=size; +//--- result + return(m_data_max==new_size); + } +//+------------------------------------------------------------------+ +//| Complete cleaning of the array with the release of memory | +//+------------------------------------------------------------------+ +bool CArrayInt::Shutdown(void) + { +//--- check + if(m_data_max==0) + return(true); +//--- clean + if(ArrayResize(m_data,0)==-1) + return(false); + m_data_total=0; + m_data_max=0; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Adding an element to the end of the array | +//+------------------------------------------------------------------+ +bool CArrayInt::Add(const int element) + { +//--- check/reserve elements of array + if(!Reserve(1)) + return(false); +//--- add + m_data[m_data_total++]=element; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Adding an element to the end of the array from another array | +//+------------------------------------------------------------------+ +bool CArrayInt::AddArray(const int &src[]) + { + int num=ArraySize(src); +//--- check/reserve elements of array + if(!Reserve(num)) + return(false); +//--- add + for(int i=0;i=m_data_total) + return(INT_MAX); +//--- result + return(m_data[index]); + } +//+------------------------------------------------------------------+ +//| Updating element in the specified position | +//+------------------------------------------------------------------+ +bool CArrayInt::Update(const int index,const int element) + { +//--- check + if(index<0 || index>=m_data_total) + return(false); +//--- update + m_data[index]=element; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Moving element from the specified position | +//| on the specified shift | +//+------------------------------------------------------------------+ +bool CArrayInt::Shift(const int index,const int shift) + { + int tmp_int; +//--- check + if(index<0 || index+shift<0 || index+shift>=m_data_total) + return(false); + if(shift==0) + return(true); +//--- move + tmp_int=m_data[index]; + if(shift>0) + { + if(MemMove(index,index+1,shift)<0) + return(false); + } + else + { + if(MemMove(index+shift+1,index+shift,-shift)<0) + return(false); + } + m_data[index+shift]=tmp_int; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Deleting element from the specified position | +//+------------------------------------------------------------------+ +bool CArrayInt::Delete(const int index) + { +//--- check + if(index<0 || index>=m_data_total) + return(false); +//--- delete + if(indexto || from>=m_data_total) + return(false); +//--- delete + if(to>=m_data_total-1) + to=m_data_total-1; + if(MemMove(from,to+1,m_data_total-to-1)<0) + return(false); + m_data_total-=to-from+1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Equality comparison of two arrays | +//+------------------------------------------------------------------+ +bool CArrayInt::CompareArray(const int &array[]) const + { +//--- compare + if(m_data_total!=ArraySize(array)) + return(false); + for(int i=0;i>1" is quick division by 2 + p_int=m_data[(beg+end)>>1]; + while(ip_int) + { + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + if(i<=j) + { + t_int=m_data[i]; + m_data[i++]=m_data[j]; + m_data[j]=t_int; + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + } + if(begelement) + Insert(element,pos); + else + Insert(element,pos+1); +//--- restore the sorting flag after Insert(...) + m_sort_mode=0; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Search of position of element in a array | +//+------------------------------------------------------------------+ +int CArrayInt::SearchLinear(const int element) const + { +//--- check + if(m_data_total==0) + return(-1); +//--- + for(int i=0;i=i) + { + //--- ">>1" is quick division by 2 + m=(j+i)>>1; + if(m<0 || m>=m_data_total) + break; + t_int=m_data[m]; + if(t_int==element) + break; + if(t_int>element) + j=m-1; + else + i=m+1; + } +//--- position + return(m); + } +//+------------------------------------------------------------------+ +//| Search of position of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayInt::Search(const int element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is greater than | +//| specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayInt::SearchGreat(const int element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + while(m_data[pos]<=element) + if(++pos==m_data_total) + return(-1); +//--- position + return(pos); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is less than | +//| specified in the sorted array | +//+------------------------------------------------------------------+ +int CArrayInt::SearchLess(const int element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + while(m_data[pos]>=element) + if(pos--==0) + return(-1); +//--- position + return(pos); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is greater than or | +//| equal to the specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayInt::SearchGreatOrEqual(const int element) const + { +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + for(int pos=QuickSearch(element);pos=element) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is less than or equal | +//| to the specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayInt::SearchLessOrEqual(const int element) const + { +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + for(int pos=QuickSearch(element);pos>=0;pos--) + if(m_data[pos]<=element) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Find position of first appearance of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayInt::SearchFirst(const int element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + { + while(m_data[pos]==element) + if(pos--==0) + break; + return(pos+1); + } +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Find position of last appearance of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayInt::SearchLast(const int element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + { + while(m_data[pos]==element) + if(++pos==m_data_total) + break; + return(pos-1); + } +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Writing array to file | +//+------------------------------------------------------------------+ +bool CArrayInt::Save(const int file_handle) + { + int i=0; +//--- check + if(!CArray::Save(file_handle)) + return(false); +//--- write array length + if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE) + return(false); +//--- write array + for(i=0;im_data_total) + count=m_data_total-src; + if(count<0) + return(-1); +//--- no need to copy + if(dest==src || count==0) + return(dest); +//--- check data total + if(dest+count>m_data_total) + { + if(m_data_max=0;i--) + m_data[dest+i]=m_data[src+i]; + } +//--- successful + return(dest); + } +//+------------------------------------------------------------------+ +//| Request for more memory in an array. Checks if the requested | +//| number of free elements already exists; allocates additional | +//| memory with a given step | +//+------------------------------------------------------------------+ +bool CArrayLong::Reserve(const int size) + { + int new_size; +//--- check + if(size<=0) + return(false); +//--- resize array + if(Available()=size); + } +//+------------------------------------------------------------------+ +//| Resizing (with removal of elements on the right) | +//+------------------------------------------------------------------+ +bool CArrayLong::Resize(const int size) + { + int new_size; +//--- check + if(size<0) + return(false); +//--- resize array + new_size=m_step_resize*(1+size/m_step_resize); + if(m_data_max!=new_size) + { + if((m_data_max=ArrayResize(m_data,new_size))==-1) + { + m_data_max=ArraySize(m_data); + return(false); + } + } + if(m_data_total>size) + m_data_total=size; +//--- result + return(m_data_max==new_size); + } +//+------------------------------------------------------------------+ +//| Complete cleaning of the array with the release of memory | +//+------------------------------------------------------------------+ +bool CArrayLong::Shutdown(void) + { +//--- check + if(m_data_max==0) + return(true); +//--- clean + if(ArrayResize(m_data,0)==-1) + return(false); + m_data_total=0; + m_data_max=0; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Adding an element to the end of the array | +//+------------------------------------------------------------------+ +bool CArrayLong::Add(const long element) + { +//--- check/reserve elements of array + if(!Reserve(1)) + return(false); +//--- add + m_data[m_data_total++]=element; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Adding an element to the end of the array from another array | +//+------------------------------------------------------------------+ +bool CArrayLong::AddArray(const long &src[]) + { + int num=ArraySize(src); +//--- check/reserve elements of array + if(!Reserve(num)) + return(false); +//--- add + for(int i=0;i=m_data_total) + return(LONG_MAX); +//--- result + return(m_data[index]); + } +//+------------------------------------------------------------------+ +//| Updating element in the specified position | +//+------------------------------------------------------------------+ +bool CArrayLong::Update(const int index,const long element) + { +//--- check + if(index<0 || index>=m_data_total) + return(false); +//--- update + m_data[index]=element; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Moving element from the specified position | +//| on the specified shift | +//+------------------------------------------------------------------+ +bool CArrayLong::Shift(const int index,const int shift) + { + long tmp_long; +//--- check + if(index<0 || index+shift<0 || index+shift>=m_data_total) + return(false); + if(shift==0) + return(true); +//--- move + tmp_long=m_data[index]; + if(shift>0) + { + if(MemMove(index,index+1,shift)<0) + return(false); + } + else + { + if(MemMove(index+shift+1,index+shift,-shift)<0) + return(false); + } + m_data[index+shift]=tmp_long; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Deleting element from the specified position | +//+------------------------------------------------------------------+ +bool CArrayLong::Delete(const int index) + { +//--- check + if(index<0 || index>=m_data_total) + return(false); +//--- delete + if(indexto || from>=m_data_total) + return(false); +//--- delete + if(to>=m_data_total-1) + to=m_data_total-1; + if(MemMove(from,to+1,m_data_total-to-1)<0) + return(false); + m_data_total-=to-from+1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Equality comparison of two arrays | +//+------------------------------------------------------------------+ +bool CArrayLong::CompareArray(const long &array[]) const + { +//--- compare + if(m_data_total!=ArraySize(array)) + return(false); + for(int i=0;i>1" is quick division by 2 + p_long=m_data[(beg+end)>>1]; + while(ip_long) + { + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + if(i<=j) + { + t_long=m_data[i]; + m_data[i++]=m_data[j]; + m_data[j]=t_long; + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + } + if(begelement) + Insert(element,pos); + else + Insert(element,pos+1); +//--- restore the sorting flag after Insert(...) + m_sort_mode=0; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Search of position of element in a array | +//+------------------------------------------------------------------+ +int CArrayLong::SearchLinear(const long element) const + { +//--- check + if(m_data_total==0) + return(-1); +//--- + for(int i=0;i=i) + { + //--- ">>1" is quick division by 2 + m=(j+i)>>1; + if(m<0 || m>=m_data_total) + break; + t_long=m_data[m]; + if(t_long==element) + break; + if(t_long>element) + j=m-1; + else + i=m+1; + } +//--- position + return(m); + } +//+------------------------------------------------------------------+ +//| Search of position of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayLong::Search(const long element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is greater than | +//| specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayLong::SearchGreat(const long element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + while(m_data[pos]<=element) + if(++pos==m_data_total) + return(-1); +//--- position + return(pos); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is less than | +//| specified in the sorted array | +//+------------------------------------------------------------------+ +int CArrayLong::SearchLess(const long element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + while(m_data[pos]>=element) + if(pos--==0) + return(-1); +//--- position + return(pos); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is greater than or | +//| equal to the specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayLong::SearchGreatOrEqual(const long element) const + { +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + for(int pos=QuickSearch(element);pos=element) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is less than or equal | +//| to the specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayLong::SearchLessOrEqual(const long element) const + { +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + for(int pos=QuickSearch(element);pos>=0;pos--) + if(m_data[pos]<=element) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Find position of first appearance of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayLong::SearchFirst(const long element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + { + while(m_data[pos]==element) + if(pos--==0) + break; + return(pos+1); + } +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Find position of last appearance of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayLong::SearchLast(const long element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + { + while(m_data[pos]==element) + if(++pos==m_data_total) + break; + return(pos-1); + } +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Writing array to file | +//+------------------------------------------------------------------+ +bool CArrayLong::Save(const int file_handle) + { + int i=0; +//--- check + if(!CArray::Save(file_handle)) + return(false); +//--- write array length + if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE) + return(false); +//--- write array + for(i=0;im_data_total) + count=m_data_total-src; + if(count<0) + return(-1); +//--- no need to copy + if(dest==src || count==0) + return(dest); +//--- check data total + if(dest+count>m_data_total) + { + if(m_data_max=0;i--) + { + //--- "physical" removal of the object (if necessary and possible) + if(m_free_mode && CheckPointer(m_data[dest+i])==POINTER_DYNAMIC) + delete m_data[dest+i]; + //--- + m_data[dest+i]=m_data[src+i]; + m_data[src+i]=NULL; + } + } +//--- successful + return(dest); + } +//+------------------------------------------------------------------+ +//| Request for more memory in an array. Checks if the requested | +//| number of free elements already exists; allocates additional | +//| memory with a given step | +//+------------------------------------------------------------------+ +bool CArrayObj::Reserve(const int size) + { + int new_size; +//--- check + if(size<=0) + return(false); +//--- resize array + if(Available()=size); + } +//+------------------------------------------------------------------+ +//| Resizing (with removal of elements on the right) | +//+------------------------------------------------------------------+ +bool CArrayObj::Resize(const int size) + { + int new_size; +//--- check + if(size<0) + return(false); +//--- resize array + new_size=m_step_resize*(1+size/m_step_resize); + if(m_data_total>size) + { + //--- "physical" removal of the object (if necessary and possible) + if(m_free_mode) + for(int i=size;i=m_data_total) + return(NULL); +//--- result + return(m_data[index]); + } +//+------------------------------------------------------------------+ +//| Updating element in the specified position | +//+------------------------------------------------------------------+ +bool CArrayObj::Update(const int index,CObject *element) + { +//--- check + if(index<0 || !CheckPointer(element) || index>=m_data_total) + return(false); +//--- "physical" removal of the object (if necessary and possible) + if(m_free_mode && CheckPointer(m_data[index])==POINTER_DYNAMIC) + delete m_data[index]; +//--- update + m_data[index]=element; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Moving element from the specified position | +//| on the specified shift | +//+------------------------------------------------------------------+ +bool CArrayObj::Shift(const int index,const int shift) + { + CObject *tmp_node; +//--- check + if(index<0 || index+shift<0 || index+shift>=m_data_total) + return(false); + if(shift==0) + return(true); +//--- move + tmp_node=m_data[index]; + m_data[index]=NULL; + if(shift>0) + { + if(MemMove(index,index+1,shift)<0) + return(false); + } + else + { + if(MemMove(index+shift+1,index+shift,-shift)<0) + return(false); + } + m_data[index+shift]=tmp_node; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Deleting element from the specified position | +//+------------------------------------------------------------------+ +bool CArrayObj::Delete(const int index) + { +//--- check + if(index>=m_data_total) + return(false); +//--- delete + if(index=0 && MemMove(index,index+1,m_data_total-index-1)<0) + return(false); + } + else + if(m_free_mode && CheckPointer(m_data[index])==POINTER_DYNAMIC) + delete m_data[index]; + m_data_total--; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Detach element from the specified position | +//+------------------------------------------------------------------+ +CObject *CArrayObj::Detach(const int index) + { + CObject *result; +//--- check + if(index>=m_data_total) + return(NULL); +//--- detach + result=m_data[index]; +//--- reset the array element, so as not remove the method MemMove + m_data[index]=NULL; + if(indexto || from>=m_data_total) + return(false); +//--- delete + if(to>=m_data_total-1) + to=m_data_total-1; + if(MemMove(from,to+1,m_data_total-to-1)<0) + return(false); + for(int i=to-from+1;i>0;i--,m_data_total--) + if(m_free_mode && CheckPointer(m_data[m_data_total-1])==POINTER_DYNAMIC) + delete m_data[m_data_total-1]; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Clearing of array without the release of memory | +//+------------------------------------------------------------------+ +void CArrayObj::Clear(void) + { +//--- "physical" removal of the object (if necessary and possible) + if(m_free_mode) + { + for(int i=0;i>1" is quick division by 2 + p_node=m_data[(beg+end)>>1]; + while(i0) + { + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + if(i<=j) + { + t_node=m_data[i]; + m_data[i++]=m_data[j]; + m_data[j]=t_node; + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + } + if(beg0) + Insert(element,pos); + else + Insert(element,pos+1); +//--- restore the sorting flag after Insert(...) + m_sort_mode=mode; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Quick search of position of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayObj::QuickSearch(const CObject *element) const + { + int i,j,m=-1; + CObject *t_node; +//--- search + i=0; + j=m_data_total-1; + while(j>=i) + { + //--- ">>1" is quick division by 2 + m=(j+i)>>1; + if(m<0 || m==m_data_total-1) + break; + t_node=m_data[m]; + if(t_node.Compare(element,m_sort_mode)==0) + break; + if(t_node.Compare(element,m_sort_mode)>0) + j=m-1; + else + i=m+1; + } +//--- position + return(m); + } +//+------------------------------------------------------------------+ +//| Search of position of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayObj::Search(const CObject *element) const + { + int pos; +//--- check + if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos].Compare(element,m_sort_mode)==0) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is greater than | +//| specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayObj::SearchGreat(const CObject *element) const + { + int pos; +//--- check + if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1) + return(-1); +//--- search + pos=QuickSearch(element); + while(m_data[pos].Compare(element,m_sort_mode)<=0) + if(++pos==m_data_total) + return(-1); +//--- position + return(pos); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is less than | +//| specified in the sorted array | +//+------------------------------------------------------------------+ +int CArrayObj::SearchLess(const CObject *element) const + { + int pos; +//--- check + if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1) + return(-1); +//--- search + pos=QuickSearch(element); + while(m_data[pos].Compare(element,m_sort_mode)>=0) + if(pos--==0) + return(-1); +//--- position + return(pos); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is greater than or | +//| equal to the specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayObj::SearchGreatOrEqual(const CObject *element) const + { +//--- check + if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1) + return(-1); +//--- search + for(int pos=QuickSearch(element);pos=0) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is less than or equal | +//| to the specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayObj::SearchLessOrEqual(const CObject *element) const + { +//--- check + if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1) + return(-1); +//--- search + for(int pos=QuickSearch(element);pos>=0;pos--) + if(m_data[pos].Compare(element,m_sort_mode)<=0) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Find position of first appearance of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayObj::SearchFirst(const CObject *element) const + { + int pos; +//--- check + if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos].Compare(element,m_sort_mode)==0) + { + while(m_data[pos].Compare(element,m_sort_mode)==0) + if(pos--==0) + break; + return(pos+1); + } +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Find position of last appearance of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayObj::SearchLast(const CObject *element) const + { + int pos; +//--- check + if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos].Compare(element,m_sort_mode)==0) + { + while(m_data[pos].Compare(element,m_sort_mode)==0) + if(++pos==m_data_total) + break; + return(pos-1); + } +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Writing array to file | +//+------------------------------------------------------------------+ +bool CArrayObj::Save(const int file_handle) + { + int i=0; +//--- check + if(!CArray::Save(file_handle)) + return(false); +//--- write array length + if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE) + return(false); +//--- write array + for(i=0;im_data_total) + count=m_data_total-src; + if(count<0) + return(-1); +//--- no need to copy + if(dest==src || count==0) + return(dest); +//--- check data total + if(dest+count>m_data_total) + { + if(m_data_max=0;i--) + m_data[dest+i]=m_data[src+i]; + } +//--- successful + return(dest); + } +//+------------------------------------------------------------------+ +//| Request for more memory in an array. Checks if the requested | +//| number of free elements already exists; allocates additional | +//| memory with a given step | +//+------------------------------------------------------------------+ +bool CArrayShort::Reserve(const int size) + { + int new_size; +//--- check + if(size<=0) + return(false); +//--- resize array + if(Available()=size); + } +//+------------------------------------------------------------------+ +//| Resizing (with removal of elements on the right) | +//+------------------------------------------------------------------+ +bool CArrayShort::Resize(const int size) + { + int new_size; +//--- check + if(size<0) + return(false); +//--- resize array + new_size=m_step_resize*(1+size/m_step_resize); + if(m_data_max!=new_size) + { + if((m_data_max=ArrayResize(m_data,new_size))==-1) + { + m_data_max=ArraySize(m_data); + return(false); + } + } + if(m_data_total>size) + m_data_total=size; +//--- result + return(m_data_max==new_size); + } +//+------------------------------------------------------------------+ +//| Complete cleaning of the array with the release of memory | +//+------------------------------------------------------------------+ +bool CArrayShort::Shutdown(void) + { +//--- check + if(m_data_max==0) + return(true); +//--- clean + if(ArrayResize(m_data,0)==-1) + return(false); + m_data_total=0; + m_data_max=0; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Adding an element to the end of the array | +//+------------------------------------------------------------------+ +bool CArrayShort::Add(const short element) + { +//--- check/reserve elements of array + if(!Reserve(1)) + return(false); +//--- add + m_data[m_data_total++]=element; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Adding an element to the end of the array from another array | +//+------------------------------------------------------------------+ +bool CArrayShort::AddArray(const short &src[]) + { + int num=ArraySize(src); +//--- check/reserve elements of array + if(!Reserve(num)) + return(false); +//--- add + for(int i=0;i=m_data_total) + return(SHORT_MAX); +//--- result + return(m_data[index]); + } +//+------------------------------------------------------------------+ +//| Updating element in the specified position | +//+------------------------------------------------------------------+ +bool CArrayShort::Update(const int index,const short element) + { +//--- check + if(index<0 || index>=m_data_total) + return(false); +//--- update + m_data[index]=element; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Moving element from the specified position | +//| on the specified shift | +//+------------------------------------------------------------------+ +bool CArrayShort::Shift(const int index,const int shift) + { + short tmp_short; +//--- check + if(index<0 || index+shift<0 || index+shift>=m_data_total) + return(false); + if(shift==0) + return(true); +//--- move + tmp_short=m_data[index]; + if(shift>0) + { + if(MemMove(index,index+1,shift)<0) + return(false); + } + else + { + if(MemMove(index+shift+1,index+shift,-shift)<0) + return(false); + } + m_data[index+shift]=tmp_short; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Deleting element from the specified position | +//+------------------------------------------------------------------+ +bool CArrayShort::Delete(const int index) + { +//--- check + if(index<0 || index>=m_data_total) + return(false); +//--- delete + if(indexto || from>=m_data_total) + return(false); +//--- delete + if(to>=m_data_total-1) + to=m_data_total-1; + if(MemMove(from,to+1,m_data_total-to-1)<0) + return(false); + m_data_total-=to-from+1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Equality comparison of two arrays | +//+------------------------------------------------------------------+ +bool CArrayShort::CompareArray(const short &array[]) const + { +//--- compare + if(m_data_total!=ArraySize(array)) + return(false); + for(int i=0;i>1" is quick division by 2 + p_short=m_data[(beg+end)>>1]; + while(ip_short) + { + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + if(i<=j) + { + t_short=m_data[i]; + m_data[i++]=m_data[j]; + m_data[j]=t_short; + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + } + if(begelement) + Insert(element,pos); + else + Insert(element,pos+1); +//--- restore the sorting flag after Insert(...) + m_sort_mode=0; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Search of position of element in a array | +//+------------------------------------------------------------------+ +int CArrayShort::SearchLinear(const short element) const + { +//--- check + if(m_data_total==0) + return(-1); +//--- + for(int i=0;i=i) + { + //--- ">>1" is quick division by 2 + m=(j+i)>>1; + if(m<0 || m>=m_data_total) + break; + t_short=m_data[m]; + if(t_short==element) + break; + if(t_short>element) + j=m-1; + else + i=m+1; + } +//--- position + return(m); + } +//+------------------------------------------------------------------+ +//| Search of position of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayShort::Search(const short element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is greater than | +//| specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayShort::SearchGreat(const short element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + while(m_data[pos]<=element) + if(++pos==m_data_total) + return(-1); +//--- position + return(pos); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is less than | +//| specified in the sorted array | +//+------------------------------------------------------------------+ +int CArrayShort::SearchLess(const short element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + while(m_data[pos]>=element) + if(pos--==0) + return(-1); +//--- position + return(pos); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is greater than or | +//| equal to the specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayShort::SearchGreatOrEqual(const short element) const + { +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + for(int pos=QuickSearch(element);pos=element) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is less than or equal | +//| to the specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayShort::SearchLessOrEqual(const short element) const + { +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + for(int pos=QuickSearch(element);pos>=0;pos--) + if(m_data[pos]<=element) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Find position of first appearance of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayShort::SearchFirst(const short element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + { + while(m_data[pos]==element) + if(pos--==0) + break; + return(pos+1); + } +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Find position of last appearance of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayShort::SearchLast(const short element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + { + while(m_data[pos]==element) + if(++pos==m_data_total) + break; + return(pos-1); + } +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Writing array to file | +//+------------------------------------------------------------------+ +bool CArrayShort::Save(const int file_handle) + { + int i=0; +//--- check + if(!CArray::Save(file_handle)) + return(false); +//--- write array length + if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE) + return(false); +//--- write array + for(i=0;im_data_total) + count=m_data_total-src; + if(count<0) + return(-1); +//--- no need to copy + if(dest==src || count==0) + return(dest); +//--- check data total + if(dest+count>m_data_total) + { + if(m_data_max=0;i--) + m_data[dest+i]=m_data[src+i]; + } +//--- successful + return(dest); + } +//+------------------------------------------------------------------+ +//| Request for more memory in an array. Checks if the requested | +//| number of free elements already exists; allocates additional | +//| memory with a given step | +//+------------------------------------------------------------------+ +bool CArrayString::Reserve(const int size) + { + int new_size; +//--- check + if(size<=0) + return(false); +//--- resize array + if(Available()=size); + } +//+------------------------------------------------------------------+ +//| Resizing (with removal of elements on the right) | +//+------------------------------------------------------------------+ +bool CArrayString::Resize(const int size) + { + int new_size; +//--- check + if(size<0) + return(false); +//--- resize array + new_size=m_step_resize*(1+size/m_step_resize); + if(m_data_max!=new_size) + { + if((m_data_max=ArrayResize(m_data,new_size))==-1) + { + m_data_max=ArraySize(m_data); + return(false); + } + } + if(m_data_total>size) + m_data_total=size; +//--- result + return(m_data_max==new_size); + } +//+------------------------------------------------------------------+ +//| Complete cleaning of the array with the release of memory | +//+------------------------------------------------------------------+ +bool CArrayString::Shutdown(void) + { +//--- check + if(m_data_max==0) + return(true); +//--- clean + if(ArrayResize(m_data,0)==-1) + return(false); + m_data_total=0; + m_data_max=0; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Adding an element to the end of the array | +//+------------------------------------------------------------------+ +bool CArrayString::Add(const string element) + { +//--- check/reserve elements of array + if(!Reserve(1)) + return(false); +//--- add + m_data[m_data_total++]=element; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Adding an element to the end of the array from another array | +//+------------------------------------------------------------------+ +bool CArrayString::AddArray(const string &src[]) + { + int num=ArraySize(src); +//--- check/reserve elements of array + if(!Reserve(num)) + return(false); +//--- add + for(int i=0;i=m_data_total) + return(""); +//--- result + return(m_data[index]); + } +//+------------------------------------------------------------------+ +//| Updating element in the specified position | +//+------------------------------------------------------------------+ +bool CArrayString::Update(const int index,const string element) + { +//--- check + if(index<0 || index>=m_data_total) + return(false); +//--- update + m_data[index]=element; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Moving element from the specified position | +//| on the specified shift | +//+------------------------------------------------------------------+ +bool CArrayString::Shift(const int index,const int shift) + { + string tmp_string; +//--- check + if(index<0 || index+shift<0 || index+shift>=m_data_total) + return(false); + if(shift==0) + return(true); +//--- move + tmp_string=m_data[index]; + if(shift>0) + { + if(MemMove(index,index+1,shift)<0) + return(false); + } + else + { + if(MemMove(index+shift+1,index+shift,-shift)<0) + return(false); + } + m_data[index+shift]=tmp_string; + m_sort_mode=-1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Deleting element from the specified position | +//+------------------------------------------------------------------+ +bool CArrayString::Delete(const int index) + { +//--- check + if(index<0 || index>=m_data_total) + return(false); +//--- delete + if(indexto || from>=m_data_total) + return(false); +//--- delete + if(to>=m_data_total-1) + to=m_data_total-1; + if(MemMove(from,to+1,m_data_total-to-1)<0) + return(false); + m_data_total-=to-from+1; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Equality comparison of two arrays | +//+------------------------------------------------------------------+ +bool CArrayString::CompareArray(const string &array[]) const + { +//--- compare + if(m_data_total!=ArraySize(array)) + return(false); + for(int i=0;i>1" is quick division by 2 + p_string=m_data[(beg+end)>>1]; + while(ip_string) + { + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + if(i<=j) + { + t_string=m_data[i]; + m_data[i++]=m_data[j]; + m_data[j]=t_string; + //--- control the output of the array bounds + if(j==0) + break; + j--; + } + } + if(begelement) + Insert(element,pos); + else + Insert(element,pos+1); +//--- restore the sorting flag after Insert(...) + m_sort_mode=0; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Search of position of element in a array | +//+------------------------------------------------------------------+ +int CArrayString::SearchLinear(const string element) const + { +//--- check + if(m_data_total==0) + return(-1); +//--- + for(int i=0;i=i) + { + //--- ">>1" is quick division by 2 + m=(j+i)>>1; + if(m<0 || m>=m_data_total) + break; + t_string=m_data[m]; + if(t_string==element) + break; + if(t_string>element) + j=m-1; + else + i=m+1; + } +//--- position + return(m); + } +//+------------------------------------------------------------------+ +//| Search of position of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayString::Search(const string element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is greater than | +//| specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayString::SearchGreat(const string element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + while(m_data[pos]<=element) + if(++pos==m_data_total) + return(-1); +//--- position + return(pos); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is less than | +//| specified in the sorted array | +//+------------------------------------------------------------------+ +int CArrayString::SearchLess(const string element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + while(m_data[pos]>=element) + if(pos--==0) + return(-1); +//--- position + return(pos); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is greater than or | +//| equal to the specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayString::SearchGreatOrEqual(const string element) const + { +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + for(int pos=QuickSearch(element);pos=element) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Search position of the first element which is less than or equal | +//| to the specified in a sorted array | +//+------------------------------------------------------------------+ +int CArrayString::SearchLessOrEqual(const string element) const + { +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + for(int pos=QuickSearch(element);pos>=0;pos--) + if(m_data[pos]<=element) + return(pos); +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Find position of first appearance of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayString::SearchFirst(const string element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + { + while(m_data[pos]==element) + if(pos--==0) + break; + return(pos+1); + } +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Find position of last appearance of element in a sorted array | +//+------------------------------------------------------------------+ +int CArrayString::SearchLast(const string element) const + { + int pos; +//--- check + if(m_data_total==0 || !IsSorted()) + return(-1); +//--- search + pos=QuickSearch(element); + if(m_data[pos]==element) + { + while(m_data[pos]==element) + if(++pos==m_data_total) + break; + return(pos-1); + } +//--- not found + return(-1); + } +//+------------------------------------------------------------------+ +//| Writing array to file | +//+------------------------------------------------------------------+ +bool CArrayString::Save(const int file_handle) + { + int i=0,len; +//--- check + if(!CArray::Save(file_handle)) + return(false); +//--- write array length + if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE) + return(false); +//--- write array + for(i=0;i +//+------------------------------------------------------------------+ +//| Class CList. | +//| Purpose: Provides the possibility of working with the list of | +//| CObject instances and its dervivatives | +//| Derives from class CObject. | +//+------------------------------------------------------------------+ +class CList : public CObject + { +protected: + CObject *m_first_node; // pointer to the first element of the list + CObject *m_last_node; // pointer to the last element of the list + CObject *m_curr_node; // pointer to the current element of the list + int m_curr_idx; // index of the current list item + int m_data_total; // number of elements + bool m_free_mode; // flag of the necessity of "physical" deletion of object + bool m_data_sort; // flag if the list is sorted or not + int m_sort_mode; // mode of sorting of array + +public: + CList(void); + ~CList(void); + //--- methods of access to protected data + bool FreeMode(void) const { return(m_free_mode); } + void FreeMode(bool mode) { m_free_mode=mode; } + int Total(void) const { return(m_data_total); } + bool IsSorted(void) const { return(m_data_sort); } + int SortMode(void) const { return(m_sort_mode); } + //--- method of identifying the object + virtual int Type(void) const { return(0x7779); } + //--- methods for working with files + virtual bool Save(const int file_handle); + virtual bool Load(const int file_handle); + //--- method of creating an element of the list + virtual CObject *CreateElement(void) { return(NULL); } + //--- methods of filling the list + int Add(CObject *new_node); + int Insert(CObject *new_node,int index); + //--- methods for navigating + int IndexOf(CObject *node); + CObject *GetNodeAtIndex(int index); + CObject *GetFirstNode(void); + CObject *GetPrevNode(void); + CObject *GetCurrentNode(void); + CObject *GetNextNode(void); + CObject *GetLastNode(void); + //--- methods for deleting + CObject *DetachCurrent(void); + bool DeleteCurrent(void); + bool Delete(int index); + void Clear(void); + //--- method for comparing lists + bool CompareList(CList *List); + //--- methods for changing + void Sort(int mode); + bool MoveToIndex(int index); + bool Exchange(CObject *node1,CObject *node2); + //--- method for searching + CObject *Search(CObject *element); +protected: + void QuickSort(int beg,int end,int mode); + CObject *QuickSearch(CObject *element); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CList::CList(void) : m_first_node(NULL), + m_last_node(NULL), + m_curr_node(NULL), + m_curr_idx(-1), + m_data_total(0), + m_free_mode(true), + m_data_sort(false), + m_sort_mode(0) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CList::~CList(void) + { + Clear(); + } +//+------------------------------------------------------------------+ +//| Method QuickSort | +//+------------------------------------------------------------------+ +void CList::QuickSort(int beg,int end,int mode) + { + int i,j,k; + CObject *i_ptr,*j_ptr,*k_ptr; +//--- + i_ptr=GetNodeAtIndex(i=beg); + j_ptr=GetNodeAtIndex(j=end); + while(i>1" is quick division by 2 + k_ptr=GetNodeAtIndex(k=(beg+end)>>1); + while(i0) + { + //--- control the output of the array bounds + if(j==0) + break; + j--; + j_ptr=j_ptr.Prev(); + } + if(i<=j) + { + Exchange(i_ptr,j_ptr); + i++; + i_ptr=GetNodeAtIndex(i); + //--- control the output of the array bounds + if(j==0) + break; + else + { + j--; + j_ptr=GetNodeAtIndex(j); + } + } + } + if(begm_data_total || index<0) + return(-1); +//--- adjust + if(index==-1) + { + if(m_curr_node==NULL) + return(Add(new_node)); + } + else + { + if(GetNodeAtIndex(index)==NULL) + return(Add(new_node)); + } +//--- no need to check m_curr_node + tmp_node=m_curr_node.Prev(); + new_node.Prev(tmp_node); + if(tmp_node!=NULL) + tmp_node.Next(new_node); + else + m_first_node=new_node; + new_node.Next(m_curr_node); + m_curr_node.Prev(new_node); + m_data_total++; + m_data_sort=false; + m_curr_node=new_node; +//--- result + return(index); + } +//+------------------------------------------------------------------+ +//| Get a pointer to the position of element in the list | +//+------------------------------------------------------------------+ +CObject *CList::GetNodeAtIndex(int index) + { + int i; + bool revers; + CObject *result; +//--- check + if(index>=m_data_total) + return(NULL); + if(index==m_curr_idx) + return(m_curr_node); +//--- optimize bust list + if(indexindex;i--) + { + result=result.Prev(); + if(result==NULL) + return(NULL); + } + } + else + { + //--- search from left to right + for(;i=m_data_total || !CheckPointer(m_curr_node)) + return(false); +//--- tune + if(m_curr_idx==index) + return(true); + if(m_curr_idx=i) + { + //--- ">>1" is quick division by 2 + m=(j+i)>>1; + if(m<0 || m>=m_data_total) + break; + t_node=GetNodeAtIndex(m); + if(t_node.Compare(element,m_sort_mode)==0) + break; + if(t_node.Compare(element,m_sort_mode)>0) + j=m-1; + else + i=m+1; + t_node=NULL; + } +//--- result + return(t_node); + } +//+------------------------------------------------------------------+ +//| Search position of an element in a sorted list | +//+------------------------------------------------------------------+ +CObject *CList::Search(CObject *element) + { + CObject *result; +//--- check + if(!CheckPointer(element) || !m_data_sort) + return(NULL); +//--- search + result=QuickSearch(element); +//--- result + return(result); + } +//+------------------------------------------------------------------+ +//| Writing list to file | +//+------------------------------------------------------------------+ +bool CList::Save(const int file_handle) + { + CObject *node; + bool result=true; +//--- check + if(!CheckPointer(m_curr_node) || file_handle==INVALID_HANDLE) + return(false); +//--- write start marker - 0xFFFFFFFFFFFFFFFF + if(FileWriteLong(file_handle,-1)!=sizeof(long)) + return(false); +//--- write type + if(FileWriteInteger(file_handle,Type(),INT_VALUE)!=INT_VALUE) + return(false); +//--- write list size + if(FileWriteInteger(file_handle,m_data_total,INT_VALUE)!=INT_VALUE) + return(false); +//--- sequential scannning of elements in the list using the call of method Save() + node=m_first_node; + while(node!=NULL) + { + result&=node.Save(file_handle); + node=node.Next(); + } +//--- successful + return(result); + } +//+------------------------------------------------------------------+ +//| Reading list from file | +//+------------------------------------------------------------------+ +bool CList::Load(const int file_handle) + { + uint i,num; + CObject *node; + bool result=true; +//--- check + if(file_handle==INVALID_HANDLE) + return(false); +//--- read and checking begin marker - 0xFFFFFFFFFFFFFFFF + if(FileReadLong(file_handle)!=-1) + return(false); +//--- read and checking type + if(FileReadInteger(file_handle,INT_VALUE)!=Type()) + return(false); +//--- read list size + num=FileReadInteger(file_handle,INT_VALUE); +//--- sequential creation of list items using the call of method Load() + Clear(); + for(i=0;i0) + p_node.Left(new_node); + else + p_node.Right(new_node); + new_node.Parent(p_node); + Balance(p_node); + } + else + m_root_node=new_node; +//--- result + return(result); + } +//+------------------------------------------------------------------+ +//| Method of removing a node from the tree | +//+------------------------------------------------------------------+ +bool CTree::Delete(CTreeNode *node) + { +//--- check + if(!CheckPointer(node)) + return(false); +//--- delete + if(Detach(node) && CheckPointer(node)==POINTER_DYNAMIC) + delete node; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Method of detaching node from the tree | +//+------------------------------------------------------------------+ +bool CTree::Detach(CTreeNode *node) + { + CTreeNode *curr_node,*tmp_node; + CTreeNode *nodeA,*nodeB; +//--- check + curr_node=node; + if(!CheckPointer(curr_node)) + return(false); +//--- detach + if(curr_node.BalanceL()>curr_node.BalanceR()) + { + nodeA=curr_node.Left(); + while(nodeA.Right()!=NULL) + nodeA=nodeA.Right(); + nodeB=nodeA.Parent(); + if(nodeB!=curr_node) + { + nodeB.Right(nodeA.Left()); + tmp_node=nodeB.Right(); + if(tmp_node!=NULL) + tmp_node.Parent(nodeB); + tmp_node=curr_node.Left(); + nodeA.Left(tmp_node); + tmp_node.Parent(nodeA); + } + //--- left link of curr_node is already installed as it should be + curr_node.Left(NULL); + //--- transferring the right link of curr_node to nodeA + nodeA.Right(curr_node.Right()); + tmp_node=curr_node.Right(); + if(tmp_node!=NULL) + tmp_node.Parent(nodeA); + curr_node.Right(NULL); + //--- transferring the root link of curr_node to nodeA + tmp_node=curr_node.Parent(); + nodeA.Parent(tmp_node); + if(tmp_node!=NULL) + { + if(tmp_node.Left()==curr_node) + tmp_node.Left(nodeA); + else + tmp_node.Right(nodeA); + } + else + { + curr_node.Parent(NULL); + m_root_node=nodeA; + tmp_node=nodeA; + } + Balance(tmp_node); + } + else + { + if(curr_node.BalanceR()>0) + { + nodeA=curr_node.Right(); + while(nodeA.Left()!=NULL) + nodeA=nodeA.Left(); + nodeB=nodeA.Parent(); + if(nodeB!=curr_node) + { + nodeB.Left(nodeA.Right()); + tmp_node=nodeB.Left(); + if(tmp_node!=NULL) + tmp_node.Parent(nodeB); + tmp_node=curr_node.Right(); + nodeA.Right(tmp_node); + tmp_node.Parent(nodeA); + } + //--- right link of curr_node is already installed as it should be + curr_node.Right(NULL); + //--- transferring the left link of curr_node to nodeA + nodeA.Left(curr_node.Left()); + tmp_node=curr_node.Left(); + if(tmp_node!=NULL) + tmp_node.Parent(nodeA); + curr_node.Left(NULL); + //--- transferring the root link of curr_node to nodeA + tmp_node=curr_node.Parent(); + nodeA.Parent(tmp_node); + if(tmp_node!=NULL) + { + if(tmp_node.Left()==curr_node) + tmp_node.Left(nodeA); + else + tmp_node.Right(nodeA); + } + else + { + curr_node.Parent(NULL); + m_root_node=nodeA; + tmp_node=nodeA; + } + Balance(tmp_node); + } + else + { + //--- node list + if(curr_node.Parent()==NULL) + m_root_node=NULL; + else + { + tmp_node=curr_node.Parent(); + if(tmp_node.Left()==curr_node) + tmp_node.Left(NULL); + else + tmp_node.Right(NULL); + curr_node.Parent(NULL); + } + Balance(curr_node.Parent()); + } + } +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Method of cleaning the tree | +//+------------------------------------------------------------------+ +void CTree::Clear(void) + { + if(CheckPointer(m_root_node)==POINTER_DYNAMIC) + delete m_root_node; + m_root_node=NULL; + } +//+------------------------------------------------------------------+ +//| Method of searching for a node in the tree | +//+------------------------------------------------------------------+ +CTreeNode *CTree::Find(const CTreeNode *node) + { + CTreeNode *result=m_root_node; +//--- find + while(result!=NULL && result.Compare(node)!=0) + result=result.GetNext(node); +//--- result + return(result); + } +//+------------------------------------------------------------------+ +//| Method of balancing the tree | +//+------------------------------------------------------------------+ +void CTree::Balance(CTreeNode *node) + { + CTreeNode *nodeA,*nodeB,*nodeC,*curr_node,*tmp_node; +//--- + curr_node=node; + while(curr_node!=NULL) + { + curr_node.RefreshBalance(); + if(MathAbs(curr_node.BalanceL()-curr_node.BalanceR())<=1) + curr_node=curr_node.Parent(); + else + { + if(curr_node.BalanceR()>curr_node.BalanceL()) + { + //--- rotation to the right + tmp_node=curr_node.Right(); + if(tmp_node.BalanceL()>tmp_node.BalanceR()) + { + //--- great rotation to the right + nodeA=curr_node; + nodeB=nodeA.Right(); + nodeC=nodeB.Left(); + nodeC.Parent(nodeA.Parent()); + tmp_node=nodeC.Parent(); + if(tmp_node!=NULL) + { + if(tmp_node.Right()==nodeA) + tmp_node.Right(nodeC); + else + tmp_node.Left(nodeC); + } + else + m_root_node=nodeC; + nodeA.Parent(nodeC); + nodeB.Parent(nodeC); + nodeA.Right(nodeC.Left()); + tmp_node=nodeA.Right(); + if(tmp_node!=NULL) + tmp_node.Parent(nodeA); + nodeC.Left(nodeA); + nodeB.Left(nodeC.Right()); + tmp_node=nodeB.Left(); + if(tmp_node!=NULL) + tmp_node.Parent(nodeB); + nodeC.Right(nodeB); + if(m_root_node==nodeA) + m_root_node=nodeC; + curr_node=nodeC.Parent(); + } + else + { + //--- slight rotation to the right + nodeA=curr_node; + nodeB=nodeA.Right(); + nodeB.Parent(nodeA.Parent()); + tmp_node=nodeB.Parent(); + if(tmp_node!=NULL) + { + if(tmp_node.Right()==nodeA) + tmp_node.Right(nodeB); + else + tmp_node.Left(nodeB); + } + else + m_root_node=nodeB; + nodeA.Parent(nodeB); + nodeA.Right(nodeB.Left()); + tmp_node=nodeA.Right(); + if(tmp_node!=NULL) + tmp_node.Parent(nodeA); + nodeB.Left(nodeA); + if(m_root_node==nodeA) + m_root_node=nodeB; + curr_node=nodeB.Parent(); + } + } + else + { + //--- rotation to the left + tmp_node=curr_node.Left(); + if(tmp_node.BalanceR()>tmp_node.BalanceL()) + { + //--- great rotation to the left + nodeA=curr_node; + nodeB=nodeA.Left(); + nodeC=nodeB.Right(); + nodeC.Parent(nodeA.Parent()); + tmp_node=nodeC.Parent(); + if(tmp_node!=NULL) + { + if(tmp_node.Right()==nodeA) + tmp_node.Right(nodeC); + else + tmp_node.Left(nodeC); + } + else + m_root_node=nodeC; + nodeA.Parent(nodeC); + nodeB.Parent(nodeC); + nodeA.Left(nodeC.Right()); + tmp_node=nodeA.Left(); + if(tmp_node!=NULL) + tmp_node.Parent(nodeA); + nodeC.Right(nodeA); + nodeB.Right(nodeC.Left()); + tmp_node=nodeB.Right(); + if(tmp_node!=NULL) + tmp_node.Parent(nodeB); + nodeC.Left(nodeB); + if(m_root_node==nodeA) + m_root_node=nodeC; + curr_node=nodeC.Parent(); + } + else + { + //--- small rotation to the left + nodeA=curr_node; + nodeB=nodeA.Left(); + nodeB.Parent(nodeA.Parent()); + tmp_node=nodeB.Parent(); + if(tmp_node!=NULL) + { + if(tmp_node.Right()==nodeA) + tmp_node.Right(nodeB); + else + tmp_node.Left(nodeB); + } + else + m_root_node=nodeB; + nodeA.Parent(nodeB); + nodeA.Left(nodeB.Right()); + tmp_node=nodeA.Left(); + if(tmp_node!=NULL) + tmp_node.Parent(nodeA); + nodeB.Right(nodeA); + if(m_root_node==nodeA) + m_root_node=nodeB; + curr_node=nodeB.Parent(); + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Writing tree to file | +//+------------------------------------------------------------------+ +bool CTree::Save(const int file_handle) + { +//--- check + if(file_handle==INVALID_HANDLE) + return(false); + if(m_root_node==NULL) + return(true); +//--- result + return(m_root_node.SaveNode(file_handle)); + } +//+------------------------------------------------------------------+ +//| Reading tree from file | +//+------------------------------------------------------------------+ +bool CTree::Load(const int file_handle) + { +//--- check + if(file_handle==INVALID_HANDLE) + return(false); +//--- create root node only + Clear(); + Insert(CreateElement()); +//--- result + return(m_root_node.LoadNode(file_handle,m_root_node)); + } +//+------------------------------------------------------------------+ diff --git a/Include/Arrays/TreeNode.mqh b/Include/Arrays/TreeNode.mqh new file mode 100644 index 0000000..fde1633 --- /dev/null +++ b/Include/Arrays/TreeNode.mqh @@ -0,0 +1,174 @@ +//+------------------------------------------------------------------+ +//| TreeNode.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include +//+------------------------------------------------------------------+ +//| Class CTreeNode. | +//| Purpose: Base class of node of binary tree CTree. | +//| Derives from class CObject. | +//+------------------------------------------------------------------+ +class CTreeNode : public CObject + { +private: + CTreeNode *m_p_node; // link to node up + CTreeNode *m_l_node; // link to node left + CTreeNode *m_r_node; // link to node right + //--- variables + int m_balance; // balance of node + int m_l_balance; // balance of the left branch + int m_r_balance; // balance of the right branch + +public: + CTreeNode(void); + ~CTreeNode(void); + //--- methods of access to protected data + CTreeNode* Parent(void) const { return(m_p_node); } + void Parent(CTreeNode *node) { m_p_node=node; } + CTreeNode* Left(void) const { return(m_l_node); } + void Left(CTreeNode *node) { m_l_node=node; } + CTreeNode* Right(void) const { return(m_r_node); } + void Right(CTreeNode *node) { m_r_node=node; } + int Balance(void) const { return(m_balance); } + int BalanceL(void) const { return(m_l_balance); } + int BalanceR(void) const { return(m_r_balance); } + //--- method of identifying the object + virtual int Type(void) const { return(0x8888); } + //--- methods for controlling + int RefreshBalance(void); + CTreeNode *GetNext(const CTreeNode *node); + //--- methods for working with files + bool SaveNode(const int file_handle); + bool LoadNode(const int file_handle,CTreeNode *main); + +protected: + //--- method for creating an instance of class + virtual CTreeNode *CreateSample(void) { return(NULL); } + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CTreeNode::CTreeNode(void) : m_p_node(NULL), + m_l_node(NULL), + m_r_node(NULL), + m_balance(0), + m_l_balance(0), + m_r_balance(0) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTreeNode::~CTreeNode(void) + { +//--- delete nodes of the next level + if(m_l_node!=NULL) + delete m_l_node; + if(m_r_node!=NULL) + delete m_r_node; + } +//+------------------------------------------------------------------+ +//| Calculating the balance of the node | +//+------------------------------------------------------------------+ +int CTreeNode::RefreshBalance(void) + { +//--- calculate the balance of the left branch + if(m_l_node==NULL) + m_l_balance=0; + else + m_l_balance=m_l_node.RefreshBalance(); +//--- calculate the balance of the right branch + if(m_r_node==NULL) + m_r_balance=0; + else + m_r_balance=m_r_node.RefreshBalance(); +//--- calculate the balance of the node + if(m_r_balance>m_l_balance) + m_balance=m_r_balance+1; + else + m_balance=m_l_balance+1; +//--- result + return(m_balance); + } +//+------------------------------------------------------------------+ +//| Selecting next node | +//+------------------------------------------------------------------+ +CTreeNode *CTreeNode::GetNext(const CTreeNode *node) + { + if(Compare(node)>0) + return(m_l_node); +//--- result + return(m_r_node); + } +//+------------------------------------------------------------------+ +//| Writing node data to file | +//+------------------------------------------------------------------+ +bool CTreeNode::SaveNode(const int file_handle) + { + bool result=true; +//--- check + if(file_handle==INVALID_HANDLE) + return(false); +//--- write left node (if it is available) + if(m_l_node!=NULL) + { + FileWriteInteger(file_handle,'L',SHORT_VALUE); + result&=m_l_node.SaveNode(file_handle); + } + else + FileWriteInteger(file_handle,'X',SHORT_VALUE); +//--- write data of current node + result&=Save(file_handle); +//--- write right node (if it is available) + if(m_r_node!=NULL) + { + FileWriteInteger(file_handle,'R',SHORT_VALUE); + result&=m_r_node.SaveNode(file_handle); + } + else + FileWriteInteger(file_handle,'X',SHORT_VALUE); +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Reading node data from file | +//+------------------------------------------------------------------+ +bool CTreeNode::LoadNode(const int file_handle,CTreeNode *main) + { + bool result=true; + short s_val; + CTreeNode *node; +//--- check + if(file_handle==INVALID_HANDLE) + return(false); +//--- read directions + s_val=(short)FileReadInteger(file_handle,SHORT_VALUE); + if(s_val=='L') + { + //--- read left node (if there is data) + node=CreateSample(); + if(node==NULL) + return(false); + m_l_node=node; + node.Parent(main); + result&=node.LoadNode(file_handle,node); + } +//--- read data of current node + result&=Load(file_handle); +//--- read directions + s_val=(short)FileReadInteger(file_handle,SHORT_VALUE); + if(s_val=='R') + { + //--- read right node (if there is data) + node=CreateSample(); + if(node==NULL) + return(false); + m_r_node=node; + node.Parent(main); + result&=node.LoadNode(file_handle,node); + } +//--- result + return(result); + } +//+------------------------------------------------------------------+ diff --git a/Include/Canvas/Canvas.mqh b/Include/Canvas/Canvas.mqh new file mode 100644 index 0000000..3d9c92a --- /dev/null +++ b/Include/Canvas/Canvas.mqh @@ -0,0 +1,4804 @@ +//+------------------------------------------------------------------+ +//| Canvas.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include +//+------------------------------------------------------------------+ +#define SIGN(i) ((i<0) ? -1 : 1) +//+------------------------------------------------------------------+ +//| Macro to generate color | +//+------------------------------------------------------------------+ +#define XRGB(r,g,b) (0xFF000000|(uchar(r)<<16)|(uchar(g)<<8)|uchar(b)) +#define ARGB(a,r,g,b) ((uchar(a)<<24)|(uchar(r)<<16)|(uchar(g)<<8)|uchar(b)) +#define TRGB(a,rgb) ((uchar(a)<<24)|(rgb)) +#define GETRGB(clr) ((clr)&0xFFFFFF) +#define GETRGBA(clr) uchar((clr)>>24) +#define GETRGBR(clr) uchar((clr)>>16) +#define GETRGBG(clr) uchar((clr)>>8) +#define GETRGBB(clr) uchar(clr) +#define COLOR2RGB(clr) (0xFF000000|(uchar(clr)<<16)|(uchar((clr)>>8)<<8)|uchar((clr)>>16)) +#define RGB2COLOR(rgb) ((uchar(rgb)<<16)|(uchar((rgb)>>8)<<8)|uchar((rgb)>>16)) +//+------------------------------------------------------------------+ +//| Line end style (round, butt, square) | +//+------------------------------------------------------------------+ +enum ENUM_LINE_END + { + LINE_END_ROUND, + LINE_END_BUTT, + LINE_END_SQUARE, + }; +//+------------------------------------------------------------------+ +//| Class CCanvas | +//| Usage: class for working with a dynamic resource | +//+------------------------------------------------------------------+ +class CCanvas + { +private: + uint m_style; // line style template + uint m_style_idx; // variable - current index of bit in line style template + static uint m_default_colors[9]; // default colors + +protected: + long m_chart_id; // chart ID + string m_objname; // object name + ENUM_OBJECT m_objtype; // object type + string m_rcname; // resource name + int m_width; // canvas width + int m_height; // canvas height + ENUM_COLOR_FORMAT m_format; // method of color processing + //--- for text + string m_fontname; // font name + int m_fontsize; // font size + uint m_fontflags; // font flags + uint m_fontangle; // angle of text tilt to the X axis in 0.1 degrees + //--- data + uint m_pixels[]; // array of pixels + +public: + CCanvas(void); + ~CCanvas(void); + //--- create/attach/destroy + virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA); + bool CreateBitmap(const string name,const datetime time,const double price, + const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA); + bool CreateBitmap(const long chart_id,const int subwin,const string name, + const datetime time,const double price,const int width,const int height, + ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA); + bool CreateBitmapLabel(const string name,const int x,const int y, + const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA); + bool CreateBitmapLabel(const long chart_id,const int subwin,const string name, + const int x,const int y,const int width,const int height, + ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA); + bool Attach(const long chart_id,const string objname,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA); + bool Attach(const long chart_id,const string objname,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA); + void Destroy(void); + //--- properties + string ChartObjectName(void) const { return(m_objname); } + string ResourceName(void) const { return(m_rcname); } + int Width(void) const { return(m_width); } + int Height(void) const { return(m_height); } + //--- update object on screen + void Update(const bool redraw=true); + bool Resize(const int width,const int height); + //--- clear/fill color + void Erase(const uint clr=0); + //--- data access + uint PixelGet(const int x,const int y) const; + void PixelSet(const int x,const int y,const uint clr); + //--- draw primitives + void LineVertical(int x,int y1,int y2,const uint clr); + void LineHorizontal(int x1,int x2,int y,const uint clr); + void Line(int x1,int y1,int x2,int y2,const uint clr); + void Polyline(int &x[],int &y[],const uint clr); + void Polygon(int &x[],int &y[],const uint clr); + void Rectangle(int x1,int y1,int x2,int y2,const uint clr); + void Triangle(int x1,int y1,int x2,int y2,int x3,int y3,const uint clr); + void Circle(int x,int y,int r,const uint clr); + void Ellipse(int x1,int y1,int x2,int y2,const uint clr); + void Arc(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4,const uint clr); + void Arc(int x,int y,int rx,int ry,double fi3,double fi4,const uint clr); + void Arc(int x,int y,int rx,int ry,double fi3,double fi4,int &x3,int &y3,int &x4,int &y4,const uint clr); + void Pie(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4,const uint clr,const uint fill_clr); + void Pie(int x,int y,int rx,int ry,double fi3,double fi4,const uint clr,const uint fill_clr); + //--- draw filled primitives + void FillRectangle(int x1,int y1,int x2,int y2,const uint clr); + void FillTriangle(int x1,int y1,int x2,int y2,int x3,int y3,const uint clr); + void FillPolygon(int &x[],int &y[],const uint clr); + void FillCircle(int x,int y,int r,const uint clr); + void FillEllipse(int x1,int y1,int x2,int y2,const uint clr); + void Fill(int x,int y,const uint clr); + void Fill(int x,int y,const uint clr,const uint threshould); + //--- draw primitives with antialiasing + void PixelSetAA(const double x,const double y,const uint clr); + void LineAA(const int x1,const int y1,const int x2,const int y2,const uint clr,const uint style=UINT_MAX); + void PolylineAA(int &x[],int &y[],const uint clr,const uint style=UINT_MAX); + void PolygonAA(int &x[],int &y[],const uint clr,const uint style=UINT_MAX); + void TriangleAA(const int x1,const int y1,const int x2,const int y2,const int x3,const int y3, + const uint clr,const uint style=UINT_MAX); + void CircleAA(const int x,const int y,const double r,const uint clr,const uint style=UINT_MAX); + void EllipseAA(const double x1,const double y1,const double x2,const double y2,const uint clr,const uint style=UINT_MAX); + //--- draw primitives with antialiasing by Wu's algorithm + void LineWu(int x1,int y1,int x2,int y2,const uint clr,const uint style=UINT_MAX); + void PolylineWu(const int &x[],const int &y[],const uint clr,const uint style=UINT_MAX); + void PolygonWu(const int &x[],const int &y[],const uint clr,const uint style=UINT_MAX); + void TriangleWu(const int x1,const int y1,const int x2,const int y2,const int x3,const int y3,const uint clr,const uint style=UINT_MAX); + void CircleWu(const int x,const int y,const double r,const uint clr,const uint style=UINT_MAX); + void EllipseWu(const int x1,const int y1,const int x2,const int y2,const uint clr,const uint style=UINT_MAX); + //--- draw primitives with prefiltered antialiasing + void LineThickVertical(const int x,const int y1,const int y2,const uint clr,const int size,const uint style,ENUM_LINE_END end_style); + void LineThickHorizontal(const int x1,const int x2,const int y,const uint clr,const int size,const uint style,ENUM_LINE_END end_style); + void LineThick(const int x1,const int y1,const int x2,const int y2,const uint clr,const int size,const uint style,ENUM_LINE_END end_style); + void PolylineThick(const int &x[],const int &y[],const uint clr,const int size,const uint style,ENUM_LINE_END end_style); + void PolygonThick(const int &x[],const int &y[],const uint clr,const int size,const uint style,ENUM_LINE_END end_style); + //--- draw primitives smoothing polyline and polygon + void PolylineSmooth(const int &x[],const int &y[],const uint clr,const int size, + ENUM_LINE_STYLE style=STYLE_SOLID,ENUM_LINE_END end_style=LINE_END_ROUND, + double tension=0.5,double step=10); + void PolygonSmooth(int &x[],int &y[],const uint clr,const int size, + ENUM_LINE_STYLE style=STYLE_SOLID,ENUM_LINE_END end_style=LINE_END_ROUND, + double tension=0.5,double step=10); + //--- for text + bool FontSet(const string name,const int size,const uint flags=0,const uint angle=0); + bool FontNameSet(string name); + bool FontSizeSet(int size); + bool FontFlagsSet(uint flags); + bool FontAngleSet(uint angle); + void FontGet(string &name,int &size,uint &flags,uint &angle); + string FontNameGet(void) const { return(m_fontname); } + int FontSizeGet(void) const { return(m_fontsize); } + uint FontFlagsGet(void) const { return(m_fontflags); } + uint FontAngleGet(void) const { return(m_fontangle); } + void TextOut(int x,int y,string text,const uint clr,uint alignment=0); + int TextWidth(const string text); + int TextHeight(const string text); + void TextSize(const string text,int &width,int &height); + //--- services + static uint GetDefaultColor(const int i); + void TransparentLevelSet(const uchar value); + //--- load bitmap from file + bool LoadFromFile(const string filename); + //--- line style property + uint LineStyleGet(void) const; + void LineStyleSet(const uint style); + +private: + bool FontSet(void); + void TextOutFast(int x,int y,string text,const uint clr,uint alignment=0); + bool PixelsSimilar(const uint clr0,const uint clr1,const uint threshould); + //--- for Wu's algorithm + void PixelTransform(const int x,const int y,const uint clr,const double alpha); + //--- for circle and ellipse + void PixelTransform4(const int x,const int y,const int dx,const int dy,const uint clr,const double alpha); + void PixelSet4AA(const double x,const double y,const double dx,const double dy,const uint clr); + //--- for thick line + void SegmentVertical(const int x,const int y1,const int y2,const int ysign,const double r,const uint clr,ENUM_LINE_END end_style); + void SegmentHorizontal(const int x1,const int x2,const int y,const int xsign,const double r,const uint clr,ENUM_LINE_END end_style); + void Segment(const int x1,const int y1,const int x2,const int y2,const double kp0,const double kp1,const int xsign,const int ysign, + const double rcos_k,const double rsin_k,const double r,const uint clr,ENUM_LINE_END end_style); + double DistancePointSegment(const double px,const double py,const double x1,const double y1,const double x2,const double y2); + //--- for pie + double AngleCalc(int x1,int y1,int x2,int y2); + //--- for polygon + int PointClassify(const CPoint &p0,const CPoint &p1,const CPoint &p2); + int PolygonClassify(const CPoint &p[]); + bool IsPolygonConvex(CPoint &p[]); + void PolygonNormalize(CPoint &p[]); + void PolygonIntersect(CPoint &p[],CPoint &add[]); + void PolygonFill(CPoint &p[],const uint clr); + //--- for smoothing polyline and polygon + void CalcCurveBezierEndp(const double xend,const double yend,const double xadj,const double yadj,const double tension,double &x,double &y); + void CalcCurveBezier(const int &x[],const int &y[],const int i,const double tension,double &x1,double &y1,double &x2,double &y2); + double CalcBezierX(const double t,const double x0,const double x1,const double x2,const double x3); + double CalcBezierY(const double t,const double y0,const double y1,const double y2,const double y3); + +protected: + //--- method for prefiltered antialiasing + virtual double FilterFunction(const double x); + }; +//+------------------------------------------------------------------+ +//| Initialize static array | +//+------------------------------------------------------------------+ +uint CCanvas::m_default_colors[9]= + { + XRGB(0,0,255), // blue + XRGB(255,0,0), // red + XRGB(0,128,0), // green + XRGB(255,242,0), // yellow + XRGB(255,0,128), // pink + XRGB(0,255,0), // lime + XRGB(185,0,61), // crimson + XRGB(0,183,239), // sky blue + XRGB(255,128,0) // orange + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CCanvas::CCanvas(void) : m_chart_id(0), + m_objname(NULL), + m_objtype(WRONG_VALUE), + m_rcname(NULL), + m_width(0), + m_height(0), + m_format(COLOR_FORMAT_XRGB_NOALPHA), + m_fontname("arial"), + m_fontsize(-120), + m_fontflags(0), + m_fontangle(0), + m_style(UINT_MAX), + m_style_idx(0) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CCanvas::~CCanvas(void) + { + } +//+------------------------------------------------------------------+ +//| Create dynamic resource | +//+------------------------------------------------------------------+ +bool CCanvas::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt) + { + Destroy(); +//--- prepare data array + if(width>0 && height>0 && ArrayResize(m_pixels,width*height)>0) + { + //--- generate resource name + m_rcname="::"+name+(string)(GetTickCount()+MathRand()); + //--- initialize data with zeros + ArrayInitialize(m_pixels,0); + //--- create dynamic resource + if(ResourceCreate(m_rcname,m_pixels,width,height,0,0,0,clrfmt)) + { + //--- successfully created + //--- complete initialization + m_width =width; + m_height=height; + m_format=clrfmt; + //--- succeed + return(true); + } + } +//--- error - destroy object + Destroy(); + return(false); + } +//+------------------------------------------------------------------+ +//| Create object on chart with attached dynamic resource | +//+------------------------------------------------------------------+ +bool CCanvas::CreateBitmap(const string name,const datetime time,const double price, + const int width,const int height,ENUM_COLOR_FORMAT clrfmt) + { + return(CreateBitmap(0,0,name,time,price,width,height,clrfmt)); + } +//+------------------------------------------------------------------+ +//| Create object on chart with attached dynamic resource | +//+------------------------------------------------------------------+ +bool CCanvas::CreateBitmap(const long chart_id,const int subwin,const string name, + const datetime time,const double price,const int width,const int height, + ENUM_COLOR_FORMAT clrfmt) + { +//--- create canvas + if(Create(name,width,height,clrfmt)) + { + //--- create attached object + if(ObjectCreate(chart_id,name,OBJ_BITMAP,subwin,time,price)) + { + //--- bind object with resource + if(ObjectSetString(chart_id,name,OBJPROP_BMPFILE,m_rcname)) + { + //--- successfully created + //--- complete initialization + m_chart_id=chart_id; + m_objname =name; + m_objtype =OBJ_BITMAP; + //--- succeed + return(true); + } + } + } +//--- error + return(false); + } +//+------------------------------------------------------------------+ +//| Create object on chart with attached dynamic resource | +//+------------------------------------------------------------------+ +bool CCanvas::CreateBitmapLabel(const string name,const int x,const int y, + const int width,const int height,ENUM_COLOR_FORMAT clrfmt) + { + return(CreateBitmapLabel(0,0,name,x,y,width,height,clrfmt)); + } +//+------------------------------------------------------------------+ +//| Create object on chart with attached dynamic resource | +//+------------------------------------------------------------------+ +bool CCanvas::CreateBitmapLabel(const long chart_id,const int subwin,const string name, + const int x,const int y,const int width,const int height, + ENUM_COLOR_FORMAT clrfmt) + { +//--- create canvas + if(Create(name,width,height,clrfmt)) + { + //--- create attached object + if(ObjectCreate(chart_id,name,OBJ_BITMAP_LABEL,subwin,0,0)) + { + //--- set x,y and bind object with resource + if(ObjectSetInteger(chart_id,name,OBJPROP_XDISTANCE,x) && + ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,y) && + ObjectSetString(chart_id,name,OBJPROP_BMPFILE,m_rcname)) + { + //--- successfully created + //--- complete initialization + m_chart_id=chart_id; + m_objname =name; + m_objtype =OBJ_BITMAP_LABEL; + //--- succeed + return(true); + } + } + } +//--- error + return(false); + } +//+------------------------------------------------------------------+ +//| Attach new object with bitmap resource | +//+------------------------------------------------------------------+ +bool CCanvas::Attach(const long chart_id,const string objname,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA) + { + if(OBJ_BITMAP_LABEL==ObjectGetInteger(chart_id,objname,OBJPROP_TYPE)) + { + string rcname=ObjectGetString(chart_id,objname,OBJPROP_BMPFILE); + rcname=StringSubstr(rcname,StringFind(rcname,"::")); + if(ResourceReadImage(rcname,m_pixels,m_width,m_height)) + { + m_objname=objname; + m_rcname=rcname; + m_format=clrfmt; + m_objtype=OBJ_BITMAP_LABEL; + //--- success + return(true); + } + } +//--- failed + return(false); + } +//+------------------------------------------------------------------+ +//| Attach new object without bitmap resource | +//+------------------------------------------------------------------+ +bool CCanvas::Attach(const long chart_id,const string objname,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA) + { + if(OBJ_BITMAP_LABEL==ObjectGetInteger(chart_id,objname,OBJPROP_TYPE)) + { + string rcname=ObjectGetString(chart_id,objname,OBJPROP_BMPFILE); + if(StringLen(rcname)==0 && width>0 && height>0 && ArrayResize(m_pixels,width*height)>0) + { + ZeroMemory(m_pixels); + if(ResourceCreate("::"+objname,m_pixels,width,height,0,0,0,clrfmt) && + ObjectSetString(chart_id,objname,OBJPROP_BMPFILE,"::"+objname)) + { + m_width=width; + m_height=height; + m_objname=objname; + m_rcname="::"+objname; + m_format=clrfmt; + m_objtype=OBJ_BITMAP_LABEL; + //--- success + return(true); + } + } + } +//--- failed + return(false); + } +//+------------------------------------------------------------------+ +//| Remove object from chart and deallocate data array | +//+------------------------------------------------------------------+ +void CCanvas::Destroy(void) + { +//--- delete object + if(m_objname!=NULL) + { + ObjectDelete(m_chart_id,m_objname); + m_chart_id=0; + m_objname =NULL; + m_objtype =WRONG_VALUE; + } +//--- deallocate array + ArrayFree(m_pixels); +//--- free resource + if(m_rcname!=NULL) + { + ResourceFree(m_rcname); + m_rcname=NULL; + } +//--- zeroize data + m_width =0; + m_height=0; + } +//+------------------------------------------------------------------+ +//| Update object on screen (redraw) | +//+------------------------------------------------------------------+ +void CCanvas::Update(const bool redraw) + { +//--- check + if(m_rcname==NULL) + return; +//--- update resource and redraw + if(ResourceCreate(m_rcname,m_pixels,m_width,m_height,0,0,0,m_format) && redraw) + ChartRedraw(this.m_chart_id); + } +//+------------------------------------------------------------------+ +//| Resize | +//+------------------------------------------------------------------+ +bool CCanvas::Resize(const int width,const int height) + { +//--- check + if(m_rcname!=NULL && width>0 && height>0) + if(ArrayResize(m_pixels,width*height)>0) + { + m_width =width; + m_height=height; + //--- initialize data with zeros + ArrayInitialize(m_pixels,0); + //--- create dynamic resource + if(ResourceCreate(m_rcname,m_pixels,m_width,m_height,0,0,0,m_format)) + { + //--- bind object with resource + if(m_objname!=NULL && ObjectSetString(m_chart_id,m_objname,OBJPROP_BMPFILE,m_rcname)) + return(true); + } + } +//--- error + return(false); + } +//+------------------------------------------------------------------+ +//| Clear/Fill color | +//+------------------------------------------------------------------+ +void CCanvas::Erase(const uint clr) + { + ArrayInitialize(m_pixels,clr); + } +//+------------------------------------------------------------------+ +//| Get pixel color | +//+------------------------------------------------------------------+ +uint CCanvas::PixelGet(const int x,const int y) const + { +//--- check coordinates + if(x>=0 && x=0 && y=0 && x=0 && y=m_width || y<0 || y>=m_height) + return; +//--- + int index=y*m_width+x; + uint old_clr=m_pixels[index]; +//--- check if replacement is necessary + if(old_clr==clr) + return; +//--- use pseudo stack to emulate deeply-nested recursive calls + int stack[]; + uint count=1; + int idx; + int total=ArraySize(m_pixels); +//--- allocate memory for stack + if(ArrayResize(stack,total)==-1) + return; + stack[0]=index; + m_pixels[index]=clr; + for(uint i=0;i0 && m_pixels[idx]==old_clr) + { + m_pixels[idx]=clr; + stack[count++]=idx; + } + //--- top adjacent point + idx=index-m_width; + if(idx>=0 && m_pixels[idx]==old_clr) + { + m_pixels[idx]=clr; + stack[count++]=idx; + } + //--- right adjacent point + idx=index+1; + if(x=m_width || y<0 || y>=m_height || threshould>255) + return; +//--- + int index=y*m_width+x; + uint old_clr=m_pixels[index]; +//--- check if replacement is necessary + if(old_clr==clr) + return; +//--- use pseudo stack to emulate deeply-nested recursive calls + int stack[]; + uint count=1; + int idx; + int total=ArraySize(m_pixels); +//--- allocate memory for stack + if(ArrayResize(stack,total)==-1) + return; + stack[0]=index; + m_pixels[index]=clr; + for(uint i=0;i0 && PixelsSimilar(m_pixels[idx],old_clr,threshould) && m_pixels[idx]!=clr) + { + m_pixels[idx]=clr; + stack[count++]=idx; + } + //--- top adjacent point + idx=index-m_width; + if(idx>=0 && PixelsSimilar(m_pixels[idx],old_clr,threshould) && m_pixels[idx]!=clr) + { + m_pixels[idx]=clr; + stack[count++]=idx; + } + //--- right adjacent point + idx=index+1; + if(xy2) + { + tmp=y1; + y1 =y2; + y2 =tmp; + } +//--- line is out of image boundaries + if(y2<0 || y1>=m_height || x<0 || x>=m_width) + return; +//--- stay withing image boundaries + if(y1<0) + y1=0; + if(y2>=m_height) + y2=m_height-1; +//--- draw line + int index=y1*m_width+x; + for(int i=y1;i<=y2;i++,index+=m_width) + m_pixels[index]=clr; + } +//+------------------------------------------------------------------+ +//| Draw horizontal line | +//+------------------------------------------------------------------+ +void CCanvas::LineHorizontal(int x1,int x2,int y,const uint clr) + { + int tmp; +//--- sort by X + if(x1>x2) + { + tmp=x1; + x1 =x2; + x2 =tmp; + } +//--- line is out of image boundaries + if(x2<0 || x1>=m_width || y<0 || y>=m_height) + return; +//--- stay withing image boundaries + if(x1<0) + x1=0; + if(x2>=m_width) + x2=m_width-1; +//--- draw line + ArrayFill(m_pixels,y*m_width+x1,(x2-x1)+1,clr); + } +//+------------------------------------------------------------------+ +//| Draw line according to Bresenham's algorithm | +//+------------------------------------------------------------------+ +void CCanvas::Line(int x1,int y1,int x2,int y2,const uint clr) + { +//--- line is out of image boundaries + if((x1<0 && x2<0) || (y1<0 && y2<0)) + return; + if(x1>=m_width && x2>=m_width) + return; + if(y1>=m_height && y2>=m_height) + return; +//--- get length by X and Y + int dx=(x2>x1)? x2-x1 : x1-x2; + int dy=(y2>y1)? y2-y1 : y1-y2; + if(dx==0) + { + //--- vertical line + LineVertical(x1,y1,y2,clr); + return; + } + if(dy==0) + { + //--- horizontal line + LineHorizontal(x1,x2,y1,clr); + return; + } +//--- get direction by X and Y + int sx=(x1=m_width || + y1<0 || y1>=m_height) + { + if(draw) + return; + } + else + { + //--- draw pixel + m_pixels[y1*m_width+x1]=clr; + draw=true; + } + //--- get coordinates of next pixel + int er2=er<<1; + if(er2>-dy) + { + er-=dy; + x1+=sx; + } + if(er2ArraySize(y)) + total=ArraySize(y); +//--- check + if(total<2) + return; + total--; +//--- draw + for(int i=0;iArraySize(y)) + total=ArraySize(y); +//--- check + if(total<2) + return; + total--; +//--- draw + for(int i=0;i=dx) + { + xx=x+dx; + if(xx>=0 && xx=0 && yy=0 && yy=0 && xx=0 && yy=0 && yy=0 && xx=0 && yy=0 && yy=0 && xx=0 && yy=0 && yy=0) + { + dy--; + dd_y+=2; + f+=dd_y; + } + dx++; + dd_x+=2; + f+=dd_x; + } + } +//+------------------------------------------------------------------+ +//| Draw ellipse according to Bresenham's algorithm | +//+------------------------------------------------------------------+ +void CCanvas::Ellipse(int x1,int y1,int x2,int y2,const uint clr) + { + int x,y; + int rx,ry; + int dx,dy; + int xx,yy; + int rx_sq,ry_sq; + int f; + int tmp; +//--- handle extreme conditions + if(x1==x2) + { + if(y1==y2) + PixelSet(x1,y1,clr); + else + LineVertical(x1,y1,y2,clr); + return; + } + if(y1==y2) + { + LineHorizontal(x1,x2,y1,clr); + return; + } +//--- sort by X + if(x1>x2) + { + tmp=x1; + x1 =x2; + x2 =tmp; + } +//--- sort by Y + if(y1>y2) + { + tmp=y1; + y1 =y2; + y2 =tmp; + } + x =(x2+x1)>>1; + y =(y2+y1)>>1; + rx=(x2-x1)>>1; + ry=(y2-y1)>>1; + dx=0; + dy=ry; + rx_sq=rx*rx; + ry_sq=ry*ry; + f=(rx_sq<<1)*((dy-1)*dy)+rx_sq+(ry_sq<<1)*(1-rx_sq); + while(rx_sq*dy>ry_sq*dx) + { + yy=y+dy; + if(yy>=0 && yy=0 && xx=0 && xx=0 && yy=0 && xx=0 && xx=0) + { + dy--; + f-=(rx_sq<<2)*dy; + } + f+=(ry_sq<<1)*(3+(dx<<1)); + dx++; + } + f=(ry_sq<<1)*(dx+1)*dx+(rx_sq<<1)*(dy*(dy-2)+1)+(1-(rx_sq<<1))*ry_sq; + while(dy>=0) + { + yy=y+dy; + if(yy>=0 && yy=0 && xx=0 && xx=0 && yy=0 && xx=0 && xxx2) + { + tmp=x1; + x1 =x2; + x2 =tmp; + } +//--- sort by Y + if(y1>y2) + { + tmp=y1; + y1 =y2; + y2 =tmp; + } + x =(x2+x1)>>1; + y =(y2+y1)>>1; +//--- check rays + if(x3==x && y3==y) + return; + if(x4==x && y4==y) + return; +//--- calculate parameters of ray x3,y3 + fi3=AngleCalc(x,y,x3,y3); +//--- calculate parameters of ray x4,y4 + fi4=AngleCalc(x,y,x4,y4); +//--- draw arc + Arc(x,y,x2-x,y2-y,fi3,fi4,clr); + } +//+------------------------------------------------------------------+ +//| Draws ellipse arc | +//+------------------------------------------------------------------+ +void CCanvas::Arc(int x,int y,int rx,int ry,double fi3,double fi4,const uint clr) + { + int x3,y3,x4,y4; +//--- check + if(rx<10 || ry<10) + return; + if(rx<0) + rx=-rx; + if(ry<0) + ry=-ry; +//--- check rays + if(fi3==fi4) + return; +//--- adjustment for passing through 0 + if(fi40) || // ray 3 is in the 1st or 2nd quadrant + (fi0) || // ray 4 is in the 1st or 2nd quadrant + (fi4-fi3>=M_PI)) // arc will pass through the top of the ellipse + { + dx=0; + dy=ry; + f=(rx_sq<<1)*((dy-1)*dy)+rx_sq+(ry_sq<<1)*(1-rx_sq); + while(rx_sq*dy>=ry_sq*dx) + { + yy=y-dy; + if(dx==0) + { + //--- central point + fi=AngleCalc(0,0,0,-dy); + if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI)) + { + PixelSet(x,yy,clr); + ckw=ackw=true; + } + else + ckw=ackw=false; + xx_c=x; + yy_c=yy; + fi_c=fi; + xx_a=x; + yy_a=yy; + fi_a=fi; + } + else + { + //--- iterate clockwise + xx=x+dx; + fi=AngleCalc(0,0,dx,-dy); + if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI)) + { + PixelSet(xx,yy,clr); + //--- if arc haven't been drawn before and intersection point of ray 4 and arc is not defined + //--- this means that we (while iterating over points of the ellipse) had just crossed ray 4 + if(!ckw) + { + ckw=true; + if(!ray4) + { + if(MathAbs(fi_c-MathMod(fi4,2*M_PI))MathAbs(fi-fi3)) + PixelSet(x3=xx,y3=yy,clr); + else + { + x3=xx_c; + y3=yy_c; + } + ray3=true; + } + ckw=false; + } + //--- save parameters of the last iteration + xx_c=xx; + yy_c=yy; + fi_c=fi; + //--- iterate counterclockwise + xx=x-dx; + fi=AngleCalc(0,0,-dx,-dy); + if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI)) + { + PixelSet(xx,yy,clr); + //--- if arc haven't been drawn before and intersection point of ray 3 and arc is not defined + //--- this means that we (while iterating over points of the ellipse) had just crossed ray 3 + if(!ackw) + { + ackw=true; + if(!ray3) + { + if(MathAbs(fi_a-fi3)MathAbs(fi-MathMod(fi4,2*M_PI))) + PixelSet(x4=xx,y4=yy,clr); + else + { + x4=xx_a; + y4=yy_a; + } + ray4=true; + } + ackw=false; + } + //--- save parameters of the last iteration + xx_a=xx; + yy_a=yy; + fi_a=fi; + } + //--- calculate coordinates of the next point + if(f>=0) + { + dy--; + f-=(rx_sq<<2)*dy; + } + f+=(ry_sq<<1)*(3+(dx<<1)); + dx++; + } + //--- if arc has been drawn clockwise "to the end" and ray 3 had not been found + if(ckw && !ray3) + { + fi=AngleCalc(0,0,dx,-dy); + if(MathAbs(fi_c-fi3)>MathAbs(fi-fi3)) + PixelSet(x3=x+dx,y3=y-dy,clr); + else + { + x3=xx_c; + y3=yy_c; + } + } + //--- if arc has been drawn counterclockwise "to the end" and ray 4 had not been found + if(ackw && !ray4) + { + fi=AngleCalc(0,0,-dx,-dy); + if(MathAbs(fi_a-MathMod(fi4,2*M_PI))>MathAbs(fi-MathMod(fi4,2*M_PI))) + PixelSet(x4=x-dx,y4=y-dy,clr); + else + { + x4=xx_a; + y4=yy_a; + } + } + } +//--- 2 left +//--- +//--- if arc is obviously not within the rays range, don't draw + fi=MathMod(fi4,2*M_PI); + if((fi3>M_PI_2 && fi3<3*M_PI_2) || // ray 3 is in the 2nd or 3rd quadrant + (fi>M_PI_2 && fi<3*M_PI_2) || // ray 4 is in the 2nd or 3rd quadrant + (fi4-fi3>=M_PI)) // arc will pass through the left part of the ellipse + { + dx=rx; + dy=0; + f=(ry_sq<<1)*((dx-1)*dx)+ry_sq+(rx_sq<<1)*(1-ry_sq); + while(ry_sq*dx>=rx_sq*dy) + { + xx=x-dx; + if(dy==0) + { + //--- central point + fi=AngleCalc(0,0,-dx,0); + if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI)) + { + PixelSet(xx,y,clr); + ckw=ackw=true; + } + else + ckw=ackw=false; + xx_c=xx; + yy_c=y; + fi_c=fi; + xx_a=xx; + yy_a=y; + fi_a=fi; + } + else + { + //--- iterate clockwise + yy=y-dy; + fi=AngleCalc(0,0,-dx,-dy); + if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI)) + { + PixelSet(xx,yy,clr); + //--- if arc haven't been drawn before and intersection point of ray 4 and arc is not defined + //--- this means that we (while iterating over points of the ellipse) had just crossed ray 4 + if(!ckw) + { + ckw=true; + if(!ray4) + { + if(MathAbs(fi_c-MathMod(fi4,2*M_PI))MathAbs(fi-fi3)) + PixelSet(x3=xx,y3=yy,clr); + else + { + x3=xx_c; + y3=yy_c; + } + ray3=true; + } + ckw=false; + } + //--- save parameters of the last iteration + xx_c=xx; + yy_c=yy; + fi_c=fi; + //--- iterate counterclockwise + yy=y+dy; + fi=AngleCalc(0,0,-dx,dy); + if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI)) + { + PixelSet(xx,yy,clr); + //--- if arc haven't been drawn before and intersection point of ray 3 and arc is not defined + //--- this means that we (while iterating over points of the ellipse) had just crossed ray 3 + if(!ackw) + { + ackw=true; + if(!ray3) + { + if(MathAbs(fi_a-fi3)MathAbs(fi-MathMod(fi4,2*M_PI))) + PixelSet(x4=xx,y4=yy,clr); + else + { + x4=xx_a; + y4=yy_a; + } + ray4=true; + } + ackw=false; + } + //--- save parameters of the last iteration + xx_a=xx; + yy_a=yy; + fi_a=fi; + } + //--- calculate coordinates of the next point + if(f>=0) + { + dx--; + f-=(ry_sq<<2)*dx; + } + f+=(rx_sq<<1)*(3+(dy<<1)); + dy++; + } + //--- if arc has been drawn clockwise "to the end" and ray 3 had not been found + if(ckw && !ray3) + { + fi=AngleCalc(0,0,-dx,-dy); + if(MathAbs(fi_c-fi3)>MathAbs(fi-fi3)) + PixelSet(x3=x-dx,y3=y-dy,clr); + else + { + x3=xx_c; + y3=yy_c; + } + } + //--- if arc has been drawn counterclockwise "to the end" and ray 4 had not been found + if(ackw && !ray4) + { + fi=AngleCalc(0,0,-dx,dy); + if(MathAbs(fi_a-MathMod(fi4,2*M_PI))>MathAbs(fi-MathMod(fi4,2*M_PI))) + PixelSet(x4=x-dx,y4=y+dy,clr); + else + { + x4=xx_a; + y4=yy_a; + } + } + } +//--- 3 bottom +//--- +//--- if arc is obviously not within the rays range, don't draw + fi=MathMod(fi4,2*M_PI); + if((fi3>M_PI && fi3<2*M_PI) || // ray 3 is in the 3rd or 4th quadrant + (fi>M_PI && fi<2*M_PI) || // ray 4 is in the 3rd or 4th quadrant + (fi4-fi3>=M_PI)) // arc will pass through the bottom of the ellipse + { + dx=0; + dy=ry; + f=(rx_sq<<1)*((dy-1)*dy)+rx_sq+(ry_sq<<1)*(1-rx_sq); + while(rx_sq*dy>=ry_sq*dx) + { + yy=y+dy; + if(dx==0) + { + //--- central point + fi=AngleCalc(0,0,0,dy); + if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI)) + { + PixelSet(x,yy,clr); + ckw=ackw=true; + } + else + ckw=ackw=false; + xx_c=x; + yy_c=yy; + fi_c=fi; + xx_a=x; + yy_a=yy; + fi_a=fi; + } + else + { + //--- iterate clockwise + xx=x-dx; + fi=AngleCalc(0,0,-dx,dy); + if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI)) + { + PixelSet(xx,yy,clr); + //--- if arc haven't been drawn before and intersection point of ray 4 and arc is not defined + //--- this means that we (while iterating over points of the ellipse) had just crossed ray 4 + if(!ckw) + { + ckw=true; + if(!ray4) + { + if(MathAbs(fi_c-MathMod(fi4,2*M_PI))MathAbs(fi-fi3)) + PixelSet(x3=xx,y3=yy,clr); + else + { + x3=xx_c; + y3=yy_c; + } + ray3=true; + } + ckw=false; + } + //--- save parameters of the last iteration + xx_c=xx; + yy_c=yy; + fi_c=fi; + //--- iterate counterclockwise + xx=x+dx; + fi=AngleCalc(0,0,dx,dy); + if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI)) + { + PixelSet(xx,yy,clr); + //--- if arc haven't been drawn before and intersection point of ray 3 and arc is not defined + //--- this means that we (while iterating over points of the ellipse) had just crossed ray 3 + if(!ackw) + { + ackw=true; + if(!ray3) + { + if(MathAbs(fi_a-fi3)MathAbs(fi-MathMod(fi4,2*M_PI))) + PixelSet(x4=xx,y4=yy,clr); + else + { + x4=xx_a; + y4=yy_a; + } + ray4=true; + } + ackw=false; + } + //--- save parameters of the last iteration + xx_a=xx; + yy_a=yy; + fi_a=fi; + } + //--- calculate coordinates of the next point + if(f>=0) + { + dy--; + f-=(rx_sq<<2)*dy; + } + f+=(ry_sq<<1)*(3+(dx<<1)); + dx++; + } + //--- if arc has been drawn clockwise "to the end" and ray 3 had not been found + if(ckw && !ray3) + { + fi=AngleCalc(0,0,-dx,dy); + if(MathAbs(fi_c-fi3)>MathAbs(fi-fi3)) + PixelSet(x3=x-dx,y3=y+dy,clr); + else + { + x3=xx_c; + y3=yy_c; + } + } + //--- if arc has been drawn counterclockwise "to the end" and ray 4 had not been found + if(ackw && !ray4) + { + fi=AngleCalc(0,0,dx,dy); + if(MathAbs(fi_a-MathMod(fi4,2*M_PI))>MathAbs(fi-MathMod(fi4,2*M_PI))) + PixelSet(x4=x+dx,y4=y+dy,clr); + else + { + x4=xx_a; + y4=yy_a; + } + } + } +//--- 4 right +//--- +//--- if arc is obviously not within the rays range, don't draw + fi=MathMod(fi4,2*M_PI); + if((fi33*M_PI_2) || // ray 3 is 1 or 4 quadrant + (fi3*M_PI_2) || // ray 4 is 1 or 4 quadrant + (fi4-fi3>=M_PI)) // arc will pass through the right side of the ellipse + { + dx=rx; + dy=0; + f=(ry_sq<<1)*((dx-1)*dx)+ry_sq+(rx_sq<<1)*(1-ry_sq); + while(ry_sq*dx>=rx_sq*dy) + { + xx=x+dx; + if(dy==0) + { + //--- central point + fi=AngleCalc(0,0,dx,0); + if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI)) + { + PixelSet(xx,y,clr); + ckw=ackw=true; + } + else + ckw=ackw=false; + xx_c=xx; + yy_c=y; + fi_c=fi; + xx_a=xx; + yy_a=y; + fi_a=fi; + } + else + { + //--- iterate clockwise + yy=y+dy; + fi=AngleCalc(0,0,dx,dy); + if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI)) + { + PixelSet(xx,yy,clr); + //--- if arc haven't been drawn before and intersection point of ray 4 and arc is not defined + //--- this means that we (while iterating over points of the ellipse) had just crossed ray 4 + if(!ckw) + { + ckw=true; + if(!ray4) + { + if(MathAbs(fi_c-MathMod(fi4,2*M_PI))MathAbs(fi-fi3)) + PixelSet(x3=xx,y3=yy,clr); + else + { + x3=xx_c; + y3=yy_c; + } + ray3=true; + } + ckw=false; + } + //--- save parameters of the last iteration + xx_c=xx; + yy_c=yy; + fi_c=fi; + //--- iterate counterclockwise + yy=y-dy; + fi=AngleCalc(0,0,dx,-dy); + if((fi<=fi4 && fi3<=fi) || (fi4>=2*M_PI && fi<=fi4-2*M_PI)) + { + PixelSet(xx,yy,clr); + //--- if arc haven't been drawn before and intersection point of ray 3 and arc is not defined + //--- this means that we (while iterating over points of the ellipse) had just crossed ray 3 + if(!ackw) + { + ackw=true; + if(!ray3) + { + if(MathAbs(MathMod(fi_a,2*M_PI)-fi3)MathAbs(fi-MathMod(fi4,2*M_PI))) + PixelSet(x4=xx,y4=yy,clr); + else + { + x4=xx_a; + y4=yy_a; + } + ray4=true; + } + ackw=false; + } + //--- save parameters of the last iteration + xx_a=xx; + yy_a=yy; + fi_a=fi; + } + //--- calculate coordinates of the next point + if(f>=0) + { + dx--; + f-=(ry_sq<<2)*dx; + } + f+=(rx_sq<<1)*(3+(dy<<1)); + dy++; + } + //--- if arc has been drawn clockwise "to the end" and ray 3 had not been found + if(ckw && !ray3) + { + fi=AngleCalc(0,0,dx,dy); + if(MathAbs(fi_c-fi3)>MathAbs(fi-fi3)) + PixelSet(x3=x+dx,y3=y+dy,clr); + else + { + x3=xx_c; + y3=yy_c; + } + } + //--- if arc has been drawn counterclockwise "to the end" and ray 4 had not been found + if(ackw && !ray4) + { + fi=AngleCalc(0,0,dx,-dy); + if(MathAbs(MathMod(fi_a,2*M_PI)-MathMod(fi4,2*M_PI))>MathAbs(fi-MathMod(fi4,2*M_PI))) + PixelSet(x4=x+dx,y4=y-dy,clr); + else + { + x4=xx_a; + y4=yy_a; + } + } + } + } +//+------------------------------------------------------------------+ +//| Draws ellipse pie | +//+------------------------------------------------------------------+ +void CCanvas::Pie(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4,const uint clr,const uint fill_clr) + { + int tmp; + int x,y; +//--- + double fi3; + double fi4; +//--- check + if(x1==x2 || y1==y2) + return; +//--- sort by X + if(x1>x2) + { + tmp=x1; + x1 =x2; + x2 =tmp; + } +//--- sort by Y + if(y1>y2) + { + tmp=y1; + y1 =y2; + y2 =tmp; + } + x =(x2+x1)>>1; + y =(y2+y1)>>1; +//--- check rays + if(x3==x && y3==y) + return; + if(x4==x && y4==y) + return; +//--- calculate parameters of ray x3,y3 + fi3=AngleCalc(x,y,x3,y3); +//--- calculate parameters of ray x4,y4 + fi4=AngleCalc(x,y,x4,y4); +//--- draw pie + Pie(x,y,x2-x,y2-y,fi3,fi4,clr,fill_clr); + } +//+------------------------------------------------------------------+ +//| Draws ellipse pie | +//+------------------------------------------------------------------+ +void CCanvas::Pie(int x,int y,int rx,int ry,double fi3,double fi4,const uint clr,const uint fill_clr) + { + int x3=x; + int y3=y; + int x4=x; + int y4=y; +//--- check + if(rx==0 || ry==0) + return; + if(rx<0) + rx=-rx; + if(ry<0) + ry=-ry; +//--- check rays + if(fi3==fi4) + return; +//--- adjustment for passing through 0 + if(fi4ry) + rx=ry; + double fi=(fi3+fi4)/2; + int xf=x+(int)(0.9*rx*cos(fi)); + int yf=y-(int)(0.9*rx*sin(fi)); + Fill(xf,yf,fill_clr); + } +//+------------------------------------------------------------------+ +//| Draw filled circle | +//+------------------------------------------------------------------+ +void CCanvas::FillCircle(int x,int y,int r,const uint clr) + { + int f =1-r; + int dd_x=1; + int dd_y=-2*r; + int dx =0; + int dy =r; +//--- draw + while(dy>=dx) + { + LineHorizontal(x-dy,x+dy,y-dx,clr); + LineHorizontal(x-dy,x+dy,y+dx,clr); + //--- + if(f>=0) + { + LineHorizontal(x-dx,x+dx,y-dy,clr); + LineHorizontal(x-dx,x+dx,y+dy,clr); + dy--; + dd_y+=2; + f+=dd_y; + } + dx++; + dd_x+=2; + f+=dd_x; + } + } +//+------------------------------------------------------------------+ +//| Draw filled ellipse | +//+------------------------------------------------------------------+ +void CCanvas::FillEllipse(int x1,int y1,int x2,int y2,const uint clr) + { + int x,y; + int rx,ry; + int dx,dy; + int rx_sq,ry_sq; + int f; + int tmp; +//--- handle extreme conditions + if(x1==x2) + { + if(y1==y2) + PixelSet(x1,y1,clr); + else + LineVertical(x1,y1,y2,clr); + return; + } + if(y1==y2) + { + LineHorizontal(x1,x2,y1,clr); + return; + } +//--- sort by X + if(x1>x2) + { + tmp=x1; + x1 =x2; + x2 =tmp; + } +//--- sort by Y + if(y1>y2) + { + tmp=y1; + y1 =y2; + y2 =tmp; + } + x =(x2+x1)>>1; + y =(y2+y1)>>1; + rx=(x2-x1)>>1; + ry=(y2-y1)>>1; + dx=0; + dy=ry; + rx_sq=rx*rx; + ry_sq=ry*ry; + f=(rx_sq<<1)*((dy-1)*dy)+rx_sq+(ry_sq<<1)*(1-rx_sq); + while(rx_sq*dy>ry_sq*(dx)) + { + LineHorizontal(x-dx,x+dx,y+dy,clr); + LineHorizontal(x-dx,x+dx,y-dy,clr); + if(f>=0) + { + dy--; + f-=(rx_sq<<2)*dy; + } + f+=(ry_sq<<1)*(3+(dx<<1)); + dx++; + } + f=(ry_sq<<1)*(dx+1)*dx+(rx_sq<<1)*(dy*(dy-2)+1)+(1-(rx_sq<<1))*ry_sq; + while(dy>=0) + { + LineHorizontal(x-dx,x+dx,y+dy,clr); + LineHorizontal(x-dx,x+dx,y-dy,clr); + if(f<=0) + { + dx++; + f+=(ry_sq<<2)*dx; + } + dy--; + f+=(rx_sq<<1)*(3-(dy<<1)); + } + } +//+------------------------------------------------------------------+ +//| Draw filled rectangle | +//+------------------------------------------------------------------+ +void CCanvas::FillRectangle(int x1,int y1,int x2,int y2,const uint clr) + { + int tmp; +//--- sort vertexes + if(x2=m_width || y1>=m_height) + return; +//--- stay withing screen boundaries + if(x1<0) + x1=0; + if(y1<0) + y1=0; + if(x2>=m_width) + x2=m_width -1; + if(y2>=m_height) + y2=m_height-1; + int len=(x2-x1)+1; +//--- set pixels + for(;y1<=y2;y1++) + ArrayFill(m_pixels,y1*m_width+x1,len,clr); + } +//+------------------------------------------------------------------+ +//| Draw filled triangle | +//+------------------------------------------------------------------+ +void CCanvas::FillTriangle(int x1,int y1,int x2,int y2,int x3,int y3,const uint clr) + { + int xx1,xx2,tmp; + double k1=0,k2=0,xd1,xd2; +//--- sort vertexes from lesser to greater + if(y1>y2) + { + tmp=y2; + y2 =y1; + y1 =tmp; + tmp=x2; + x2 =x1; + x1=tmp; + } + if(y1>y3) + { + tmp=y1; + y1 =y3; + y3 =tmp; + tmp=x1; + x1 =x3; + x3 =tmp; + } + if(y2>y3) + { + tmp=y2; + y2 =y3; + y3 =tmp; + tmp=x2; + x2 =x3; + x3 =tmp; + } +//--- all vertexes are out of image boundaries + if(y3<0 || y1>m_height) + return; + if(x1<0 && x2<0 && x3<0) + return; + if(x1>m_width && x2>m_width && x3>m_width) + return; +//--- find coefficients of lines + if((tmp=y1-y2)!=0) + k1=(x1-x2)/(double)tmp; + if((tmp=y1-y3)!=0) + k2=(x1-x3)/(double)tmp; +//--- + xd1=x1; + xd2=x1; +//--- + for(int i=y1;i<=y3;i++) + { + if(i==y2) + { + if((tmp=y2-y3)!=0) + k1=(x2-x3)/(double)tmp; + xd1=x2; + } + //--- calculate new boundaries of triangle line + xx1 =(int)xd1; + xd1+=k1; + xx2 =(int)xd2; + xd2+=k2; + //--- triangle line is out of screen boundaries + if(i<0 || i>=m_height) + continue; + //--- sort + if(xx1>xx2) + { + tmp=xx1; + xx1=xx2; + xx2=tmp; + } + //--- line is out of screen boundaries + if(xx2<0 || xx1>=m_width) + continue; + //--- draw only what is within screen boundaries + if(xx1<0) + xx1=0; + if(xx2>=m_width) + xx2=m_width-1; + //--- draw horizontal line of triangle + ArrayFill(m_pixels,i*m_width+xx1,xx2-xx1,clr); + } + } +//+------------------------------------------------------------------+ +//| Draw filled poligon | +//+------------------------------------------------------------------+ +void CCanvas::FillPolygon(int &x[],int &y[],const uint clr) + { + static CPoint p[]; + int total=ArraySize(x); + if(total>ArraySize(y)) + total=ArraySize(y); +//--- check + if(total<3) + return; +//--- resize array of points + ArrayResize(p,total); +//--- find top-left point + int imin=0; + int xmin=x[0]; + int ymin=y[0]; + for(int i=1;iymin) + continue; + if(y[i]==ymin) + { + if(x[i]0.0) + xx[1]=xx[3]=ix+1; + if(dy<0.0) + yy[2]=yy[2]=iy-1; + if(dy==0.0) + yy[2]=yy[2]=iy; + if(dy>0.0) + yy[2]=yy[2]=iy+1; +//--- calculate radii and sum of their squares + for(int i=0;i<4;i++) + { + dx=xx[i]-x; + dy=yy[i]-y; + rr[i]=1/(dx*dx+dy*dy); + rrr+=rr[i]; + } +//--- draw pixels + for(int i=0;i<4;i++) + { + k=rr[i]/rrr; + c=PixelGet(xx[i],yy[i]); + a=(uchar)(k*GETRGBA(clr)+(1-k)*GETRGBA(c)); + r=(uchar)(k*GETRGBR(clr)+(1-k)*GETRGBR(c)); + g=(uchar)(k*GETRGBG(clr)+(1-k)*GETRGBG(c)); + b=(uchar)(k*GETRGBB(clr)+(1-k)*GETRGBB(c)); + PixelSet(xx[i],yy[i],ARGB(a,r,g,b)); + } + } +//+------------------------------------------------------------------+ +//| Get line style | +//+------------------------------------------------------------------+ +uint CCanvas::LineStyleGet(void) const + { + switch(m_style) + { + case 0xFFFFFF: + return(STYLE_SOLID); + break; + case 0x3FFFF: + return(STYLE_DASH); + break; + case 0x1C71C7: + return(STYLE_DOT); + break; + case 0x381FF: + return(STYLE_DASHDOT); + break; + case 0x1C71FF: + return(STYLE_DASHDOTDOT); + break; + default: + return (m_style); + break; + } + } +//+------------------------------------------------------------------+ +//| Set line style | +//+------------------------------------------------------------------+ +void CCanvas::LineStyleSet(const uint style) + { + switch(style) + { + case STYLE_SOLID: + m_style=0xFFFFFF; + break; + case STYLE_DASH: + m_style=0x3FFFF; + break; + case STYLE_DOT: + m_style=0x1C71C7; + break; + case STYLE_DASHDOT: + m_style=0x381FF; + break; + case STYLE_DASHDOTDOT: + m_style=0x1C71FF; + break; + default: + //--- high-order bit must be set then custom style + if((style&0x80000000)!=0) + { + m_style=style; + } + break; + } + m_style_idx=0; + } +//+------------------------------------------------------------------+ +//| Draw line with antialiasing (with style) | +//+------------------------------------------------------------------+ +void CCanvas::LineAA(const int x1,const int y1,const int x2,const int y2,const uint clr,const uint style) + { +//--- line is out of image boundaries + if((x1<0 && x2<0) || (y1<0 && y2<0)) + return; + if(x1>=m_width && x2>=m_width) + return; + if(y1>=m_height && y2>=m_height) + return; +//--- check + if(x1==x2 && y1==y2) + { + PixelSet(x1,y1,clr); + return; + } +//--- set the line style + uint prev_style=m_style; + if(style!=UINT_MAX) + LineStyleSet(style); +//--- preliminary calculations + double dx=x2-x1; + double dy=y2-y1; + double xy=sqrt(dx*dx+dy*dy); + double xx=x1; + double yy=y1; + uint mask=1<=fabs(dx) && fabs(y2-yy)>=fabs(dy)); +//--- set last pixel + if((m_style&mask)==mask) + { + PixelSetAA(x2,y2,clr); + } +//--- set the previous line style + if(style!=UINT_MAX) + m_style=prev_style; + } +//+------------------------------------------------------------------+ +//| Draw polyline with antialiasing (with style) | +//+------------------------------------------------------------------+ +void CCanvas::PolylineAA(int &x[],int &y[],const uint clr,const uint style) + { +//--- check arrays + int total=ArraySize(x); + if(total>ArraySize(y)) + total=ArraySize(y); +//--- check + if(total<2) + return; + total--; +//--- set the line style + uint prev_style=m_style; + if(style!=UINT_MAX) + LineStyleSet(style); + uint mask=1<=m_width && x2>=m_width) + { + //--- set the previous line style + if(style!=UINT_MAX) + m_style=prev_style; + return; + } + if(y1>=m_height && y2>=m_height) + { + //--- set the previous line style + if(style!=UINT_MAX) + m_style=prev_style; + return; + } + //--- check + if(x1==x2 && y1==y2) + { + PixelSet(x1,y1,clr); + //--- set the previous line style + if(style!=UINT_MAX) + m_style=prev_style; + return; + } + //--- preliminary calculations + double dx=x2-x1; + double dy=y2-y1; + double xy=sqrt(dx*dx+dy*dy); + double xx=x1; + double yy=y1; + //--- set pixels + dx/=xy; + dy/=xy; + do + { + if((m_style&mask)==mask) + { + PixelSetAA(xx,yy,clr); + } + xx+=dx; + yy+=dy; + mask<<=1; + if(mask==0x1000000) + mask=1; + } + while(fabs(x2-xx)>=fabs(dx) && fabs(y2-yy)>=fabs(dy)); + //--- set last pixel + if((m_style&mask)==mask) + { + PixelSetAA(x2,y2,clr); + } + mask<<=1; + if(mask==0x1000000) + mask=1; + } +//--- set the previous line style + if(style!=UINT_MAX) + m_style=prev_style; + } +//+------------------------------------------------------------------+ +//| Draw polygon with antialiasing (with style) | +//+------------------------------------------------------------------+ +void CCanvas::PolygonAA(int &x[],int &y[],const uint clr,const uint style) + { +//--- check arrays + int total=ArraySize(x); + if(total>ArraySize(y)) + total=ArraySize(y); +//--- check + if(total<2) + return; +//--- set the line style + uint prev_style=m_style; + if(style!=UINT_MAX) + LineStyleSet(style); + uint mask=1<=m_width && x2>=m_width) + { + //--- set the previous line style + if(style!=UINT_MAX) + m_style=prev_style; + return; + } + if(y1>=m_height && y2>=m_height) + { + //--- set the previous line style + if(style!=UINT_MAX) + m_style=prev_style; + return; + } + //--- check + if(x1==x2 && y1==y2) + { + PixelSet(x1,y1,clr); + //--- set the previous line style + if(style!=UINT_MAX) + m_style=prev_style; + return; + } + //--- preliminary calculations + double dx=x2-x1; + double dy=y2-y1; + double xy=sqrt(dx*dx+dy*dy); + double xx=x1; + double yy=y1; + //--- set pixels + dx/=xy; + dy/=xy; + do + { + if((m_style&mask)==mask) + { + PixelSetAA(xx,yy,clr); + } + xx+=dx; + yy+=dy; + mask<<=1; + if(mask==0x1000000) + mask=1; + } + while(fabs(x2-xx)>=fabs(dx) && fabs(y2-yy)>=fabs(dy)); + //--- set last pixel + if((m_style&mask)==mask) + { + PixelSetAA(x2,y2,clr); + } + } +//--- set the previous line style + if(style!=UINT_MAX) + m_style=prev_style; + } +//+------------------------------------------------------------------+ +//| Draw triangle with antialiasing | +//+------------------------------------------------------------------+ +void CCanvas::TriangleAA(const int x1,const int y1,const int x2,const int y2,const int x3,const int y3,const uint clr,const uint style) + { +//--- draw + int x[3]; + int y[3]; + x[0] = x1; + x[1] = x2; + x[2] = x3; + y[0] = y1; + y[1] = y2; + y[2] = y3; + PolygonAA(x,y,clr,style); + } +//+------------------------------------------------------------------+ +//| Draw circle with antialiasing | +//+------------------------------------------------------------------+ +void CCanvas::CircleAA(const int x,const int y,const double r,const uint clr,const uint style=UINT_MAX) + { + if(r<=0) + return; +//--- preliminary calculations + double xx=x+r; + double yy=y; + double fi=0; + double df=M_PI_2/MathCeil(r); +//--- set the line style + uint prev_style=m_style; + if(style!=UINT_MAX) + LineStyleSet(style); + uint mask=1<M_PI) + df/=2; + do + { + xx=x+r*cos(fi); + yy=y-r*sin(fi); + if((m_style&mask)==mask) + PixelSetAA(xx,yy,clr); + mask<<=1; + if(mask==0x1000000) + mask=1; + fi+=df; + } + while(fabs(2*M_PI-fi)>=df/2); +//--- set the previous line style + if(style!=UINT_MAX) + m_style=prev_style; + } +//+------------------------------------------------------------------+ +//| Draw ellipse with antialiasing | +//+------------------------------------------------------------------+ +void CCanvas::EllipseAA(const double x1,const double y1,const double x2,const double y2,const uint clr,const uint style=UINT_MAX) + { + double rx = (x2-x1)/2; + double ry = (y2-y1)/2; +//--- preliminary calculations + double x=(x2>x1) ? x1+rx : x2+rx; + double y=(y2>y1) ? y1+ry : y2+ry; + double rx2=rx*rx; + double ry2=ry*ry; +//--- set the line style + uint prev_style=m_style; + if(style!=UINT_MAX) + LineStyleSet(style); + uint mask=1<ym) + continue; + if((p[i].y==ym) && (p[i].x>xm)) + continue; + im=i; + xm=p[i].x; + ym=p[i].y; + } +//--- check the orientation of triangle + return PointClassify(p[(im-1+total)%total],p[im],p[(im+1)%total]); + } +//+------------------------------------------------------------------+ +//| Checks convexity of polygon | +//+------------------------------------------------------------------+ +bool CCanvas::IsPolygonConvex(CPoint &p[]) + { + int total=ArraySize(p); +//--- triangle - always convex + if(total==3) + return(true); + int res=SIGN(PointClassify(p[0],p[1],p[2])); + for(int i=1;iymin) + continue; + if(p[i].y==ymin) + { + if(p[i].xp[il].y) + return; + if(yy!=p[il].y) + { + dl=(p[il].x-xl)/(p[il].y-yy); + //--- make adjustment for half of left increment dl/2 + LineHorizontal((int)MathCeil(xl+dl/2),(int)MathFloor(xl),yy,clr); + xl+=dl/2; + } + else + LineHorizontal((int)MathCeil(xl),(int)MathFloor(p[il].x),yy,clr); + } + while(yy==p[ir].y) + { + ir=(ir+1)%total; + if(yy>p[ir].y) + return; + if(yy!=p[ir].y) + { + dr=(p[ir].x-xr)/(p[ir].y-yy); + //--- make adjustment for half of right increment dr/2 + LineHorizontal((int)MathCeil(xr),(int)MathFloor(xr+dr/2),yy,clr); + xr+=dr/2; + } + else + LineHorizontal((int)MathCeil(p[ir].x),(int)MathFloor(xr),yy,clr); + } + yy++; + if(yy==p[il].y) + xl=p[il].x; + else + xl+=dl; + if(yy==p[ir].y) + xr=p[ir].x; + else + xr+=dr; + LineHorizontal((int)MathCeil(xl),(int)MathFloor(xr),yy,clr); + } + while(il>=ir && ir!=0); + } +//+------------------------------------------------------------------+ +//| Draw line according to Wu's algorithm | +//+------------------------------------------------------------------+ +void CCanvas::LineWu(int x1,int y1,int x2,int y2,const uint clr,const uint style=UINT_MAX) + { +//--- calculating the variation of the coordinates + int dx = (x2 > x1) ? (x2 - x1) : (x1 - x2); + int dy = (y2 > y1) ? (y2 - y1) : (y1 - y2); +//--- set the line style + uint prev_style=m_style; + if(style!=UINT_MAX) + LineStyleSet(style); + uint mask=1<y2) + { + tmp=y1; + y1 =y2; + y2 =tmp; + } + //--- line is out of image boundaries + if(y2<0 || y1>=m_height || x1<0 || x1>=m_width) + { + //--- set the previous line style + if(style!=UINT_MAX) + m_style=prev_style; + return; + } + //--- stay withing image boundaries + if(y1<0) + y1=0; + if(y2>=m_height-1) + y2=m_height-1; + //--- draw line + int index=y1*m_width+x1; + for(int i=y1;i<=y2;i++,index+=m_width) + { + if((m_style&mask)==mask) + m_pixels[index]=clr; + + mask<<=1; + if(mask==0x1000000) + mask=1; + } + //--- set the previous line style + if(style!=UINT_MAX) + m_style=prev_style; + //--- success + return; + } +//--- check if dy==0 then draw horizontal line + if(dy==0) + { + //--- sort by X + if(x1>x2) + { + tmp=x1; + x1 =x2; + x2 =tmp; + } + //--- line is out of image boundaries + if(x2<0 || x1>=m_width || y1<0 || y1>=m_height) + { + //--- set the previous line style + if(style!=UINT_MAX) + m_style=prev_style; + return; + } + //--- stay withing image boundaries + if(x1<0) + x1=0; + if(x2>=m_width) + x2=m_width-1; + //--- draw line + for(int i=0,index=y1*m_width+x1; i 1) + else + { + //--- first point has to have a smaller Y coordinate + if(y2ArraySize(y)) + total=ArraySize(y); +//--- check + if(total<2) + return; + total--; +//--- set the line style + uint prev_style=m_style; + if(style!=UINT_MAX) + LineStyleSet(style); + uint mask=1< x1) ? (x2 - x1) : (x1 - x2); + int dy = (y2 > y1) ? (y2 - y1) : (y1 - y2); + int tmp; + //--- check if dx==0 then draw vertical line + if(dx==0) + { + //--- sort by Y + if(y1>y2) + { + tmp=y1; + y1 =y2; + y2 =tmp; + } + //--- line is out of image boundaries + if(y2<0 || y1>=m_height || x1<0 || x1>=m_width) + continue; + //--- stay withing image boundaries + if(y1<0) + y1=0; + if(y2>=m_height-1) + y2=m_height-1; + //--- draw line + int index=y1*m_width+x1; + for(int j=y1;j<=y2;j++,index+=m_width) + { + if((m_style&mask)==mask) + m_pixels[index]=clr; + + mask<<=1; + if(mask==0x1000000) + mask=1; + } + continue; + } + //--- check if dy==0 then draw horizontal line + if(dy==0) + { + //--- sort by X + if(x1>x2) + { + tmp=x1; + x1 =x2; + x2 =tmp; + } + //--- line is out of image boundaries + if(x2<0 || x1>=m_width || y1<0 || y1>=m_height) + continue; + //--- stay withing image boundaries + if(x1<0) + x1=0; + if(x2>=m_width) + x2=m_width-1; + //--- draw line + for(int j=0,index=y1*m_width+x1; j 1) + else + { + //--- first point has to have a smaller Y coordinate + if(y2ArraySize(y)) + total=ArraySize(y); +//--- check + if(total<2) + return; +//--- set the line style + uint prev_style=m_style; + if(style!=UINT_MAX) + LineStyleSet(style); + uint mask=1< x1) ? (x2 - x1) : (x1 - x2); + int dy = (y2 > y1) ? (y2 - y1) : (y1 - y2); + int tmp; + //--- check if dx==0 then draw vertical line + if(dx==0) + { + //--- sort by Y + if(y1>y2) + { + tmp=y1; + y1 =y2; + y2 =tmp; + } + //--- line is out of image boundaries + if(y2<0 || y1>=m_height || x1<0 || x1>=m_width) + continue; + //--- stay withing image boundaries + if(y1<0) + y1=0; + if(y2>=m_height-1) + y2=m_height-1; + //--- draw line + int index=y1*m_width+x1; + for(int j=y1;j<=y2;j++,index+=m_width) + { + if((m_style&mask)==mask) + m_pixels[index]=clr; + + mask<<=1; + if(mask==0x1000000) + mask=1; + } + continue; + } + //--- check if dy==0 then draw horizontal line + if(dy==0) + { + //--- sort by X + if(x1>x2) + { + tmp=x1; + x1 =x2; + x2 =tmp; + } + //--- line is out of image boundaries + if(x2<0 || x1>=m_width || y1<0 || y1>=m_height) + continue; + //--- stay withing image boundaries + if(x1<0) + x1=0; + if(x2>=m_width) + x2=m_width-1; + //--- draw line + for(int j=0,index=y1*m_width+x1; j 1) + else + { + //--- first point has to have a smaller Y coordinate + if(y2x1) ? x1+rx : x2+rx; + int y=(y2>y1) ? y1+ry : y2+ry; + if(rx<=0 || ry<=0) + return; +//--- set the line style + uint prev_style=m_style; + if(style!=UINT_MAX) + LineStyleSet(style); + uint mask=1<0) + LineWu(x,y1,x,y2,clr,style); + return; + } +//--- r be the filter radius (and also the half-width of the wide line) + double r=(size/2.0); +//--- primary calculate + int dy=MathAbs(y2-y1); + int sign=(y10) + LineWu(x1,y,x2,y,clr,style); + return; + } +//--- r be the filter radius (and also the half-width of the wide line) + double r=(size/2.0); +//--- primary calculate + int dx=MathAbs(x2-x1); + int sign=(x10) + LineWu(x1,y1,x2,y2,clr,style); + return; + } +//--- r be the filter radius (and also the half-width of the wide line) + double r=(size/2.0); +//--- compute x and y deltas + double dx=MathAbs(x2-x1); + double dy=MathAbs(y2-y1); + if(dx==0) + { + LineThickVertical(x1,y1,y2,size,clr,style,end_style); + return; + } + if(dy==0) + { + LineThickHorizontal(x1,x2,y1,size,clr,style,end_style); + return; + } +//--- compute the linear coefficients of the two (scaled) edge functions + double k=MathArctan(dx/dy); + double rcos_k=r*cos(k); + double rsin_k=r*sin(k); +//--- set the line style + uint prev_style=m_style; + if(style!=UINT_MAX) + LineStyleSet(style); + uint mask=1<0) + PolylineWu(x,y,clr,style); + return; + } +//--- check arrays + int total=ArraySize(x); + if(total>ArraySize(y)) + total=ArraySize(y); +//--- check + if(total<2) + return; + total--; +//--- r be the filter radius (and also the half-width of the wide line) + double r=(size/2.0); +//--- + double gap=1.0; +//--- set the line style + uint prev_style=m_style; + if(style!=UINT_MAX) + LineStyleSet(style); + uint mask=1<0) + PolylineWu(x,y,clr,style); + return; + } +//--- check arrays + int total=ArraySize(x); + if(total>ArraySize(y)) + total=ArraySize(y); +//--- check + if(total<2) + return; +//--- r be the filter radius (and also the half-width of the wide line) + double r=(size/2.0); +//--- + double gap=1.0; +//--- set the line style + uint prev_style=m_style; + if(style!=UINT_MAX) + LineStyleSet(style); + uint mask=1<>16) &0xff) - + uint((clr1>>16) &0xff)); + uint dg=MathAbs(uint((clr0>>8) &0xff) - + uint((clr1>>8) &0xff)); + uint db=MathAbs(uint((clr0>>0) &0xff) - + uint((clr1>>0) &0xff)); +//--- return + return (dr<=threshould || dg<=threshould || db<=threshould); + } +//+------------------------------------------------------------------+ +//| Calculate and set new color | +//+------------------------------------------------------------------+ +void CCanvas::PixelTransform(const int x,const int y,const uint clr,const double alpha) + { + int index=y*m_width+x; +//--- check + if(x<0 || y<0 || x>m_width || y>m_height || index>=ArraySize(m_pixels)) + return; +//--- check alpha + if(alpha==1) + { + m_pixels[index]=clr; + return; + } +//--- get pixel color + uint clr0=m_pixels[index]; +//--- transform of color component for the background + double r0 = ((clr0>>16) & 0xFF) * (1.0-alpha); + double g0 = ((clr0>>8) & 0xFF) * (1.0-alpha); + double b0 = ((clr0>>0) & 0xFF) * (1.0-alpha); +//--- transform of color component + double r1 = ((clr>>16) & 0xFF) * (alpha); + double g1 = ((clr>>8) & 0xFF) * (alpha); + double b1 = ((clr>>0) & 0xFF) * (alpha); +//--- components of the new color + int r = (int)(r0+r1); + int g = (int)(g0+g1); + int b = (int)(b0+b1); +//--- set new color + m_pixels[y*m_width+x]=(r<<16|g<<8|b<<0|255<<24) &0xffffffff; + } +//+------------------------------------------------------------------+ +//| Draw 4 pixel with PixelTransform method | +//+------------------------------------------------------------------+ +void CCanvas::PixelTransform4(const int x,const int y,const int dx,const int dy,const uint clr,const double alpha) + { + PixelTransform(x+dx,y+dy,clr,alpha); + PixelTransform(x-dx,y+dy,clr,alpha); + PixelTransform(x+dx,y-dy,clr,alpha); + PixelTransform(x-dx,y-dy,clr,alpha); + } +//+------------------------------------------------------------------+ +//| Draw 4 pixel with antialiasing | +//+------------------------------------------------------------------+ +void CCanvas::PixelSet4AA(const double x,const double y,const double dx,const double dy,const uint clr) + { + PixelSetAA(x+dx,y+dy,clr); + PixelSetAA(x-dx,y+dy,clr); + PixelSetAA(x+dx,y-dy,clr); + PixelSetAA(x-dx,y-dy,clr); + } +//+------------------------------------------------------------------+ +//| Draw solid segment for vertical thick line | +//+------------------------------------------------------------------+ +void CCanvas::SegmentVertical(const int x,const int y1,const int y2,const int ysign,const double r,const uint clr,ENUM_LINE_END end_style) + { +//--- compute the constol points of the solid segment + int ye1,ye2; + int ys1,ys2; + switch(end_style) + { + case LINE_END_ROUND: + { + ye1=y1; + ye2=y2; + ys1=y1-(int)(ysign*r); + ys2=y2+(int)(ysign*r); + break; + } + case LINE_END_BUTT: + { + ye1=y1; + ye2=y2; + ys1=y1; + ys2=y2; + break; + } + case LINE_END_SQUARE: + { + ye1=y1-(int)(ysign*r); + ye2=y2+(int)(ysign*r); + ys1=ye1; + ys2=ye2; + break; + } + default: + return; + }; +//--- darw solid segment + for(int i=0; i<=MathAbs(ys2-ys1); i++) + { + double yi=ys1+(ysign*i); + for(int j=0; j<2*r; j++) + { + double xi=x-r+j; + double dist=DistancePointSegment(xi,yi,x,ye1,x,ye2); + double val=MathAbs(dist/r); + PixelTransform((int)xi,(int)yi,clr,FilterFunction(val)); + } + } + } +//+------------------------------------------------------------------+ +//| Draw solid segment for horizontal thick line | +//+------------------------------------------------------------------+ +void CCanvas::SegmentHorizontal(const int x1,const int x2,const int y,const int xsign,const double r,const uint clr,ENUM_LINE_END end_style) + { +//--- compute the constol points of the solid segment + int xe1,xe2; + int xs1,xs2; + switch(end_style) + { + case LINE_END_ROUND: + { + xe1=x1; + xe2=x2; + xs1=x1-(int)(xsign*r); + xs2=x2+(int)(xsign*r); + break; + } + case LINE_END_BUTT: + { + xe1=x1; + xe2=x2; + xs1=x1; + xs2=x2; + break; + } + case LINE_END_SQUARE: + { + xe1=x1-(int)(xsign*r); + xe2=x2+(int)(xsign*r); + xs1=xe1; + xs2=xe2; + break; + } + default: + return; + }; +//--- draw solid segment + for(int i=0; i<=MathAbs(xs2-xs1); i++) + { + double xi=xs1+(xsign*i); + for(int j=0; j<2*r; j++) + { + double yi=y-r+j; + double dist=DistancePointSegment(xi,yi,xe1,y,xe2,y); + double val=MathAbs(dist/r); + PixelTransform((int)xi,(int)yi,clr,FilterFunction(val)); + } + } + } +//+------------------------------------------------------------------+ +//| Draw solid segment for thick line | +//+------------------------------------------------------------------+ +void CCanvas::Segment(const int x1,const int y1,const int x2,const int y2,const double kp0,const double kp1,const int xsign,const int ysign, + const double rcos_k,const double rsin_k,const double r,const uint clr,ENUM_LINE_END end_style) + { + if(x1==x2 && y1==y2) + return; + if(x1==x2) + { + SegmentVertical(x1,y1,y2,ysign,r,clr,end_style); + return; + } + if(y1==y2) + { + SegmentHorizontal(x1,x2,y1,xsign,r,clr,end_style); + return; + } +//--- compute the constol points of the solid segment + int xe1,ye1,xe2,ye2; + int xs1,ys1,xs2,ys2; + switch(end_style) + { + case LINE_END_ROUND: + { + xe1=x1; + ye1=y1; + xe2=x2; + ye2=y2; + xs1=x1-(xsign)*(int)(rsin_k); + ys1=y1-(ysign)*(int)(rcos_k); + xs2=x2+(xsign)*(int)(rsin_k); + ys2=y2+(ysign)*(int)(rcos_k); + break; + } + case LINE_END_BUTT: + { + xe1=x1; + ye1=y1; + xe2=x2; + ye2=y2; + xs1=x1; + ys1=y1; + xs2=x2; + ys2=y2; + break; + } + case LINE_END_SQUARE: + { + xe1=x1-(xsign)*(int)(rsin_k); + ye1=y1-(ysign)*(int)(rcos_k); + xe2=x2+(xsign)*(int)(rsin_k); + ye2=y2+(ysign)*(int)(rcos_k); + xs1=xe1; + ys1=ye1; + xs2=xe2; + ys2=ye2; + break; + } + default: + return; + }; +//--- compute the four corners of the wide line + double p0x=xs1+(xsign)*(rcos_k); + double p0y=ys1-(ysign)*(rsin_k); + double p1x=xs1-(xsign)*(rcos_k); + double p1y=ys1+(ysign)*(rsin_k); + double p2x=xs2+(xsign)*(rcos_k); + double p2y=ys2-(ysign)*(rsin_k); + double p3x=xs2-(xsign)*(rcos_k); + double p3y=ys2+(ysign)*(rsin_k); +//--- draw solid segment + if(MathAbs(kp0)>=1) + { + double xi0,xi1; + double height=MathAbs(p3y-p0y); + for(int i=0; i<=height; i++) + { + double y=p0y+(ysign*i); + double xi00 = MathRound(p0x + (y-p0y)/kp0); + double xi01 = MathRound(p1x + (y-p1y)/kp1); + double xi02 = MathRound(p2x + (y-p2y)/kp1); + double xi03 = MathRound(p3x + (y-p3y)/kp0); + if(xsign==1) + { + xi0 = MathMax(xi00,xi01); + xi1 = MathMin(xi02,xi03); + } + else + { + xi0 = MathMin(xi00,xi01); + xi1 = MathMax(xi02,xi03); + } + double width=MathAbs(MathRound(xi1-xi0)); + for(int j=0; j<=width; j++) + { + double xi=xi0+(xsign*j); + double dist=DistancePointSegment(xi,y,xe1,ye1,xe2,ye2); + double val = MathAbs(dist/r); + PixelTransform((int)xi,(int)y,clr,FilterFunction(val)); + } + } + } + else + { + double yi0,yi1; + double width=MathAbs(p2x-p1x); + for(int i=0; i<=width; i++) + { + double x=p1x+(xsign*i); + double yi00 = MathRound(p0y + (x-p0x)*kp0); + double yi01 = MathRound(p1y + (x-p1x)*kp1); + double yi02 = MathRound(p2y + (x-p2x)*kp1); + double yi03 = MathRound(p3y + (x-p3x)*kp0); + if(ysign==1) + { + yi0 = MathMax(yi00,yi02); + yi1 = MathMin(yi01,yi03); + } + else + { + yi0 = MathMin(yi00,yi02); + yi1 = MathMax(yi01,yi03); + } + double height=MathAbs(yi1-yi0); + for(int j=0; j<=height; j++) + { + double yi=yi0+(ysign*j); + double dist=DistancePointSegment(x,yi,xe1,ye1,xe2,ye2); + double val=MathAbs(dist/r); + PixelTransform((int)x,(int)yi,clr,FilterFunction(val)); + } + } + } + } +//+------------------------------------------------------------------+ +//| Filter function for calculating alpha channel | +//+------------------------------------------------------------------+ +double CCanvas::FilterFunction(const double x) + { + if(x<=0.8) + return(1.0); + else + return MathExp(-(x-0.8)*(x-0.8)*50); + } +//+------------------------------------------------------------------+ +//| Calculate distance between point and segment | +//+------------------------------------------------------------------+ +double CCanvas::DistancePointSegment(const double px,const double py,const double x1,const double y1,const double x2,const double y2) + { +//--- primary calculate + double a=(px-x1)*(px-x1)+(py-y1)*(py-y1); + double b=(px-x2)*(px-x2)+(py-y2)*(py-y2); + double c=(x2-x1)*(x2-x1)+(y2-y1)*(y2-y1); +//--- check + if(a>=b+c) + return (MathSqrt(b)); + if(b>=a+c) + return (MathSqrt(a)); +//--- calculate distance + a=MathSqrt(a); + b=MathSqrt(b); + c=MathSqrt(c); + double p=(a+b+c)/2; + double s=MathSqrt((p-a)*(p-b)*(p-c)*p); +//--- check distance + if(MathIsValidNumber(s)) + return(s*2.0/c); + else + return(0); + } +//+------------------------------------------------------------------+ +//| Draw smothing polyline | +//+------------------------------------------------------------------+ +void CCanvas::PolylineSmooth(const int &x[],const int &y[],const uint clr,const int size,ENUM_LINE_STYLE style=STYLE_SOLID, + ENUM_LINE_END end_style=LINE_END_ROUND,double tension=0.5,double step=10) + { +//--- + int arr_size= ArraySize(x); + if(arr_size!=ArraySize(y)) + return; +//--- + double x1,x2,y1,y2; + tension*=0.3; +//--- coordinates of Bezier curve + int xc[]; + int yc[]; +//--- initialize control points + double ptX[]; + double ptY[]; + int size_pt=arr_size*3-2; + + ArrayResize(ptX,size_pt); + ArrayResize(ptY,size_pt); +//--- calculation of control points + CalcCurveBezierEndp(x[0],y[0],x[1],y[1],tension,x1,y1); + + ptX[0] = x[0]; + ptY[0] = y[0]; + ptX[1] = x1; + ptY[1] = y1; + + for(int i=0; i0.0) ?(int)(distance/step) : 1; + if(size_i<1) + size_i=2; + ArrayResize(xc,ArraySize(xc)+size_i,1024); + ArrayResize(yc,ArraySize(yc)+size_i,1024); + for(int t=0; t0.0) ?(int)(distance/step) : 1; + if(size_i<1) + size_i=2; + ArrayResize(xc,ArraySize(xc)+size_i,1024); + ArrayResize(yc,ArraySize(yc)+size_i,1024); + for(int t=0; t0.0) ?(int)(distance/step) : 1; + if(size_i<1) + size_i=2; + ArrayResize(xc,ArraySize(xc)+size_i,1024); + ArrayResize(yc,ArraySize(yc)+size_i,1024); + for(int t=0; t +#include +#include +//--- enumerations +enum ENUM_SHOW_FLAGS + { + FLAG_SHOW_NONE =0, + FLAG_SHOW_LEGEND =1, + FLAG_SHOW_SCALE_LEFT =2, + FLAG_SHOW_SCALE_RIGHT =4, + FLAG_SHOW_SCALE_TOP =8, + FLAG_SHOW_SCALE_BOTTOM=16, + FLAG_SHOW_GRID =32, + FLAG_SHOW_DESCRIPTORS =64, + FLAG_SHOW_VALUE =128, + FLAG_SHOW_PERCENT =256, + FLAGS_SHOW_SCALES =(FLAG_SHOW_SCALE_LEFT+FLAG_SHOW_SCALE_RIGHT+ + FLAG_SHOW_SCALE_TOP+FLAG_SHOW_SCALE_BOTTOM), + FLAGS_SHOW_ALL =(FLAG_SHOW_LEGEND+FLAGS_SHOW_SCALES+FLAG_SHOW_GRID+ + FLAG_SHOW_DESCRIPTORS+FLAG_SHOW_VALUE+FLAG_SHOW_PERCENT) + }; +enum ENUM_ALIGNMENT + { + ALIGNMENT_LEFT = 1, // align by left border + ALIGNMENT_TOP = 2, // align by top border + ALIGNMENT_RIGHT = 4, // align by right border + ALIGNMENT_BOTTOM = 8 // align by bottom border + }; +//--- macro +#define IS_SHOW_LEGEND ((m_show_flags&FLAG_SHOW_LEGEND) !=0) +#define IS_SHOW_SCALES ((m_show_flags&FLAGS_SHOW_SCALES) !=0) +#define IS_SHOW_SCALE_LEFT ((m_show_flags&FLAG_SHOW_SCALE_LEFT) !=0) +#define IS_SHOW_SCALE_RIGHT ((m_show_flags&FLAG_SHOW_SCALE_RIGHT) !=0) +#define IS_SHOW_SCALE_TOP ((m_show_flags&FLAG_SHOW_SCALE_TOP) !=0) +#define IS_SHOW_SCALE_BOTTOM ((m_show_flags&FLAG_SHOW_SCALE_BOTTOM)!=0) +#define IS_SHOW_GRID ((m_show_flags&FLAG_SHOW_GRID) !=0) +#define IS_SHOW_DESCRIPTORS ((m_show_flags&FLAG_SHOW_DESCRIPTORS) !=0) +#define IS_SHOW_VALUE ((m_show_flags&FLAG_SHOW_VALUE) !=0) +#define IS_SHOW_PERCENT ((m_show_flags&FLAG_SHOW_PERCENT) !=0) +//+------------------------------------------------------------------+ +//| Class CChartCanvas | +//| Usage: base class for graphical charts | +//+------------------------------------------------------------------+ +class CChartCanvas : public CCanvas + { +protected: + //--- colors + uint m_color_background; + uint m_color_border; + uint m_color_text; + uint m_color_grid; + //--- adjusted parameters + uint m_max_data; + uint m_max_descr_len; + uint m_allowed_show_flags; + uint m_show_flags; + ENUM_ALIGNMENT m_legend_alignment; + uint m_threshold_drawing; + bool m_accumulative; + //--- parameters for scales and grid + double m_v_scale_min; + double m_v_scale_max; + uint m_num_grid; + int m_scale_digits; + //--- data + int m_data_offset; + uint m_data_total; + CArray *m_data; + CArrayInt m_colors; + CArrayString m_descriptors; + //--- + CArrayInt m_index; + uint m_index_size; + double m_sum; + double m_others; + uint m_max_descr_width; + uint m_max_value_width; + //--- variables + CRect m_data_area; + //--- variables for scaling and scales + double m_scale_x; + int m_x_min; + int m_x_0; + int m_x_max; + int m_dx_grid; + double m_scale_y; + int m_y_min; + int m_y_0; + int m_y_max; + int m_dy_grid; + string m_scale_text[]; + +public: + CChartCanvas(void); + ~CChartCanvas(void); + //--- create + virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA); + //--- colors + uint ColorBackground(void) const { return(m_color_background); } + void ColorBackground(const uint value); + uint ColorBorder(void) const { return(m_color_border); } + void ColorBorder(const uint value); + uint ColorText(void) const { return(m_color_text); } + void ColorText(const uint value); + uint ColorGrid(void) const { return(m_color_grid); } + void ColorGrid(const uint value) { m_color_grid=value; } + //--- adjusted parameters + uint MaxData(void) const { return(m_max_data); } + void MaxData(const uint value); + uint MaxDescrLen(void) const { return(m_max_descr_len); } + void MaxDescrLen(const uint value); + //--- show flags + void AllowedShowFlags(const uint flags); + bool ShowFlags(void) const { return(m_show_flags); } + void ShowFlags(const uint flags); + bool IsShowLegend(void) const { return(IS_SHOW_LEGEND); } + bool IsShowScaleLeft(void) const { return(IS_SHOW_SCALE_LEFT); } + bool IsShowScaleRight(void) const { return(IS_SHOW_SCALE_RIGHT); } + bool IsShowScaleTop(void) const { return(IS_SHOW_SCALE_TOP); } + bool IsShowScaleBottom(void) const { return(IS_SHOW_SCALE_BOTTOM); } + bool IsShowGrid(void) const { return(IS_SHOW_GRID); } + bool IsShowDescriptors(void) const { return(IS_SHOW_DESCRIPTORS); } + bool IsShowPercent(void) const { return(IS_SHOW_PERCENT); } + void ShowLegend(const bool flag=true); + void ShowScaleLeft(const bool flag=true); + void ShowScaleRight(const bool flag=true); + void ShowScaleTop(const bool flag=true); + void ShowScaleBottom(const bool flag=true); + void ShowGrid(const bool flag=true); + void ShowDescriptors(const bool flag=true); + void ShowValue(const bool flag=true); + void ShowPercent(const bool flag=true); + void LegendAlignment(const ENUM_ALIGNMENT value); + void Accumulative(const bool flag=true); + //--- for scales and grid + double VScaleMin(void) const { return(m_v_scale_min); } + void VScaleMin(const double value); + double VScaleMax(void) const { return(m_v_scale_max); } + void VScaleMax(const double value); + uint NumGrid(void) const { return(m_num_grid); } + void NumGrid(const uint value); + void VScaleParams(const double max,const double min,const uint grid); + //--- state + int DataOffset(void) const { return(m_data_offset); } + void DataOffset(const int value); + //--- data + uint DataTotal(void) const { return(m_data_total); } + bool DescriptorUpdate(const uint pos,const string descr); + bool ColorUpdate(const uint pos,const uint clr); + +protected: + virtual void ValuesCheck(void); + virtual void Redraw(void); + virtual void DrawBackground(void); + virtual void DrawLegend(void); + int DrawLegendVertical(const int w,const int h); + int DrawLegendHorizontal(const int w,const int h); + virtual void CalcScales(void); + virtual void DrawScales(void); + virtual int DrawScaleLeft(const bool draw=true); + virtual int DrawScaleRight(const bool draw=true); + virtual int DrawScaleTop(const bool draw=true); + virtual int DrawScaleBottom(const bool draw=true); + virtual void DrawGrid(void); + virtual void DrawDescriptors(void) {} + virtual void DrawChart(void); + virtual void DrawData(const uint idx=0) {} + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CChartCanvas::CChartCanvas(void) : m_color_background(XRGB(0xFF,0xFF,0xFF)), + m_color_border(XRGB(0x9F,0x9F,0x9F)), + m_color_text(XRGB(0x3F,0x3F,0x3F)), + m_color_grid(XRGB(0xCF,0xCF,0xCF)), + m_max_data(10), + m_max_descr_len(10), + m_allowed_show_flags(FLAGS_SHOW_ALL), + m_show_flags(FLAG_SHOW_NONE), + m_legend_alignment(ALIGNMENT_BOTTOM), + m_threshold_drawing(2), + m_accumulative(false), + m_data_offset(0), + m_data_total(0), + m_data(NULL), + m_v_scale_min(0.0), + m_v_scale_max(10.0), + m_num_grid(5), + m_scale_digits(0) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CChartCanvas::~CChartCanvas(void) + { + if(m_data!=NULL) + delete m_data; + } +//+------------------------------------------------------------------+ +//| Create dynamic resource | +//+------------------------------------------------------------------+ +bool CChartCanvas::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt) + { +//--- call method of parent class + if(!CCanvas::Create(name,width,height,clrfmt)) + return(false); +//--- set font + FontSet("Tahoma",-100); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Sets background color | +//+------------------------------------------------------------------+ +void CChartCanvas::ColorBackground(const uint value) + { + m_color_background=value; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets border color | +//+------------------------------------------------------------------+ +void CChartCanvas::ColorBorder(const uint value) + { + m_color_border=value; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets text color | +//+------------------------------------------------------------------+ +void CChartCanvas::ColorText(const uint value) + { + m_color_text=value; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets maximum amount of data | +//+------------------------------------------------------------------+ +void CChartCanvas::MaxData(const uint value) + { +//--- check + if((value==0) || (m_data_total==value)) + return; +//--- save + m_max_data=value; + if(m_data_total>m_max_data) + { + m_data_total=value; + m_colors.Resize(value); + m_descriptors.Resize(value); + } + } +//+------------------------------------------------------------------+ +//| Sets maximum length of descriptor | +//+------------------------------------------------------------------+ +void CChartCanvas::MaxDescrLen(const uint value) + { + m_max_descr_len=value; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets allowed visibility flags | +//+------------------------------------------------------------------+ +void CChartCanvas::AllowedShowFlags(const uint flags) + { + m_allowed_show_flags=flags; + m_show_flags&=m_allowed_show_flags; + } +//+------------------------------------------------------------------+ +//| Sets visibility flags | +//+------------------------------------------------------------------+ +void CChartCanvas::ShowFlags(const uint flags) + { + m_show_flags=flags&m_allowed_show_flags; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets visibility flag for "legend" | +//+------------------------------------------------------------------+ +void CChartCanvas::ShowLegend(const bool flag) + { + if((m_allowed_show_flags&FLAG_SHOW_LEGEND)!=0) + { + if(flag) + m_show_flags|=FLAG_SHOW_LEGEND; + else + m_show_flags&=~FLAG_SHOW_LEGEND; + //--- redraw + if(m_data_total>0) + Redraw(); + } + } +//+------------------------------------------------------------------+ +//| Sets visibility flag for left scale | +//+------------------------------------------------------------------+ +void CChartCanvas::ShowScaleLeft(const bool flag) + { + if((m_allowed_show_flags&FLAG_SHOW_SCALE_LEFT)!=0) + { + if(flag) + m_show_flags|=FLAG_SHOW_SCALE_LEFT; + else + m_show_flags&=~FLAG_SHOW_SCALE_LEFT; + //--- redraw + if(m_data_total>0) + Redraw(); + } + } +//+------------------------------------------------------------------+ +//| Sets visibility flag for right scale | +//+------------------------------------------------------------------+ +void CChartCanvas::ShowScaleRight(const bool flag) + { + if((m_allowed_show_flags&FLAG_SHOW_SCALE_RIGHT)!=0) + { + if(flag) + m_show_flags|=FLAG_SHOW_SCALE_RIGHT; + else + m_show_flags&=~FLAG_SHOW_SCALE_RIGHT; + //--- redraw + if(m_data_total>0) + Redraw(); + } + } +//+------------------------------------------------------------------+ +//| Sets visibility flag for top scale | +//+------------------------------------------------------------------+ +void CChartCanvas::ShowScaleTop(const bool flag) + { + if((m_allowed_show_flags&FLAG_SHOW_SCALE_TOP)!=0) + { + if(flag) + m_show_flags|=FLAG_SHOW_SCALE_TOP; + else + m_show_flags&=~FLAG_SHOW_SCALE_TOP; + //--- redraw + if(m_data_total>0) + Redraw(); + } + } +//+------------------------------------------------------------------+ +//| Sets visibility flag for bottom scale | +//+------------------------------------------------------------------+ +void CChartCanvas::ShowScaleBottom(const bool flag) + { + if((m_allowed_show_flags&FLAG_SHOW_SCALE_BOTTOM)!=0) + { + if(flag) + m_show_flags|=FLAG_SHOW_SCALE_BOTTOM; + else + m_show_flags&=~FLAG_SHOW_SCALE_BOTTOM; + //--- redraw + if(m_data_total>0) + Redraw(); + } + } +//+------------------------------------------------------------------+ +//| Sets visibility flag for grid | +//+------------------------------------------------------------------+ +void CChartCanvas::ShowGrid(const bool flag) + { + if((m_allowed_show_flags&FLAG_SHOW_GRID)!=0) + { + if(flag) + m_show_flags|=FLAG_SHOW_GRID; + else + m_show_flags&=~FLAG_SHOW_GRID; + //--- redraw + if(m_data_total>0) + Redraw(); + } + } +//+------------------------------------------------------------------+ +//| Sets visibility flag for descriptors | +//+------------------------------------------------------------------+ +void CChartCanvas::ShowDescriptors(const bool flag) + { + if((m_allowed_show_flags&FLAG_SHOW_DESCRIPTORS)!=0) + { + if(flag) + m_show_flags|=FLAG_SHOW_DESCRIPTORS; + else + m_show_flags&=~FLAG_SHOW_DESCRIPTORS; + //--- redraw + if(m_data_total>0) + Redraw(); + } + } +//+------------------------------------------------------------------+ +//| Sets visibility flag for value | +//+------------------------------------------------------------------+ +void CChartCanvas::ShowValue(const bool flag) + { + if((m_allowed_show_flags&FLAG_SHOW_VALUE)!=0) + { + if(flag) + { + m_show_flags|=FLAG_SHOW_VALUE; + m_show_flags&=~FLAG_SHOW_PERCENT; + } + else + m_show_flags&=~FLAG_SHOW_VALUE; + //--- redraw + if(m_data_total>0) + Redraw(); + } + } +//+------------------------------------------------------------------+ +//| Sets visibility flag for percentage | +//+------------------------------------------------------------------+ +void CChartCanvas::ShowPercent(const bool flag) + { + if((m_allowed_show_flags&FLAG_SHOW_PERCENT)!=0) + { + if(flag) + { + m_show_flags|=FLAG_SHOW_PERCENT; + m_show_flags&=~FLAG_SHOW_VALUE; + } + else + m_show_flags&=~FLAG_SHOW_PERCENT; + //--- redraw + if(m_data_total>0) + Redraw(); + } + } +//+------------------------------------------------------------------+ +//| Sets legend alignment | +//+------------------------------------------------------------------+ +void CChartCanvas::LegendAlignment(const ENUM_ALIGNMENT value) + { + m_legend_alignment=value; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets accumulative flag | +//+------------------------------------------------------------------+ +void CChartCanvas::Accumulative(const bool flag=true) + { + m_accumulative=flag; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets lower limit for vertical scale | +//+------------------------------------------------------------------+ +void CChartCanvas::VScaleMin(const double value) + { +//--- check + if(value==m_v_scale_max) + return; +//--- save + m_v_scale_min=value; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets upper limit for vertical scale | +//+------------------------------------------------------------------+ +void CChartCanvas::VScaleMax(const double value) + { + if(value==m_v_scale_min) + return; +//--- save + m_v_scale_max=value; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets number of vertical scale divisions | +//+------------------------------------------------------------------+ +void CChartCanvas::NumGrid(const uint value) + { +//--- check + if(value==0) + return; +//--- save + m_num_grid=value; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets parameters for vertical scale | +//+------------------------------------------------------------------+ +void CChartCanvas::VScaleParams(const double max,const double min,const uint grid) + { +//--- check + if(grid==0) + return; + if(max<=min) + return; +//--- save + m_v_scale_max=max; + m_v_scale_min=min; + m_num_grid =grid; +//--- redraw + if(m_data_total>0) + Redraw(); + } +//+------------------------------------------------------------------+ +//| Sets data offset | +//+------------------------------------------------------------------+ +void CChartCanvas::DataOffset(const int value) + { + m_data_offset=value; +//--- redraw + Redraw(); + } +//+------------------------------------------------------------------+ +//| Updates parameter descriptor only (in specified position) | +//+------------------------------------------------------------------+ +bool CChartCanvas::DescriptorUpdate(const uint pos,const string descr) + { +//--- update + if(descr!=NULL && !m_descriptors.Update(pos,descr)) + return(false); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Updates parameter color only (in specified position) | +//+------------------------------------------------------------------+ +bool CChartCanvas::ColorUpdate(const uint pos,const uint clr) + { +//--- update + if(clr!=0 && !m_colors.Update(pos,clr)) + return(false); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Checks values for insignificance | +//+------------------------------------------------------------------+ +void CChartCanvas::ValuesCheck(void) + { + string text; + uint w,h; +//--- clear + m_max_value_width=0; + m_sum =0; + m_others =0; + m_index_size =0; + m_index.Clear(); +//--- check + if(m_data==NULL) + return; + if(m_data.Type()==TYPE_DOUBLE) + { + //--- single-series chart + //--- calculate sum of all values + for(uint i=0;im_height) + { + cols++; + rows=(int)m_index_size/cols; + if((int)m_index_size%cols!=0) + rows++; + } +//--- draw + int x0=(m_legend_alignment==ALIGNMENT_RIGHT) ? width-w*cols+h : h; + int x=0; + int y =-h/2; + int i; + if(m_data_total==m_index_size) + { + for(i=0;i<(int)m_data_total;i++,x+=w) + { + if(i%cols==0) + { + x=x0; + y+=dy; + } + FillRectangle(x,y,x+h,y+h,(uint)m_colors[i]); + TextOut(x+h,y," - "+m_descriptors[i],m_color_text); + } + } + else + { + for(i=0;i<(int)m_index_size;i++,x+=w) + { + int index=m_index[i]; + if(i%cols==0) + { + x=x0; + y+=dy; + } + FillRectangle(x,y,x+h,y+h,(uint)m_colors[index]); + TextOut(x+h,y," - "+m_descriptors[index],m_color_text); + } + if(i%cols==0) + { + x=x0; + y+=dy; + } + FillRectangle(x,y,x+h,y+h,COLOR2RGB(clrBlack)); + TextOut(x+h,y," - Others",m_color_text); + } +//--- width + return(w*cols); + } +//+------------------------------------------------------------------+ +//| Draw horizontal "legend" | +//+------------------------------------------------------------------+ +int CChartCanvas::DrawLegendHorizontal(const int w,const int h) + { + int width =m_data_area.Width(); + int height=m_data_area.Height(); + int rows =1; + int cols =(int)m_index_size; +//--- calculate + while(w*cols>m_width) + { + rows++; + cols=(int)m_index_size/rows; + if((int)m_index_size%rows!=0) + cols++; + } +//--- draw + int dx=width/(cols+1); + int x =dx-w/2+h; + int dy=(int)(1.5*h); + int y =(m_legend_alignment==ALIGNMENT_BOTTOM) ? height-dy*(rows+1) : -h/2; + int i; + if(m_data_total==m_index_size) + { + for(i=0;i<(int)m_data_total;i++,x+=dx) + { + if(i%cols==0) + { + x=dx-w/2+h; + y+=dy; + } + FillRectangle(x,y,x+h,y+h,(uint)m_colors[i]); + TextOut(x+h,y," - "+m_descriptors[i],m_color_text); + } + } + else + { + for(i=0;i<(int)m_index_size;i++,x+=dx) + { + int index=m_index[i]; + if(i%cols==0) + { + x=dx-w/2+h; + y+=dy; + } + FillRectangle(x,y,x+h,y+h,(uint)m_colors[index]); + TextOut(x+h,y," - "+m_descriptors[index],m_color_text); + } + if(i%cols==0) + { + x=dx-w/2+h; + y+=dy; + } + FillRectangle(x,y,x+h,y+h,COLOR2RGB(clrBlack)); + TextOut(x+h,y," - Others",m_color_text); + } +//--- height + return(dy*(rows+1)); + } +//+------------------------------------------------------------------+ +//| Calculates coordinates of scales | +//+------------------------------------------------------------------+ +void CChartCanvas::CalcScales(void) + { + int width =m_data_area.Width(); + int height=m_data_area.Height(); +//--- limits + m_y_max=m_data_area.top+DrawScaleTop(false); + m_y_min=m_data_area.bottom-DrawScaleBottom(false); +//--- additional + m_dy_grid=(int)((m_y_min-m_y_max)/m_num_grid); + m_y_max+=(int)(((m_y_min-m_y_max)-m_dy_grid*m_num_grid)/2); + m_y_min=(int)(m_y_max+m_dy_grid*m_num_grid); +//--- normalize + if(m_v_scale_min>=0.0) + m_y_0=m_y_min; + else + { + if(m_v_scale_max<=0.0) + m_y_0=m_y_max; + else + m_y_0=(int)(m_y_max+(m_y_min-m_y_max)*m_v_scale_max/(m_v_scale_max-m_v_scale_min)); + } +//--- scale + m_scale_y=(m_v_scale_max!=m_v_scale_min) ? (m_y_min-m_y_max)/(m_v_scale_max-m_v_scale_min) : 1; +//--- labels on scale + if(ArraySize(m_scale_text)!=m_num_grid+1 && ArrayResize(m_scale_text,m_num_grid+1)==-1) + return; + double val=m_v_scale_min; + double dval=(m_v_scale_max-m_v_scale_min)/m_num_grid; + for(uint i=0;i<=m_num_grid;i++,val+=dval) + m_scale_text[i]=DoubleToString(val,m_scale_digits); + } +//+------------------------------------------------------------------+ +//| Redraws scales | +//+------------------------------------------------------------------+ +void CChartCanvas::DrawScales(void) + { +//--- recalculate + CalcScales(); +//--- redraw scales + if(IS_SHOW_SCALE_LEFT) + DrawScaleLeft(); + if(IS_SHOW_SCALE_RIGHT) + DrawScaleRight(); + if(IS_SHOW_SCALE_TOP) + DrawScaleTop(); + if(IS_SHOW_SCALE_BOTTOM) + DrawScaleBottom(); + } +//+------------------------------------------------------------------+ +//| Redraws left scale | +//+------------------------------------------------------------------+ +int CChartCanvas::DrawScaleLeft(const bool draw) + { +//--- check flag + if(!IS_SHOW_SCALE_LEFT) + return(0); +//--- variables + int x1=m_data_area.left; + int x2; + int y=m_y_min; +//--- calculate scale width + int size=0; + for(uint i=0;i<=m_num_grid;i++) + { + if(size +//+------------------------------------------------------------------+ +//| Class CHistogramChart | +//| Usage: generates histogram chart | +//+------------------------------------------------------------------+ +class CHistogramChart : public CChartCanvas + { +private: + //--- colors + uint m_fill_brush[]; + //--- adjusted parameters + bool m_gradient; + uint m_bar_gap; + uint m_bar_min_size; + uint m_bar_border; + //--- data + CArrayObj *m_values; + +public: + CHistogramChart(void); + ~CHistogramChart(void); + //--- create + virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_ARGB_NORMALIZE); + //--- adjusted parameters + void Gradient(const bool flag=true) { m_gradient=flag; } + void BarGap(const uint value) { m_bar_gap=value; } + void BarMinSize(const uint value) { m_bar_min_size=value; } + void BarBorder(const uint value) { m_bar_border=value; } + //--- data + bool SeriesAdd(const double &value[],const string descr="",const uint clr=0); + bool SeriesInsert(const uint pos,const double &value[],const string descr="",const uint clr=0); + bool SeriesUpdate(const uint pos,const double &value[],const string descr=NULL,const uint clr=0); + bool SeriesDelete(const uint pos); + bool ValueUpdate(const uint series,const uint pos,double value); + +protected: + virtual void DrawData(const uint idx); + void DrawBar(const int x,const int y,const int w,const int h,const uint clr); + void GradientBrush(const int size,const uint fill_clr); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CHistogramChart::CHistogramChart(void) : m_gradient(true), + m_bar_gap(3), + m_bar_min_size(5), + m_bar_border(0) + { + ShowFlags(FLAG_SHOW_LEGEND|FLAGS_SHOW_SCALES|FLAG_SHOW_GRID); + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CHistogramChart::~CHistogramChart(void) + { + if(ArraySize(m_fill_brush)!=0) + ArrayFree(m_fill_brush); + } +//+------------------------------------------------------------------+ +//| Create dynamic resource | +//+------------------------------------------------------------------+ +bool CHistogramChart::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt) + { +//--- create object to store data + if((m_values=new CArrayObj)==NULL) + return(false); +//--- pass responsibility for its destruction to the parent class + m_data=m_values; +//--- call method of parent class + if(!CChartCanvas::Create(name,width,height,clrfmt)) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Adds data series | +//+------------------------------------------------------------------+ +bool CHistogramChart::SeriesAdd(const double &value[],const string descr,const uint clr) + { +//--- check + if(m_data_total==m_max_data) + return(false); +//--- add + CArrayDouble *arr=new CArrayDouble; + if(!m_values.Add(arr)) + return(false); + if(!arr.AssignArray(value)) + return(false); + if(!m_colors.Add((clr==0) ? GetDefaultColor(m_data_total) : clr)) + return(false); + if(!m_descriptors.Add(descr)) + return(false); + m_data_total++; +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Inserts data series | +//+------------------------------------------------------------------+ +bool CHistogramChart::SeriesInsert(const uint pos,const double &value[],const string descr,const uint clr) + { +//--- check + if(m_data_total==m_max_data) + return(false); + if(pos>=m_data_total) + return(false); +//--- insert + CArrayDouble *arr=new CArrayDouble; + if(!m_values.Insert(arr,pos)) + return(false); + if(!arr.AssignArray(value)) + return(false); + if(!m_colors.Insert((clr==0) ? GetDefaultColor(m_data_total) : clr,pos)) + return(false); + if(!m_descriptors.Insert(descr,pos)) + return(false); + m_data_total++; +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Updates data series | +//+------------------------------------------------------------------+ +bool CHistogramChart::SeriesUpdate(const uint pos,const double &value[],const string descr,const uint clr) + { +//--- check + if(pos>=m_data_total) + return(false); + CArrayDouble *data=m_values.At(pos); + if(data==NULL) + return(false); +//--- update + if(!data.AssignArray(value)) + return(false); + if(clr!=0 && !m_colors.Update(pos,clr)) + return(false); + if(descr!=NULL && !m_descriptors.Update(pos,descr)) + return(false); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Deletes data series | +//+------------------------------------------------------------------+ +bool CHistogramChart::SeriesDelete(const uint pos) + { +//--- check + if(pos>=m_data_total && m_data_total!=0) + return(false); +//--- delete + if(!m_values.Delete(pos)) + return(false); + m_data_total--; + if(!m_colors.Delete(pos)) + return(false); + if(!m_descriptors.Delete(pos)) + return(false); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Updates element in data series | +//+------------------------------------------------------------------+ +bool CHistogramChart::ValueUpdate(const uint series,const uint pos,double value) + { + CArrayDouble *data=m_values.At(series); +//--- check + if(data==NULL) + return(false); +//--- update + if(!data.Update(pos,value)) + return(false); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Draws histogram | +//+------------------------------------------------------------------+ +void CHistogramChart::DrawData(const uint idx) + { + double value=0.0; +//--- check + CArrayDouble *data=m_values.At(idx); + if(data==NULL) + return; + int total=data.Total(); + if(total==0 || (int)idx>=total) + return; +//--- calculate + int x1=m_data_area.left; + int x2=m_data_area.right; + int dx=(x2-x1)/total; + uint clr=m_colors[idx]; + uint w=dx/m_data_total; + if(w0) + { + y=(m_y_0-(int)(value*m_scale_y)); + h=m_y_0-y; + } + else + { + y=m_y_0; + h=-(int)(value*m_scale_y); + } + DrawBar(x,y,w,h,clr); + //--- draw text of value + if(IS_SHOW_VALUE) + { + string text =DoubleToString(value,2); + int width=(int)(TextWidth(text)+w); + if(value>0) + { + if(width>y-m_y_max) + TextOut(x+w/2,y+w,text,m_color_text,TA_RIGHT|TA_VCENTER); + else + TextOut(x+w/2,y-w,text,m_color_text,TA_LEFT|TA_VCENTER); + } + else + { + if(width>m_y_min-y-h) + TextOut(x+w/2,y+h-w,text,m_color_text,TA_LEFT|TA_VCENTER); + else + TextOut(x+w/2,y+h+w,text,m_color_text,TA_RIGHT|TA_VCENTER); + } + } + } + if(IS_SHOW_VALUE) + FontSet(fontname,fontsize,fontflags,fontangle); + } +//+------------------------------------------------------------------+ +//| Draws bar | +//+------------------------------------------------------------------+ +void CHistogramChart::DrawBar(const int x,const int y,const int w,const int h,const uint clr) + { +//--- draw bar + if(!m_gradient || ArraySize(m_fill_brush)>1; + if((r&1)==0) + i1--; + //--- calculate + while(dy>=dx) + { + clr=fill_clr; + dclr=GETRGB(XRGB((r-dy)*GETRGBR(clr)/r,(r-dy)*GETRGBG(clr)/r,(r-dy)*GETRGBB(clr)/r)); + clr-=dclr; + m_fill_brush[i1]=clr; + m_fill_brush[i2]=clr; + //--- + if(f>=0) + { + dy--; + dd_y+=2; + f+=dd_y; + } + dx++; + if(--i1<0) + break; + i2++; + dd_x+=2; + f+=dd_x; + } + } + else + ArrayFree(m_fill_brush); + } +//+------------------------------------------------------------------+ diff --git a/Include/Canvas/Charts/LineChart.mqh b/Include/Canvas/Charts/LineChart.mqh new file mode 100644 index 0000000..c81e9e3 --- /dev/null +++ b/Include/Canvas/Charts/LineChart.mqh @@ -0,0 +1,383 @@ +//+------------------------------------------------------------------+ +//| LineChart.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include "ChartCanvas.mqh" +#include +//+------------------------------------------------------------------+ +//| Class CLineChart | +//| Usage: generates line chart | +//+------------------------------------------------------------------+ +class CLineChart : public CChartCanvas + { +private: + //--- data + CArrayObj *m_values; + //--- adjusted parameters + bool m_filled; + +public: + CLineChart(void); + ~CLineChart(void); + //--- create + virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_ARGB_NORMALIZE); + //--- adjusted parameters + void Filled(const bool flag=true) { m_filled=flag; } + //--- set up + bool SeriesAdd(const double &value[],const string descr="",const uint clr=0); + bool SeriesInsert(const uint pos,const double &value[],const string descr="",const uint clr=0); + bool SeriesUpdate(const uint pos,const double &value[],const string descr=NULL,const uint clr=0); + bool SeriesDelete(const uint pos); + bool ValueUpdate(const uint series,const uint pos,double value); + +protected: + virtual void DrawChart(void); + virtual void DrawData(const uint index=0); + +private: + double CalcArea(const uint index); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CLineChart::CLineChart(void) : m_filled(false) + { + ShowFlags(FLAG_SHOW_LEGEND|FLAGS_SHOW_SCALES|FLAG_SHOW_GRID); + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CLineChart::~CLineChart(void) + { + } +//+------------------------------------------------------------------+ +//| Create dynamic resource | +//+------------------------------------------------------------------+ +bool CLineChart::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt) + { +//--- create object to store data + if((m_values=new CArrayObj)==NULL) + return(false); +//--- pass responsibility for its destruction to the parent class + m_data=m_values; +//--- call method of parent class + if(!CChartCanvas::Create(name,width,height,clrfmt)) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Adds data series | +//+------------------------------------------------------------------+ +bool CLineChart::SeriesAdd(const double &value[],const string descr,const uint clr) + { +//--- check + if(m_data_total==m_max_data) + return(false); +//--- add + CArrayDouble *arr=new CArrayDouble; + if(!m_values.Add(arr)) + return(false); + if(!arr.AssignArray(value)) + return(false); + if(!m_colors.Add((clr==0) ? GetDefaultColor(m_data_total) : clr)) + return(false); + if(!m_descriptors.Add(descr)) + return(false); + m_data_total++; +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Inserts data series | +//+------------------------------------------------------------------+ +bool CLineChart::SeriesInsert(const uint pos,const double &value[],const string descr,const uint clr) + { +//--- check + if(m_data_total==m_max_data) + return(false); + if(pos>=m_data_total) + return(false); +//--- insert + CArrayDouble *arr=new CArrayDouble; + if(!m_values.Insert(arr,pos)) + return(false); + if(!arr.AssignArray(value)) + return(false); + if(!m_colors.Insert((clr==0) ? GetDefaultColor(m_data_total) : clr,pos)) + return(false); + if(!m_descriptors.Insert(descr,pos)) + return(false); + m_data_total++; +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Updates data series | +//+------------------------------------------------------------------+ +bool CLineChart::SeriesUpdate(const uint pos,const double &value[],const string descr,const uint clr) + { +//--- check + if(pos>=m_data_total) + return(false); + CArrayDouble *data=m_values.At(pos); + if(data==NULL) + return(false); +//--- update + if(!data.AssignArray(value)) + return(false); + if(clr!=0 && !m_colors.Update(pos,clr)) + return(false); + if(descr!=NULL && !m_descriptors.Update(pos,descr)) + return(false); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Deletes data series | +//+------------------------------------------------------------------+ +bool CLineChart::SeriesDelete(const uint pos) + { +//--- check + if(pos>=m_data_total && m_data_total!=0) + return(false); +//--- delete + if(!m_values.Delete(pos)) + return(false); + m_data_total--; + if(!m_colors.Delete(pos)) + return(false); + if(!m_descriptors.Delete(pos)) + return(false); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Updates element in data series | +//+------------------------------------------------------------------+ +bool CLineChart::ValueUpdate(const uint series,const uint pos,double value) + { + CArrayDouble *data=m_values.At(series); +//--- check + if(data==NULL) + return(false); +//--- update + if(!data.Update(pos,value)) + return(false); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Redraws data | +//+------------------------------------------------------------------+ +void CLineChart::DrawChart(void) + { + if(m_filled) + { + //--- calculate areas of filling + double s[]; + ArrayResize(s,m_data_total); + ArrayInitialize(s,0); + for(uint i=0;im_y_0 && y2m_y_0)) + { + //--- draw two triangles + int x3; + if(y1>y2) + { + x3=x+dx*(y1-m_y_0)/(y1-y2); + FillTriangle(x,y1,x3,m_y_0,x,m_y_0,(uint)m_colors[index]); + FillTriangle(x+dx,y2,x3,m_y_0,x+dx,m_y_0,(uint)m_colors[index]); + } + else + { + x3=x+dx*(m_y_0-y1)/(y2-y1); + FillTriangle(x,y1,x3,m_y_0,x,m_y_0,(uint)m_colors[index]); + FillTriangle(x+dx,y2,x3,m_y_0,x+dx,m_y_0,(uint)m_colors[index]); + } + continue; + } + if(y1y2) + FillTriangle(x,y1,x+dx,y2,x+dx,y1,(uint)m_colors[index]); + if(y1m_y_0 || y2>m_y_0) + { + if(y1y2) + { + FillTriangle(x,y1,x+dx,y2,x,y2,(uint)m_colors[index]); + y1=y2; + } + } + FillRectangle(x,m_y_0,x+dx,y1,(uint)m_colors[index]); + } + else + LineAA(x,y1,x+dx,y2,(uint)m_colors[index],STYLE_SOLID); + } + } +//+------------------------------------------------------------------+ +//| Area of filling | +//+------------------------------------------------------------------+ +double CLineChart::CalcArea(const uint index) + { + double area =0; + double value=0; + int dx =100; +//--- + CArrayDouble *data=m_values.At(index); + if(data==NULL) + return(0); + int total=data.Total(); + if(total<=1) + return(0); + int y1=0; + int y2=(int)(m_y_0-data[0]*m_scale_y); + for(int i=0;im_y_0 && y2m_y_0)) + { + //--- line of values crosses the Y axis + int x; + if(y1>y2) + { + //--- from the bottom up + x=dx*(y1-m_y_0)/(y1-y2); + //--- add area of lower triangle + area+=x*(y1-m_y_0)/2; + //--- add area of upper triangle + area+=(dx-x)*(m_y_0-y2)/2; + } + else + { + //--- from top down + x=dx*(m_y_0-y1)/(y2-y1); + //--- add area of upper triangle + area+=x*(m_y_0-y1)/2; + //--- add area of lower triangle + area+=(dx-x)*(y2-m_y_0)/2; + } + continue; + } + if(y1y2) + { + //--- add area of triangle + area+=dx*(y1-y2)/2; + //--- add area of rectangle + area+=dx*(m_y_0-y2); + } + if(y1m_y_0 || y2>m_y_0) + { + //--- both values are less than zero + if(y1y2) + { + //--- add area of triangle + area+=dx*(y1-y2)/2; + //--- add area of rectangle + area+=dx*(y2-m_y_0); + } + } + } +//--- + return(area); + } +//+------------------------------------------------------------------+ diff --git a/Include/Canvas/Charts/PieChart.mqh b/Include/Canvas/Charts/PieChart.mqh new file mode 100644 index 0000000..79be4d1 --- /dev/null +++ b/Include/Canvas/Charts/PieChart.mqh @@ -0,0 +1,414 @@ +//+------------------------------------------------------------------+ +//| PieChart.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include "ChartCanvas.mqh" +//+------------------------------------------------------------------+ +//| Class CPieChart | +//| Usage: generates pie chart | +//+------------------------------------------------------------------+ +class CPieChart : public CChartCanvas + { +private: + //--- data + CArrayDouble *m_values; + //--- for draw + int m_x0; + int m_y0; + int m_r; + +public: + CPieChart(void); + ~CPieChart(void); + //--- create + virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA); + //--- data + bool SeriesSet(const double &value[],const string &text[],const uint &clr[]); + bool ValueAdd(const double value,const string descr="",const uint clr=0); + bool ValueInsert(const uint pos,const double value,const string descr="",const uint clr=0); + bool ValueUpdate(const uint pos,const double value,const string descr=NULL,const uint clr=0); + bool ValueDelete(const uint pos); + +protected: + virtual void DrawChart(void); + void DrawPie(double fi3,double fi4,int idx,CPoint &p[],const uint clr); + string LabelMake(const string text,const double value,const bool to_left); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CPieChart::CPieChart(void) + { + uint flags=FLAG_SHOW_LEGEND|FLAG_SHOW_DESCRIPTORS|FLAG_SHOW_VALUE|FLAG_SHOW_PERCENT; + AllowedShowFlags(flags); + ShowFlags(flags); + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CPieChart::~CPieChart(void) + { + } +//+------------------------------------------------------------------+ +//| Create dynamic resource | +//+------------------------------------------------------------------+ +bool CPieChart::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt) + { +//--- create object to store data + if((m_values=new CArrayDouble)==NULL) + return(false); +//--- pass responsibility for its destruction to the parent class + m_data=m_values; +//--- call method of parent class + if(!CChartCanvas::Create(name,width,height,clrfmt)) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Sets displayed parameters | +//+------------------------------------------------------------------+ +bool CPieChart::SeriesSet(const double &value[],const string &text[],const uint &clr[]) + { +//--- !!! user is responsible for correct filling of arrays !!! +//--- check + if(m_values==NULL) + return(false); +//--- set + if(!m_values.AssignArray(value)) + return(false); + if(!m_descriptors.AssignArray(text)) + return(false); + if(!m_colors.AssignArray(clr)) + return(false); + m_data_total=m_values.Total(); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Adds displayed parameter (to the end) | +//+------------------------------------------------------------------+ +bool CPieChart::ValueAdd(const double value,const string descr,const uint clr) + { +//--- check + if((value<=0)) + return(false); +//--- add + if(!m_values.Add(value)) + return(false); + if(!m_descriptors.Add(descr)) + return(false); + if(!m_colors.Add((clr==0) ? GetDefaultColor(m_data_total) : clr)) + return(false); + m_data_total++; +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Inserts displayed parameter (to specified position) | +//+------------------------------------------------------------------+ +bool CPieChart::ValueInsert(const uint pos,const double value,const string descr,const uint clr) + { +//--- check + if((value<=0)) + return(false); +//--- insert + if(!m_values.Insert(value,pos)) + return(false); + if(!m_descriptors.Insert(descr,pos)) + return(false); + if(!m_colors.Insert((clr==0) ? GetDefaultColor(m_data_total) : clr,pos)) + return(false); + m_data_total++; +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Updates displayed parameter (in specified position) | +//+------------------------------------------------------------------+ +bool CPieChart::ValueUpdate(const uint pos,const double value,const string descr,const uint clr) + { +//--- check + if((value<=0)) + return(false); +//--- update + if(!m_values.Update(pos,value)) + return(false); + if(descr!=NULL && !m_descriptors.Update(pos,descr)) + return(false); + if(clr!=0 && !m_colors.Update(pos,clr)) + return(false); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Deletes displayed parameter (from specified position) | +//+------------------------------------------------------------------+ +bool CPieChart::ValueDelete(const uint pos) + { +//--- delete + if(!m_values.Delete(pos)) + return(false); + m_data_total--; + if(!m_descriptors.Delete(pos)) + return(false); + if(!m_colors.Delete(pos)) + return(false); +//--- redraw + Redraw(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Draws | +//+------------------------------------------------------------------+ +void CPieChart::DrawChart(void) + { +//--- check + if(m_data_total==0) + return; +//--- variables + string text=""; + double angle=M_PI*(m_data_offset%360)/180; + int width,height; + int dw=0; + int dh=0; + int index; + CPoint p0[]; + CPoint p1[]; +//--- calculate geometry + width =(m_data_area.Width()<<3)/10; + height=(m_data_area.Height()<<3)/10; + if(IS_SHOW_LEGEND || !IS_SHOW_DESCRIPTORS) + { + if(IS_SHOW_VALUE) + dw=(int)m_max_value_width; + else + { + if(IS_SHOW_PERCENT) + dw=TextWidth("100.00%"); + } + } + else + { + if(IS_SHOW_DESCRIPTORS) + { + if(IS_SHOW_VALUE) + dw=(int)m_max_value_width+TextWidth(" ()"); + else + { + if(IS_SHOW_PERCENT) + dw=TextWidth(" (100.00%)"); + } + dw+=(int)m_max_descr_width; + } + } +//--- pie chart will always be round + width -=2*dw+10; + height-=20; + m_x0=m_data_area.left+(m_data_area.Width()>>1); + m_y0=m_data_area.top+(m_data_area.Height()>>1); + m_r =(((width>height) ? height : width)>>1); +//--- draw pie chart + if(ArrayResize(p0,m_data_total+1)==-1) + return; + if(m_data_total==1) + { + FillCircle(m_x0,m_y0,m_r,m_colors[0]); + Circle(m_x0,m_y0,m_r,m_color_border); + } + else + { + Circle(m_x0,m_y0,m_r,m_color_border); + for(uint i=0;i=m_x0) + { + x=p1[i].x+10; + y=p1[i].y; + index=m_index[i]; + text=LabelMake(m_descriptors[index],m_values[index],false); + if(text!="") + { + Line(p0[i].x,p0[i].y,p1[i].x,p1[i].y,m_color_border); + Line(p1[i].x,p1[i].y,x,y,m_color_border); + TextOut(x+5,y,text,m_color_text,TA_LEFT|TA_VCENTER); + } + } + if(m_data_total!=m_index_size) + { + index=(int)m_data_total-1; + if(p0[index].x>=m_x0) + { + x=p1[index].x+10; + y=p1[index].y; + text=LabelMake("Others",m_others,true); + TextOut(x+5,y,text,m_color_text,TA_LEFT|TA_VCENTER); + } + else + { + x=p1[index].x-10; + y=p1[index].y; + text=LabelMake("Others",m_others,false); + TextOut(x-5,y,text,m_color_text,TA_RIGHT|TA_VCENTER); + } + if(text!="") + { + Line(p0[index].x,p0[index].y,p1[index].x,p1[index].y,m_color_border); + Line(p1[index].x,p1[index].y,x,y,m_color_border); + } + } + ArrayFree(p1); + ArrayFree(p0); + } +//+------------------------------------------------------------------+ +//| Draw pie | +//+------------------------------------------------------------------+ +void CPieChart::DrawPie(double fi3,double fi4,int idx,CPoint &p[],const uint clr) + { +//--- draw arc + Arc(m_x0,m_y0,m_r,m_r,fi3,fi4,p[idx].x,p[idx].y,p[idx+1].x,p[idx+1].y,clr); +//--- variables + int x3=p[idx].x; + int y3=p[idx].y; + int x4=p[idx+1].x; + int y4=p[idx+1].y; +//--- draw radii + if(idx==0) + Line(m_x0,m_y0,x3,y3,clr); + if(idx!=m_data_total-1) + Line(m_x0,m_y0,x4,y4,clr); +//--- fill + double fi=(fi3+fi4)/2; + int xf=m_x0+(int)(0.99*m_r*cos(fi)); + int yf=m_y0-(int)(0.99*m_r*sin(fi)); + Fill(xf,yf,clr); +//--- for small pie + if(fi4-fi3<=M_PI_4) + Line(m_x0,m_y0,xf,yf,clr); + } +//+------------------------------------------------------------------+ +//| Make label for pie | +//+------------------------------------------------------------------+ +string CPieChart::LabelMake(const string text,const double value,const bool to_left) + { + string label=""; +//--- + if(to_left) + { + if(IS_SHOW_LEGEND || !IS_SHOW_DESCRIPTORS) + { + if(IS_SHOW_VALUE) + label=DoubleToString(value,2); + else + { + if(IS_SHOW_PERCENT) + label=DoubleToString(100*value/m_sum,2)+"%"; + } + } + else + { + label=text; + if(IS_SHOW_VALUE) + label+=" ("+DoubleToString(value,2)+")"; + else + { + if(IS_SHOW_PERCENT) + label+=" ("+DoubleToString(100*value/m_sum,2)+"%)"; + } + } + } + else + { + if(IS_SHOW_LEGEND || !IS_SHOW_DESCRIPTORS) + { + if(IS_SHOW_VALUE) + label=DoubleToString(value,2); + else + { + if(IS_SHOW_PERCENT) + label=DoubleToString(100*value/m_sum,2)+"%"; + } + } + else + { + if(IS_SHOW_VALUE) + label="("+DoubleToString(value,2)+") "; + else + { + if(IS_SHOW_PERCENT) + label="("+DoubleToString(100*value/m_sum,2)+"%) "; + } + label+=text; + } + } +//--- + return(label); + } +//+------------------------------------------------------------------+ diff --git a/Include/Canvas/FlameCanvas.mqh b/Include/Canvas/FlameCanvas.mqh new file mode 100644 index 0000000..3705caa --- /dev/null +++ b/Include/Canvas/FlameCanvas.mqh @@ -0,0 +1,751 @@ +//+------------------------------------------------------------------+ +//| FlameCanvas.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include "Canvas.mqh" +#include +//+------------------------------------------------------------------+ +//| Gradient descriptors | +//+------------------------------------------------------------------+ +struct GRADIENT_COLOR + { + uint clr; // color in ARGB format + uint pos; // position of color in percentage of gradient range + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +struct GRADIENT_SIZE + { + uint size; // width of gradient fill in percentage of base fill + uint pos; // position of color in percentage of gradient length + }; +//+------------------------------------------------------------------+ +//| Class CFlameCanvas | +//| Usage: generates flame | +//+------------------------------------------------------------------+ +class CFlameCanvas : public CCanvas + { +private: + //--- parameters + uint m_bar_gap; + uint m_bar_width; + uint m_chart_scale; + double m_chart_price_min; + double m_chart_price_max; + ENUM_TIMEFRAMES m_timeframe; + string m_symbol; + int m_future_bars; + int m_back_bars; + int m_rates_total; + uint m_palette[256]; // flame palette + uchar m_flame[]; // buffer for calculation of flame + uint m_time_redraw; + uint m_delay; + // bool m_resize_flag; + // int m_tick_cnt; + //--- flame parameters + datetime m_tb1; + double m_pb1; + datetime m_te1; + double m_pe1; + datetime m_tb2; + double m_pb2; + datetime m_te2; + double m_pe2; + //--- equation parameters for flame + int m_cloud_axis[100]; + double m_a1; + double m_b1; + double m_a2; + double m_b2; + int m_xb1; + int m_yb1; + int m_xe1; + int m_ye1; + int m_xb2; + int m_yb2; + int m_xe2; + int m_ye2; + +public: + CFlameCanvas(void); + ~CFlameCanvas(void); + //--- create + bool FlameCreate(const string name,const datetime time,const int future_bars,const int back_bars=0); + void RatesTotal(const int value); + //--- setting + void PaletteSet(uint clr=0xFF0000); + //--- draw + void FlameDraw(const double &prices[],const int width,const int lenght); + void FlameSet(datetime xb1,double yb1,datetime xe1,double ye1,datetime xb2,double yb2,datetime xe2,double ye2); + //--- event handler + void ChartEventHandler(const int id,const long &lparam,const double &dparam,const string &sparam); + +protected: + bool Resize(void); + void ChartScale(void); + void FlameSet(void); + void CloudDraw(const double &prices[],const int width,const int lenght,GRADIENT_SIZE &size[],GRADIENT_COLOR &gradient[],const uchar t_level=255,const bool custom_gradient=true); + void FlameDraw(const int width,const int lenght,GRADIENT_SIZE &size[],GRADIENT_COLOR &gradient[]); + void GradientVertical(const int xb,const int xe,const int yb1,const int ye1,const int yb2,const int ye2,const GRADIENT_COLOR &gradient[]); + void GradientVerticalLine(int x,int y1,int y2,const GRADIENT_COLOR &gradient[]); + void GradientVerticalLineMonochrome(int x,int y1,int y2,uint clr1,uint clr2); + void FlameCreate(void); + void FlameCalculate(void); + void Delay(const uint value); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CFlameCanvas::CFlameCanvas(void) : m_bar_gap(16), + m_bar_width(8), + m_chart_scale(1), + m_chart_price_min(0.0), + m_chart_price_max(0.0), + m_timeframe(PERIOD_CURRENT), + m_symbol(NULL), + m_future_bars(0), + m_back_bars(0), + m_rates_total(0), + m_time_redraw(0), + m_delay(50), + m_tb1(0), + m_pb1(0), + m_te1(0), + m_pe1(0), + m_tb2(0), + m_pb2(0), + m_te2(0), + m_pe2(0) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CFlameCanvas::~CFlameCanvas(void) + { + Destroy(); + } +//+------------------------------------------------------------------+ +//| Creates dynamic resource with object | +//+------------------------------------------------------------------+ +bool CFlameCanvas::FlameCreate(const string name,const datetime time,const int future_bars,const int back_bars) + { +//--- get chart parameters + ChartScale(); +//--- create + int width =(int)m_bar_gap*(future_bars+back_bars); + int height=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS); + if(!CreateBitmap(0,0,name,time-back_bars*PeriodSeconds(),m_chart_price_max,width,height,COLOR_FORMAT_ARGB_NORMALIZE)) + return(false); + ArrayResize(m_flame,width*height); +//--- save parameters + m_future_bars=future_bars; + m_back_bars =back_bars; +//--- settings + PaletteSet(); + m_timeframe =Period(); + m_symbol =Symbol(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Resize | +//+------------------------------------------------------------------+ +bool CFlameCanvas::Resize(void) + { + int x,y; +//--- get limits + double min=ChartGetDouble(0,CHART_PRICE_MIN); + double max=ChartGetDouble(0,CHART_PRICE_MAX); + if(m_chart_price_max!=max) + { + //--- move object + ObjectSetDouble(0,m_objname,OBJPROP_PRICE,0,max); + } +//--- check + if(m_chart_price_min==min && m_chart_price_max==max) + return(false); + m_chart_price_min=min; + m_chart_price_max=max; +//--- grt size + ChartTimePriceToXY(0,0,m_tb1,min,x,y); + int width =(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS)-x; + int height=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS); +//--- resize + if(width80) g+=dg; + if(i>160) b+=db; + } + } +//+------------------------------------------------------------------+ +//| Draws the flame | +//+------------------------------------------------------------------+ +void CFlameCanvas::FlameDraw(const double &prices[],const int width,const int lenght) + { + static GRADIENT_SIZE sword[]={{100,0},{150,70},{0,100}}; + static GRADIENT_COLOR flame[]={{0x00,0},{0x7F7F7F,12},{0xCCCCCC,30},{0xFFFFFF,45},{0xFFFFFF,55},{0xCCCCCC,70},{0x7F7F7F,88},{0x00,100}}; +//--- draw + CloudDraw(prices,width,lenght,sword,flame); +//--- copy flame buffer + FlameCalculate(); +//--- start timer + EventChartCustom(CONTROLS_SELF_MESSAGE,1302,0,0,NULL); + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void CFlameCanvas::FlameDraw(const int width,const int lenght,GRADIENT_SIZE &size[],GRADIENT_COLOR &gradient[]) + { +//--- check + int total=ArraySize(m_cloud_axis); + if(total<2) + return; + if(total>lenght) + total=lenght; +//--- draw + int xb,xe; // coordinates of the segment + int ybm,yem; // coordinates of the center line + int yb1,ye1; // coordinates of the first line + int yb2,ye2; // coordinates of the second line +//--- for implementation of variable width + int w_total=ArraySize(size); + if(w_total<2) + return; + int w_i =0; + int w_is=(int)size[w_i].pos*total/100; + int w_ie=(int)size[w_i+1].pos*total/100; + double w =size[w_i].size*width/100; + double dw =(size[w_i+1].size*width/100-w)/(w_ie-w_is); +//--- draw from left to right + xb=0; + ybm=m_cloud_axis[0]; + yb1=ybm-(int)(w/2); + yb2=ybm+(int)(w/2); +//--- draw + for(int i=1;i=m_width) + break; + yb1=ye1; + yb2=ye2; + while(i>=w_ie-1 && i!=total-1) + { + w_i++; + w_is=(int)size[w_i].pos*total/100; + w_ie=(int)size[w_i+1].pos*total/100; + w =size[w_i].size*width/100; + if(w_ie==w_is) + { + //--- for "instant" resize + dw=size[w_i+1].size*width/100-w; + w+=dw; + ye1=yem-(int)(w/2); + ye2=yem+(int)(w/2); + //--- draw the segment of 'cloud' + GradientVertical(xb,xe,yb1,ye1,yb2,ye2,gradient); + yb1=ye1; + yb2=ye2; + } + else + { + dw=(size[w_i+1].size*width/100-w)/(w_ie-w_is); + break; + } + } + } +//--- copy flame buffer + FlameCalculate(); + } +//+------------------------------------------------------------------+ +//| Sets parameters of the flame and starts to draw | +//+------------------------------------------------------------------+ +void CFlameCanvas::FlameSet(void) + { + m_a1=m_bar_gap*((m_ye1-m_yb1)/((double)m_xe1-m_xb1)); + m_a2=m_bar_gap*((m_ye2-m_yb2)/((double)m_xe2-m_xb2)); + } +//+------------------------------------------------------------------+ +//| Sets parameters of the flame and starts to draw | +//+------------------------------------------------------------------+ +void CFlameCanvas::FlameSet(datetime tb1,double pb1, + datetime te1,double pe1, + datetime tb2,double pb2, + datetime te2,double pe2) + { + datetime obj_time =(datetime)ObjectGetInteger(0,m_objname,OBJPROP_TIME); + double obj_price=ObjectGetDouble(0,m_objname,OBJPROP_PRICE); + int dx,dy; +//--- save parameters + m_tb1=tb1; + m_pb1=pb1; + m_te1=te1; + m_pe1=pe1; + m_tb2=tb2; + m_pb2=pb2; + m_te2=te2; + m_pe2=pe2; +//--- resize + Resize(); +//--- convert + if(ChartTimePriceToXY(0,0,obj_time,obj_price,dx,dy)) + { + dy=m_yb1; + if(ChartTimePriceToXY(0,0,tb1,pb1,m_xb1,m_yb1)) + if(ChartTimePriceToXY(0,0,te1,pe1,m_xe1,m_ye1)) + if(ChartTimePriceToXY(0,0,tb2,pb2,m_xb2,m_yb2)) + if(ChartTimePriceToXY(0,0,te2,pe2,m_xe2,m_ye2)) + { + //--- convert to canvas coordinates + m_xb1-=dx; + m_xe1-=dx; + m_xb2-=dx; + m_xe2-=dx; + //--- + FlameSet(); + } + } +//--- start timer + EventChartCustom(CONTROLS_SELF_MESSAGE,1302,0,0,NULL); + } +//+------------------------------------------------------------------+ +//| Generate array that describes the body of flame | +//+------------------------------------------------------------------+ +void CFlameCanvas::FlameCreate(void) + { + static GRADIENT_SIZE sword[]={{100,0},{150,70},{0,100}}; + static GRADIENT_COLOR flame[]={{0x00,0},{0x7F7F7F,12},{0xCCCCCC,30},{0xFFFFFF,45},{0xFFFFFF,55},{0xCCCCCC,70},{0x7F7F7F,88},{0x00,100}}; +//--- + double a=rand(); // parameter of line a*x+b + double b=rand(); // parameter of line a*x+b + double c=rand(); // parameter of sine c*Sin(d*x) + double d=rand(); // parameter of sine c*Sin(d*x) + int w=rand(); // width at the base + int l=rand(); // length +//--- normalize + a=fmod(a,(m_a2-m_a1))+m_a1; + b=(m_yb1+m_yb2)/2; + c=fmod(c,20); + d=fmod(d,3*M_PI)+M_PI; +//--- shape + w%=150; + if(w<10) + w=10; // but no less than 10 + sword[1].size=w; + w=rand(); + l%=50; + sword[1].pos=l+30; + l=rand(); +//--- sizes + w=(m_yb2-m_yb1!=0) ? w%(m_yb2-m_yb1) : 10; // proportional to the starting width + if(w<10) + w=10; // but no less than 10 + l=l%((m_xe1-m_xb1)/(int)m_bar_gap-20)+20; // proportional to length +//--- create + int total=ArraySize(m_cloud_axis); + for(int i=0;ilenght) + total=lenght; +//--- draw + int xb,xe; // coordinates of the segment + int ybm,yem; // coordinates of the center line + int yb1,ye1; // coordinates of the first line + int yb2,ye2; // coordinates of the second line + int xx; +//--- for implementation of variable width + int w_total=ArraySize(size); + if(w_total<2) + return; + int w_i =0; + int w_is=(int)size[w_i].pos*total/100; + int w_ie=(int)size[w_i+1].pos*total/100; + double w =size[w_i].size*width/100; + double dw =(size[w_i+1].size*width/100-w)/(w_ie-w_is); +//--- draw from left to right + xb=0; + ChartTimePriceToXY(0,0,0,prices[0],xx,ybm); + yb1=ybm-(int)(w/2); + yb2=ybm+(int)(w/2); +//--- draw + for(int i=1;i=m_width) + break; + yb1=ye1; + yb2=ye2; + while(i>=w_ie-1 && i!=total-1) + { + w_i++; + w_is=(int)size[w_i].pos*total/100; + w_ie=(int)size[w_i+1].pos*total/100; + w =size[w_i].size*width/100; + if(w_ie==w_is) + { + //--- for "instant" resize + dw=size[w_i+1].size*width/100-w; + w+=dw; + ye1=yem-(int)(w/2); + ye2=yem+(int)(w/2); + //--- draw the segment of 'cloud' + GradientVertical(xb,xe,yb1,ye1,yb2,ye2,gradient); + yb1=ye1; + yb2=ye2; + } + else + { + dw=(size[w_i+1].size*width/100-w)/(w_ie-w_is); + break; + } + } + } + } +//+------------------------------------------------------------------+ +//| Draws area with vertical fill using specified gradient | +//+------------------------------------------------------------------+ +void CFlameCanvas::GradientVertical(const int xb,const int xe,const int yb1,const int ye1,const int yb2,const int ye2,const GRADIENT_COLOR &gradient[]) + { +//--- it is assumed that the colors array has sufficient size and positions are already sorted in ascending order +//--- get length by X and Y + int x1 =xb; + int y1 =yb1; + int x2 =xb; + int y2 =yb2; + int dx =(xe>xb)? xe-xb : xb-xe; + int dy1=(ye1>yb1)? ye1-yb1 : yb1-ye1; + int dy2=(ye2>yb2)? ye2-yb2 : yb2-ye2; +//--- get direction by X and Y + int sx =(xb-dy1) + { + //--- try to change X coordinate of the first line + //--- draw the second line + while(x2!=xe || y2!=ye2) + { + //--- calculate coordinates of next pixel of the second line + if((er2<<1)>-dy2) + { + //--- try to change X coordinate of the second line + //--- gradient fill + GradientVerticalLine(x1,y1,y2,gradient); + er2-=dy2; + if(x2!=xe) + x2+=sx; + } + if((er2<<1)0) + { + dd=dy; + dy=1; + } + else + { + dd=-dy; + dy=-1; + } +//--- increments for the color components + dc=(double)((uchar)clr2-clr)/dd; +//--- draw + for(int i=0;y1!=y2;i++,y1+=dy) + { + int idx=y1*m_width+x; + //--- check range + if(idx<0 || idx>=ArraySize(m_flame)) + continue; + if(x>=0 && x=0 && y1m_time_redraw) + { + //--- add the body of flame + FlameCreate(); + //--- draw frame + FlameCalculate(); + Update(); + //--- calculate time for the next frame + m_time_redraw=GetTickCount()+m_delay; + } + //--- generate next event for custom timer + EventChartCustom(CONTROLS_SELF_MESSAGE,1302,0,0,NULL); + break; + } + } +//+------------------------------------------------------------------+ +//| Delay | +//+------------------------------------------------------------------+ +void CFlameCanvas::Delay(const uint value) + { +//--- too small + if(value<10) + return; +//--- start delay + uint cnt=GetTickCount()+value; +//--- delay + while(cnt>=GetTickCount()); + } +//+------------------------------------------------------------------+ diff --git a/Include/ChartObjects/ChartObject.mqh b/Include/ChartObjects/ChartObject.mqh new file mode 100644 index 0000000..bde74b8 --- /dev/null +++ b/Include/ChartObjects/ChartObject.mqh @@ -0,0 +1,1000 @@ +//+------------------------------------------------------------------+ +//| ChartObject.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include +//+------------------------------------------------------------------+ +//| Class CChartObject. | +//| Pupose: Base class of chart objects. | +//| Derives from class CObject. | +//+------------------------------------------------------------------+ +class CChartObject : public CObject + { +protected: + long m_chart_id; // identifier of chart the object belongs to + int m_window; // number of subwindow (0 - main window) + string m_name; // unique name object name + int m_num_points; // number of anchor points of object + +public: + CChartObject(void); + ~CChartObject(void); + //--- methods of access to protected data + long ChartId(void) const { return(m_chart_id); } + int Window(void) const { return(m_window); } + string Name(void) const { return(m_name); } + bool Name(const string name); + int NumPoints(void) const { return(m_num_points); } + //--- method of identifying the object + virtual int Type(void) const { return(0x8888); } + //--- methods of filling the object + bool Attach(long chart_id,const string name,const int window,const int points); + bool SetPoint(const int point,const datetime time,const double price) const; + //--- methods of deleting + bool Delete(void); + void Detach(void); + //--- methods of access to properties of the object + datetime Time(const int point) const; + bool Time(const int point,const datetime time) const; + double Price(const int point) const; + bool Price(const int point,const double price) const; + color Color(void) const; + bool Color(const color new_color) const; + ENUM_LINE_STYLE Style(void) const; + bool Style(const ENUM_LINE_STYLE new_style) const; + int Width(void) const; + bool Width(const int new_width) const; + bool Background(void) const; + bool Background(const bool new_back) const; + bool Fill(void) const; + bool Fill(const bool new_fill) const; + long Z_Order(void) const; + bool Z_Order(const long value) const; + bool Selected(void) const; + bool Selected(const bool new_sel) const; + bool Selectable(void) const; + bool Selectable(const bool new_sel) const; + string Description(void) const; + bool Description(const string new_text) const; + string Tooltip(void) const; + bool Tooltip(const string new_text) const; + int Timeframes(void) const; + virtual bool Timeframes(const int timeframes) const; + datetime CreateTime(void) const; + int LevelsCount(void) const; + bool LevelsCount(const int new_count) const; + //--- methods to access the properties of levels of objects + color LevelColor(const int level) const; + bool LevelColor(const int level,const color new_color) const; + ENUM_LINE_STYLE LevelStyle(const int level) const; + bool LevelStyle(const int level,const ENUM_LINE_STYLE new_style) const; + int LevelWidth(const int level) const; + bool LevelWidth(const int level,const int new_width) const; + double LevelValue(const int level) const; + bool LevelValue(const int level,const double new_value) const; + string LevelDescription(const int level) const; + bool LevelDescription(const int level,const string new_text) const; + //--- access methods to the API functions of MQL5 + long GetInteger(const ENUM_OBJECT_PROPERTY_INTEGER prop_id,const int modifier=-1) const; + bool GetInteger(const ENUM_OBJECT_PROPERTY_INTEGER prop_id,const int modifier,long &value) const; + bool SetInteger(const ENUM_OBJECT_PROPERTY_INTEGER prop_id,const int modifier,const long value) const; + bool SetInteger(const ENUM_OBJECT_PROPERTY_INTEGER prop_id,const long value) const; + double GetDouble(const ENUM_OBJECT_PROPERTY_DOUBLE prop_id,const int modifier=-1) const; + bool GetDouble(const ENUM_OBJECT_PROPERTY_DOUBLE prop_id,const int modifier,double &value) const; + bool SetDouble(const ENUM_OBJECT_PROPERTY_DOUBLE prop_id,const int modifier,const double value) const; + bool SetDouble(const ENUM_OBJECT_PROPERTY_DOUBLE prop_id,const double value) const; + string GetString(const ENUM_OBJECT_PROPERTY_STRING prop_id,const int modifier=-1) const; + bool GetString(const ENUM_OBJECT_PROPERTY_STRING prop_id,const int modifier,string &value) const; + bool SetString(const ENUM_OBJECT_PROPERTY_STRING prop_id,const int modifier,const string value) const; + bool SetString(const ENUM_OBJECT_PROPERTY_STRING prop_id,const string value) const; + //--- methods of moving + bool ShiftObject(const datetime d_time,const double d_price) const; + bool ShiftPoint(const int point,const datetime d_time,const double d_price) const; + //--- methods for working with files + virtual bool Save(const int file_handle); + virtual bool Load(const int file_handle); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CChartObject::CChartObject(void) + { +//--- initialize protected data + Detach(); + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CChartObject::~CChartObject(void) + { + if(m_chart_id!=-1) + ObjectDelete(m_chart_id,m_name); + } +//+------------------------------------------------------------------+ +//| Changing name of the object | +//+------------------------------------------------------------------+ +bool CChartObject::Name(const string name) + { +//--- check + if(m_chart_id==-1) + return(false); +//--- change + if(ObjectSetString(m_chart_id,m_name,OBJPROP_NAME,name)) + { + m_name=name; + return(true); + } +//--- failure + return(false); + }; +//+------------------------------------------------------------------+ +//| Attach object | +//+------------------------------------------------------------------+ +bool CChartObject::Attach(long chart_id,const string name,const int window,const int points) + { +//--- check + if(ObjectFind(chart_id,name)<0) + return(false); +//--- attach + if(chart_id==0) + chart_id=ChartID(); + m_chart_id =chart_id; + m_window =window; + m_name =name; + m_num_points=points; +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Setting new coordinates of anchor point of an object | +//+------------------------------------------------------------------+ +bool CChartObject::SetPoint(const int point,const datetime time,const double price) const + { +//--- check + if(m_chart_id==-1) + return(false); + if(point>=m_num_points) + return(false); +//--- result + return(ObjectMove(m_chart_id,m_name,point,time,price)); + } +//+------------------------------------------------------------------+ +//| Delete an object | +//+------------------------------------------------------------------+ +bool CChartObject::Delete(void) + { +//--- checki + if(m_chart_id==-1) + return(false); +//--- actions + bool result=ObjectDelete(m_chart_id,m_name); + Detach(); +//--- result + return(result); + } +//+------------------------------------------------------------------+ +//| Detach object | +//+------------------------------------------------------------------+ +void CChartObject::Detach(void) + { + m_chart_id =-1; + m_window =-1; + m_name =NULL; + m_num_points=0; + } +//+------------------------------------------------------------------+ +//| Get the time coordinate of the specified anchor point of object | +//+------------------------------------------------------------------+ +datetime CChartObject::Time(const int point) const + { +//--- check + if(m_chart_id==-1) + return(0); + if(point>=m_num_points) + return(0); +//--- result + return((datetime)ObjectGetInteger(m_chart_id,m_name,OBJPROP_TIME,point)); + } +//+------------------------------------------------------------------+ +//| Set the time coordinate of the specified anchor point of object | +//+------------------------------------------------------------------+ +bool CChartObject::Time(const int point,const datetime time) const + { +//--- check + if(m_chart_id==-1) + return(false); + if(point>=m_num_points) + return(false); +//--- result + return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_TIME,point,time)); + } +//+------------------------------------------------------------------+ +//| Get the price coordinate of the specified anchor point of object.| +//+------------------------------------------------------------------+ +double CChartObject::Price(const int point) const + { +//--- check + if(m_chart_id==-1) + return(EMPTY_VALUE); + if(point>=m_num_points) + return(EMPTY_VALUE); +//--- result + return(ObjectGetDouble(m_chart_id,m_name,OBJPROP_PRICE,point)); + } +//+------------------------------------------------------------------+ +//| Set the price coordinate of the specified anchor point of object.| +//+------------------------------------------------------------------+ +bool CChartObject::Price(const int point,const double price) const + { +//--- check + if(m_chart_id==-1) + return(false); + if(point>=m_num_points) + return(false); +//--- result + return(ObjectSetDouble(m_chart_id,m_name,OBJPROP_PRICE,point,price)); + } +//+------------------------------------------------------------------+ +//| Get object color | +//+------------------------------------------------------------------+ +color CChartObject::Color(void) const + { +//--- check + if(m_chart_id==-1) + return(CLR_NONE); +//--- result + return((color)ObjectGetInteger(m_chart_id,m_name,OBJPROP_COLOR)); + } +//+------------------------------------------------------------------+ +//| Set object color | +//+------------------------------------------------------------------+ +bool CChartObject::Color(const color new_color) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_COLOR,new_color)); + } +//+------------------------------------------------------------------+ +//| Get style of line of object | +//+------------------------------------------------------------------+ +ENUM_LINE_STYLE CChartObject::Style(void) const + { +//--- check + if(m_chart_id==-1) + return(WRONG_VALUE); +//--- result + return((ENUM_LINE_STYLE)ObjectGetInteger(m_chart_id,m_name,OBJPROP_STYLE)); + } +//+------------------------------------------------------------------+ +//| Set style of line of object | +//+------------------------------------------------------------------+ +bool CChartObject::Style(const ENUM_LINE_STYLE new_style) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_STYLE,new_style)); + } +//+------------------------------------------------------------------+ +//| Get width of line of object | +//+------------------------------------------------------------------+ +int CChartObject::Width(void) const + { +//--- check + if(m_chart_id==-1) + return(-1); +//--- result + return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_WIDTH)); + } +//+------------------------------------------------------------------+ +//| Set width of line of object | +//+------------------------------------------------------------------+ +bool CChartObject::Width(const int new_width) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_WIDTH,new_width)); + } +//+------------------------------------------------------------------+ +//| Get the "Draw object as background" flag | +//+------------------------------------------------------------------+ +bool CChartObject::Background(void) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectGetInteger(m_chart_id,m_name,OBJPROP_BACK)); + } +//+------------------------------------------------------------------+ +//| Set the "Draw object as background" flag | +//+------------------------------------------------------------------+ +bool CChartObject::Background(const bool new_back) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_BACK,new_back)); + } +//+------------------------------------------------------------------+ +//| Get the "Filling" flag | +//+------------------------------------------------------------------+ +bool CChartObject::Fill(void) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectGetInteger(m_chart_id,m_name,OBJPROP_FILL)); + } +//+------------------------------------------------------------------+ +//| Set the "Filling" flag | +//+------------------------------------------------------------------+ +bool CChartObject::Fill(const bool new_fill) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_FILL,new_fill)); + } +//+------------------------------------------------------------------+ +//| Get the "Z-order" property | +//+------------------------------------------------------------------+ +long CChartObject::Z_Order(void) const + { +//--- check + if(m_chart_id==-1) + return(0); +//--- result + return(ObjectGetInteger(m_chart_id,m_name,OBJPROP_ZORDER)); + } +//+------------------------------------------------------------------+ +//| Set the "Z-order" property | +//+------------------------------------------------------------------+ +bool CChartObject::Z_Order(const long value) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_ZORDER,value)); + } +//+------------------------------------------------------------------+ +//| Get the "selected" flag | +//+------------------------------------------------------------------+ +bool CChartObject::Selected(void) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectGetInteger(m_chart_id,m_name,OBJPROP_SELECTED)); + } +//+------------------------------------------------------------------+ +//| Set the "selected" flag | +//+------------------------------------------------------------------+ +bool CChartObject::Selected(const bool new_sel) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_SELECTED,new_sel)); + } +//+------------------------------------------------------------------+ +//| Get the "selectable" flag | +//+------------------------------------------------------------------+ +bool CChartObject::Selectable(void) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectGetInteger(m_chart_id,m_name,OBJPROP_SELECTABLE)); + } +//+------------------------------------------------------------------+ +//| Set flag the "selectable" flag | +//+------------------------------------------------------------------+ +bool CChartObject::Selectable(const bool new_sel) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_SELECTABLE,new_sel)); + } +//+------------------------------------------------------------------+ +//| Get comment of object | +//+------------------------------------------------------------------+ +string CChartObject::Description(void) const + { +//--- check + if(m_chart_id==-1) + return(""); +//--- result + return(ObjectGetString(m_chart_id,m_name,OBJPROP_TEXT)); + } +//+------------------------------------------------------------------+ +//| Set comment of object | +//+------------------------------------------------------------------+ +bool CChartObject::Description(const string new_text) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- tune + if(new_text=="") + return(ObjectSetString(m_chart_id,m_name,OBJPROP_TEXT," ")); +//--- result + return(ObjectSetString(m_chart_id,m_name,OBJPROP_TEXT,new_text)); + } +//+------------------------------------------------------------------+ +//| Get tooltip of object | +//+------------------------------------------------------------------+ +string CChartObject::Tooltip(void) const + { +//--- check + if(m_chart_id==-1) + return(""); +//--- result + return(ObjectGetString(m_chart_id,m_name,OBJPROP_TOOLTIP)); + } +//+------------------------------------------------------------------+ +//| Set tooltip of object | +//+------------------------------------------------------------------+ +bool CChartObject::Tooltip(const string new_text) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- tune + if(new_text=="") + return(ObjectSetString(m_chart_id,m_name,OBJPROP_TOOLTIP," ")); +//--- result + return(ObjectSetString(m_chart_id,m_name,OBJPROP_TOOLTIP,new_text)); + } +//+------------------------------------------------------------------+ +//| Get the "Timeframes" (visibility) flag | +//+------------------------------------------------------------------+ +int CChartObject::Timeframes(void) const + { +//--- check + if(m_chart_id==-1) + return(0); +//--- result + return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_TIMEFRAMES)); + } +//+------------------------------------------------------------------+ +//| Set the "Timeframes" (visibility) flag | +//+------------------------------------------------------------------+ +bool CChartObject::Timeframes(const int timeframes) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_TIMEFRAMES,timeframes)); + } +//+------------------------------------------------------------------+ +//| Get time of object creation | +//+------------------------------------------------------------------+ +datetime CChartObject::CreateTime(void) const + { +//--- check + if(m_chart_id==-1) + return(0); +//--- result + return((datetime)ObjectGetInteger(m_chart_id,m_name,OBJPROP_CREATETIME)); + } +//+------------------------------------------------------------------+ +//| Get number of levels of object | +//+------------------------------------------------------------------+ +int CChartObject::LevelsCount(void) const + { +//--- check + if(m_chart_id==-1) + return(0); +//--- result + return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_LEVELS)); + } +//+------------------------------------------------------------------+ +//| Set number of levels of object | +//+------------------------------------------------------------------+ +bool CChartObject::LevelsCount(const int new_count) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_LEVELS,new_count)); + } +//+------------------------------------------------------------------+ +//| Get color of the specified level of object | +//+------------------------------------------------------------------+ +color CChartObject::LevelColor(const int level) const + { +//--- check + if(m_chart_id==-1) + return(CLR_NONE); + if(level>=LevelsCount()) + return(CLR_NONE); +//--- result + return((color)ObjectGetInteger(m_chart_id,m_name,OBJPROP_LEVELCOLOR,level)); + } +//+------------------------------------------------------------------+ +//| Set color of the specified level of object | +//+------------------------------------------------------------------+ +bool CChartObject::LevelColor(const int level,const color new_color) const + { +//--- check + if(m_chart_id==-1) + return(false); + if(level>=LevelsCount()) + return(false); +//--- result + return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_LEVELCOLOR,level,new_color)); + } +//+------------------------------------------------------------------+ +//| Get line style of the specified level of object | +//+------------------------------------------------------------------+ +ENUM_LINE_STYLE CChartObject::LevelStyle(const int level) const + { +//--- check + if(m_chart_id==-1) + return(WRONG_VALUE); + if(level>=LevelsCount()) + return(WRONG_VALUE); +//--- result + return((ENUM_LINE_STYLE)ObjectGetInteger(m_chart_id,m_name,OBJPROP_LEVELSTYLE,level)); + } +//+------------------------------------------------------------------+ +//| Set line style of the specified level of object | +//+------------------------------------------------------------------+ +bool CChartObject::LevelStyle(const int level,const ENUM_LINE_STYLE new_style) const + { +//--- check + if(m_chart_id==-1) + return(false); + if(level>=LevelsCount()) + return(false); +//--- result + return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_LEVELSTYLE,level,new_style)); + } +//+------------------------------------------------------------------+ +//| Get line width of the specified level of object | +//+------------------------------------------------------------------+ +int CChartObject::LevelWidth(const int level) const + { +//--- check + if(m_chart_id==-1) + return(-1); + if(level>=LevelsCount()) + return(-1); +//--- result + return((int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_LEVELWIDTH,level)); + } +//+------------------------------------------------------------------+ +//| Set line width of the specified level of object | +//+------------------------------------------------------------------+ +bool CChartObject::LevelWidth(const int level,const int new_width) const + { +//--- check + if(m_chart_id==-1) + return(false); + if(level>=LevelsCount()) + return(false); +//--- result + return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_LEVELWIDTH,level,new_width)); + } +//+------------------------------------------------------------------+ +//| Get value of the specified level of object | +//+------------------------------------------------------------------+ +double CChartObject::LevelValue(const int level) const + { +//--- check + if(m_chart_id==-1) + return(EMPTY_VALUE); + if(level>=LevelsCount()) + return(EMPTY_VALUE); +//--- result + return(ObjectGetDouble(m_chart_id,m_name,OBJPROP_LEVELVALUE,level)); + } +//+------------------------------------------------------------------+ +//| Set value of the specified level of object | +//+------------------------------------------------------------------+ +bool CChartObject::LevelValue(const int level,const double new_value) const + { +//--- check + if(m_chart_id==-1) + return(false); + if(level>=LevelsCount()) + return(false); +//--- result + return(ObjectSetDouble(m_chart_id,m_name,OBJPROP_LEVELVALUE,level,new_value)); + } +//+------------------------------------------------------------------+ +//| Get comment of of the specified level of object | +//+------------------------------------------------------------------+ +string CChartObject::LevelDescription(const int level) const + { +//--- check + if(m_chart_id==-1) + return(""); + if(level>=LevelsCount()) + return(""); +//--- result + return(ObjectGetString(m_chart_id,m_name,OBJPROP_LEVELTEXT,level)); + } +//+------------------------------------------------------------------+ +//| Set comment to the specified level of object | +//+------------------------------------------------------------------+ +bool CChartObject::LevelDescription(const int level,const string new_text) const + { +//--- checking + if(m_chart_id==-1) + return(false); + if(level>=LevelsCount()) + return(false); +//--- result + return(ObjectSetString(m_chart_id,m_name,OBJPROP_LEVELTEXT,level,new_text)); + } +//+------------------------------------------------------------------+ +//| Access function long ObjectGetInteger(...) | +//+------------------------------------------------------------------+ +long CChartObject::GetInteger(const ENUM_OBJECT_PROPERTY_INTEGER prop_id,const int modifier) const + { +//--- check + if(m_chart_id==-1) + return(0); +//--- + if(modifier==-1) + return(ObjectGetInteger(m_chart_id,m_name,prop_id)); +//--- result + return(ObjectGetInteger(m_chart_id,m_name,prop_id,modifier)); + } +//+------------------------------------------------------------------+ +//| Access function bool ObjectGetInteger(...) | +//+------------------------------------------------------------------+ +bool CChartObject::GetInteger(const ENUM_OBJECT_PROPERTY_INTEGER prop_id,const int modifier,long &value) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectGetInteger(m_chart_id,m_name,prop_id,modifier,value)); + } +//+------------------------------------------------------------------+ +//| Access function ObjectSetInteger(.,modifier,.) | +//+------------------------------------------------------------------+ +bool CChartObject::SetInteger(const ENUM_OBJECT_PROPERTY_INTEGER prop_id,const int modifier,const long value) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectSetInteger(m_chart_id,m_name,prop_id,modifier,value)); + } +//+------------------------------------------------------------------+ +//| Access function ObjectSetInteger(...) | +//+------------------------------------------------------------------+ +bool CChartObject::SetInteger(const ENUM_OBJECT_PROPERTY_INTEGER prop_id,const long value) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectSetInteger(m_chart_id,m_name,prop_id,value)); + } +//+------------------------------------------------------------------+ +//| Access function double ObjectGetDouble(...) | +//+------------------------------------------------------------------+ +double CChartObject::GetDouble(const ENUM_OBJECT_PROPERTY_DOUBLE prop_id,const int modifier) const + { +//--- check + if(m_chart_id==-1) + return(EMPTY_VALUE); +//--- + if(modifier==-1) + return(ObjectGetDouble(m_chart_id,m_name,prop_id)); +//--- result + return(ObjectGetDouble(m_chart_id,m_name,prop_id,modifier)); + } +//+------------------------------------------------------------------+ +//| Access function bool ObjectGetDouble(...) | +//+------------------------------------------------------------------+ +bool CChartObject::GetDouble(const ENUM_OBJECT_PROPERTY_DOUBLE prop_id,const int modifier,double &value) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectGetDouble(m_chart_id,m_name,prop_id,modifier,value)); + } +//+------------------------------------------------------------------+ +//| Access function ObjectSetDouble(.,modifier,.) | +//+------------------------------------------------------------------+ +bool CChartObject::SetDouble(const ENUM_OBJECT_PROPERTY_DOUBLE prop_id,const int modifier,const double value) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectSetDouble(m_chart_id,m_name,prop_id,modifier,value)); + } +//+------------------------------------------------------------------+ +//| Access function ObjectSetDouble(...) | +//+------------------------------------------------------------------+ +bool CChartObject::SetDouble(const ENUM_OBJECT_PROPERTY_DOUBLE prop_id,const double value) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectSetDouble(m_chart_id,m_name,prop_id,value)); + } +//+------------------------------------------------------------------+ +//| Access function string ObjectGetString (...) | +//+------------------------------------------------------------------+ +string CChartObject::GetString(const ENUM_OBJECT_PROPERTY_STRING prop_id,const int modifier) const + { +//--- check + if(m_chart_id==-1) + return(""); +//--- + if(modifier==-1) + return(ObjectGetString(m_chart_id,m_name,prop_id)); +//--- result + return(ObjectGetString(m_chart_id,m_name,prop_id,modifier)); + } +//+------------------------------------------------------------------+ +//| Access function bool ObjectGetString(...) | +//+------------------------------------------------------------------+ +bool CChartObject::GetString(const ENUM_OBJECT_PROPERTY_STRING prop_id,const int modifier,string &value) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectGetString(m_chart_id,m_name,prop_id,modifier,value)); + } +//+------------------------------------------------------------------+ +//| Access function ObjectSetString(.,modifier,.) | +//+------------------------------------------------------------------+ +bool CChartObject::SetString(const ENUM_OBJECT_PROPERTY_STRING prop_id,const int modifier,const string value) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectSetString(m_chart_id,m_name,prop_id,modifier,value)); + } +//+------------------------------------------------------------------+ +//| Access function ObjectSetString(...) | +//+------------------------------------------------------------------+ +bool CChartObject::SetString(const ENUM_OBJECT_PROPERTY_STRING prop_id,const string value) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ObjectSetString(m_chart_id,m_name,prop_id,value)); + } +//+------------------------------------------------------------------+ +//| Relative movement of object | +//+------------------------------------------------------------------+ +bool CChartObject::ShiftObject(const datetime d_time,const double d_price) const + { + bool result=true; + int i; +//--- check + if(m_chart_id==-1) + return(false); +//--- move + for(i=0;i=m_num_points) + return(false); +//--- move + datetime time=(datetime)ObjectGetInteger(m_chart_id,m_name,OBJPROP_TIME,point); + double price=ObjectGetDouble(m_chart_id,m_name,OBJPROP_PRICE,point); +//--- result + return(ObjectMove(m_chart_id,m_name,point,time+d_time,price+d_price)); + } +//+------------------------------------------------------------------+ +//| Writing object parameters to file | +//+------------------------------------------------------------------+ +bool CChartObject::Save(const int file_handle) + { + int i,len; + int levels; + string str; +//--- check + if(file_handle==INVALID_HANDLE || m_chart_id==-1) + return(false); +//--- write start marker - 0xFFFFFFFFFFFFFFFF + if(FileWriteLong(file_handle,-1)!=sizeof(long)) + return(false); +//--- write object type + if(FileWriteInteger(file_handle,Type(),INT_VALUE)!=INT_VALUE) + return(false); +//--- write object name + str=ObjectGetString(m_chart_id,m_name,OBJPROP_NAME); + len=StringLen(str); + if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE) + return(false); + if(len!=0) if(FileWriteString(file_handle,str,len)!=len) + return(false); +//--- write object color + if(FileWriteLong(file_handle,ObjectGetInteger(m_chart_id,m_name,OBJPROP_COLOR))!=sizeof(long)) + return(false); +//--- write object line style + if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_STYLE))!=sizeof(int)) + return(false); +//--- write object line width + if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_WIDTH))!=sizeof(int)) + return(false); +//--- write the property value "Background" + if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_BACK),CHAR_VALUE)!=sizeof(char)) + return(false); +//--- write the property value "Selectable" + if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_SELECTABLE),CHAR_VALUE)!=sizeof(char)) + return(false); +//--- write the property value "Timeframes" + if(FileWriteInteger(file_handle,(int)ObjectGetInteger(m_chart_id,m_name,OBJPROP_TIMEFRAMES),INT_VALUE)!=sizeof(int)) + return(false); +//--- write comment + str=ObjectGetString(m_chart_id,m_name,OBJPROP_TEXT); + len=StringLen(str); + if(FileWriteInteger(file_handle,len,INT_VALUE)!=INT_VALUE) + return(false); + if(len!=0) if(FileWriteString(file_handle,str,len)!=len) + return(false); +//--- write number of points + if(FileWriteInteger(file_handle,m_num_points,INT_VALUE)!=INT_VALUE) + return(false); +//--- write points + for(i=0;i +#include +#include +//+------------------------------------------------------------------+ +//| Class CChartObjectPanel. | +//| Purpose: Class for grouping objects for managing a chart | +//+------------------------------------------------------------------+ +class CChartObjectPanel : public CChartObjectButton + { +protected: + CArrayObj m_attachment; // array of attached objects + CArrayInt m_dX; // array of dX attached objects + CArrayInt m_dY; // array of dY attached objects + bool m_expanded; // collapsed/expanded flag + +public: + CChartObjectPanel(); + ~CChartObjectPanel(); + //--- method for attaching objects + bool Attach(CChartObjectLabel *chart_object); + bool X_Distance(const int X); + bool Y_Distance(const int Y); + int X_Size() const; + int Y_Size() const; + virtual bool Timeframes(const int timeframes); + bool State(const bool state); + bool CheckState(); + +protected: + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +void CChartObjectPanel::CChartObjectPanel(void) : m_expanded(true) + { + } +//+------------------------------------------------------------------+ +//| Destructor. | +//+------------------------------------------------------------------+ +void CChartObjectPanel::~CChartObjectPanel(void) + { +//--- All objects added by the method Add(), deleted automatically + } +//+------------------------------------------------------------------+ +//| Method Attach | +//+------------------------------------------------------------------+ +bool CChartObjectPanel::Attach(CChartObjectLabel *chart_object) + { + if(m_attachment.Add(chart_object)) + { + int x,y; + x=chart_object.X_Distance(); + m_dX.Add(chart_object.X_Distance()); + x+=X_Distance(); + chart_object.X_Distance(X_Distance()+chart_object.X_Distance()); + y=CChartObjectButton::Y_Size(); + y+=chart_object.Y_Distance(); + m_dY.Add(chart_object.Y_Distance()+CChartObjectButton::Y_Size()+2); + chart_object.Y_Distance(Y_Distance()+chart_object.Y_Distance()+CChartObjectButton::Y_Size()+2); + return(true); + } +//--- + return(false); + } +//+------------------------------------------------------------------+ +//| Method X_Distance | +//+------------------------------------------------------------------+ +bool CChartObjectPanel::X_Distance(const int X) + { + CChartObjectLabel *chart_object; +//--- + for(int i=0;i +//+------------------------------------------------------------------+ +//| Class CChart. | +//| Purpose: Class of the "Chart" object. | +//| Derives from class CObject. | +//+------------------------------------------------------------------+ +class CChart : public CObject + { +protected: + long m_chart_id; // chart identifier +public: + CChart(void); + ~CChart(void); + //--- methods of access to protected data + long ChartId(void) const { return(m_chart_id); } + //--- method of identifying the object + virtual int Type(void) const { return(0x1111); } + //--- methods of access to properties of the chart + //--- common properties + ENUM_CHART_MODE Mode(void) const; + bool Mode(const ENUM_CHART_MODE mode) const; + bool Foreground(void) const; + bool Foreground(const bool foreground) const; + bool Shift(void) const; + bool Shift(const bool shift) const; + double ShiftSize(void) const; + bool ShiftSize(double shift) const; + bool AutoScroll(void) const; + bool AutoScroll(const bool auto_scroll) const; + int Scale(void) const; + bool Scale(int scale) const; + bool ScaleFix(void) const; + bool ScaleFix(const bool scale_fix) const; + bool ScaleFix_11(void) const; + bool ScaleFix_11(const bool scale_fix_11) const; + double FixedMax(void) const; + bool FixedMax(const double fixed_max) const; + double FixedMin(void) const; + bool FixedMin(const double fixed_min) const; + bool ScalePPB(void) const; + bool ScalePPB(const bool scale_ppb) const; + double PointsPerBar(void) const; + bool PointsPerBar(const double points_per_bar) const; + //--- show properties + bool ShowOHLC(void) const; + bool ShowOHLC(const bool show) const; + bool ShowLineBid(void) const; + bool ShowLineBid(const bool show) const; + bool ShowLineAsk(void) const; + bool ShowLineAsk(const bool show) const; + bool ShowLastLine(void) const; + bool ShowLastLine(const bool show) const; + bool ShowPeriodSep(void) const; + bool ShowPeriodSep(const bool show) const; + bool ShowGrid(void) const; + bool ShowGrid(const bool show) const; + ENUM_CHART_VOLUME_MODE ShowVolumes(void) const; + bool ShowVolumes(const ENUM_CHART_VOLUME_MODE show) const; + bool ShowObjectDescr(void) const; + bool ShowObjectDescr(const bool show) const; + bool ShowDateScale(const bool show) const; + bool ShowPriceScale(const bool show) const; + //--- color properties + color ColorBackground(void) const; + bool ColorBackground(const color new_color) const; + color ColorForeground(void) const; + bool ColorForeground(const color new_color) const; + color ColorGrid(void) const; + bool ColorGrid(const color new_color) const; + color ColorBarUp(void) const; + bool ColorBarUp(const color new_color) const; + color ColorBarDown(void) const; + bool ColorBarDown(const color new_color) const; + color ColorCandleBull(void) const; + bool ColorCandleBull(const color new_color) const; + color ColorCandleBear(void) const; + bool ColorCandleBear(const color new_color) const; + color ColorChartLine(void) const; + bool ColorChartLine(const color new_color) const; + color ColorVolumes(void) const; + bool ColorVolumes(const color new_color) const; + color ColorLineBid(void) const; + bool ColorLineBid(const color new_color) const; + color ColorLineAsk(void) const; + bool ColorLineAsk(const color new_color) const; + color ColorLineLast(void) const; + bool ColorLineLast(const color new_color) const; + color ColorStopLevels(void) const; + bool ColorStopLevels(const color new_color) const; + //--- other properties + bool BringToTop(void) const; + bool EventObjectCreate(const bool flag=true) const; + bool EventObjectDelete(const bool flag=true) const; + bool EventMouseMove(const bool flag=true) const; + bool MouseScroll(const bool flag=true) const; + //--- methods of access to READ ONLY properties of the chart + int VisibleBars(void) const; + int WindowsTotal(void) const; + bool WindowIsVisible(const int num) const; + int WindowHandle(void) const; + int FirstVisibleBar(void) const; + int WidthInBars(void) const; + int WidthInPixels(void) const; + int HeightInPixels(const int num) const; + int SubwindowY(const int num) const; + double PriceMin(const int num) const; + double PriceMax(const int num) const; + bool IsObject(void) const; + //--- methods of binding chart + void Attach(void) { m_chart_id=ChartID(); } + void Attach(const long chart) { m_chart_id=chart; } + void FirstChart(void) { m_chart_id=ChartFirst(); } + void NextChart(void) { m_chart_id=ChartNext(m_chart_id); } + long Open(const string symbol_name,const ENUM_TIMEFRAMES timeframe); + void Detach(void) { m_chart_id=-1; } + void Close(void); + //--- navigation method + bool Navigate(const ENUM_CHART_POSITION position,const int shift=0) const; + //--- methods of access to the API functions of MQL5 + string Symbol(void) const { return(ChartSymbol(m_chart_id)); } + ENUM_TIMEFRAMES Period(void) const { return(ChartPeriod(m_chart_id)); } + void Redraw(void) const { ChartRedraw(m_chart_id); } + long GetInteger(const ENUM_CHART_PROPERTY_INTEGER prop_id,const int sub_window=0) const; + bool GetInteger(const ENUM_CHART_PROPERTY_INTEGER prop_id,const int sub_window,long &value) const; + bool SetInteger(const ENUM_CHART_PROPERTY_INTEGER prop_id,const long value) const; + double GetDouble(const ENUM_CHART_PROPERTY_DOUBLE prop_id,const int sub_window=0) const; + bool GetDouble(const ENUM_CHART_PROPERTY_DOUBLE prop_id,const int sub_window,double &value) const; + bool SetDouble(const ENUM_CHART_PROPERTY_DOUBLE prop_id,const double value) const; + string GetString(const ENUM_CHART_PROPERTY_STRING prop_id) const; + bool GetString(const ENUM_CHART_PROPERTY_STRING prop_id,string &value) const; + bool SetString(const ENUM_CHART_PROPERTY_STRING prop_id,const string value) const; + bool SetSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period) const; + bool ApplyTemplate(const string filename) const; + bool ScreenShot(const string filename,const int width,const int height, + const ENUM_ALIGN_MODE align_mode=ALIGN_RIGHT) const; + int WindowOnDropped(void) const; + double PriceOnDropped(void) const; + datetime TimeOnDropped(void) const; + int XOnDropped(void) const; + int YOnDropped(void) const; + //--- methods for working with indicators + bool IndicatorAdd(const int subwin,const int handle) const; + bool IndicatorDelete(const int subwin,const string name) const; + int IndicatorsTotal(const int subwin) const; + string IndicatorName(const int subwin,const int index) const; + //--- methods for working with files + virtual bool Save(const int file_handle); + virtual bool Load(const int file_handle); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CChart::CChart(void) : m_chart_id(-1) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CChart::~CChart(void) + { + if(m_chart_id!=-1) + Close(); + } +//+------------------------------------------------------------------+ +//| Opening chart | +//+------------------------------------------------------------------+ +long CChart::Open(const string symbol_name,const ENUM_TIMEFRAMES timeframe) + { + m_chart_id=ChartOpen(symbol_name,timeframe); + if(m_chart_id==0) + m_chart_id=-1; + return(m_chart_id); + } +//+------------------------------------------------------------------+ +//| Get the type of representation of chart | +//+------------------------------------------------------------------+ +ENUM_CHART_MODE CChart::Mode(void) const + { +//--- check + if(m_chart_id==-1) + return(WRONG_VALUE); +//--- result + return((ENUM_CHART_MODE)ChartGetInteger(m_chart_id,CHART_MODE)); + } +//+------------------------------------------------------------------+ +//| Set the type of representation chart | +//+------------------------------------------------------------------+ +bool CChart::Mode(const ENUM_CHART_MODE mode) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_MODE,mode)); + } +//+------------------------------------------------------------------+ +//| Get value of the "Foreground" property | +//+------------------------------------------------------------------+ +bool CChart::Foreground(void) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartGetInteger(m_chart_id,CHART_FOREGROUND)); + } +//+------------------------------------------------------------------+ +//| Set value of the "Foreground" property | +//+------------------------------------------------------------------+ +bool CChart::Foreground(const bool foreground) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_FOREGROUND,foreground)); + } +//+------------------------------------------------------------------+ +//| Get value of the "Shift" property | +//+------------------------------------------------------------------+ +bool CChart::Shift(void) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartGetInteger(m_chart_id,CHART_SHIFT)); + } +//+------------------------------------------------------------------+ +//| Set value of the "Shift"property | +//+------------------------------------------------------------------+ +bool CChart::Shift(const bool shift) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_SHIFT,shift)); + } +//+------------------------------------------------------------------+ +//| Get value of the "ShiftSize" property | +//+------------------------------------------------------------------+ +double CChart::ShiftSize(void) const + { +//--- check + if(m_chart_id==-1) + return(DBL_MAX); +//--- result + return(ChartGetDouble(m_chart_id,CHART_SHIFT_SIZE)); + } +//+------------------------------------------------------------------+ +//| Set value of the "ShiftSize" property | +//+------------------------------------------------------------------+ +bool CChart::ShiftSize(double shift) const + { +//--- check + if(m_chart_id==-1) + return(false); + if(shift<10) + shift=10; + if(shift>50) + shift=50; +//--- result + return(ChartSetDouble(m_chart_id,CHART_SHIFT_SIZE,shift)); + } +//+------------------------------------------------------------------+ +//| Get value of the "AutoScroll" property | +//+------------------------------------------------------------------+ +bool CChart::AutoScroll(void) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartGetInteger(m_chart_id,CHART_AUTOSCROLL)); + } +//+------------------------------------------------------------------+ +//| Set value of the "AutoScroll" property | +//+------------------------------------------------------------------+ +bool CChart::AutoScroll(const bool auto_scroll) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_AUTOSCROLL,auto_scroll)); + } +//+------------------------------------------------------------------+ +//| Get value of the "Scale" property | +//+------------------------------------------------------------------+ +int CChart::Scale(void) const + { +//--- check + if(m_chart_id==-1) + return(0); +//--- result + return((int)ChartGetInteger(m_chart_id,CHART_SCALE)); + } +//+------------------------------------------------------------------+ +//| Set value of the "Scale" property | +//+------------------------------------------------------------------+ +bool CChart::Scale(int shift) const + { +//--- check + if(m_chart_id==-1) + return(false); + if(shift<0) + shift=0; + if(shift>32) + shift=32; +//--- result + return(ChartSetInteger(m_chart_id,CHART_SCALE,shift)); + } +//+------------------------------------------------------------------+ +//| Get value of the "ScaleFix" property | +//+------------------------------------------------------------------+ +bool CChart::ScaleFix(void) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartGetInteger(m_chart_id,CHART_SCALEFIX)); + } +//+------------------------------------------------------------------+ +//| Set value of the "ScaleFix" property | +//+------------------------------------------------------------------+ +bool CChart::ScaleFix(const bool scale_fix) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_SCALEFIX,scale_fix)); + } +//+------------------------------------------------------------------+ +//| Get value of the "ScaleFix_11" property | +//+------------------------------------------------------------------+ +bool CChart::ScaleFix_11(void) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartGetInteger(m_chart_id,CHART_SCALEFIX_11)); + } +//+------------------------------------------------------------------+ +//| Set value of the "ScaleFix_11" property | +//+------------------------------------------------------------------+ +bool CChart::ScaleFix_11(const bool scale_fix_11) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_SCALEFIX_11,scale_fix_11)); + } +//+------------------------------------------------------------------+ +//| Get value of the "FixedMax" property | +//+------------------------------------------------------------------+ +double CChart::FixedMax(void) const + { +//--- check + if(m_chart_id==-1) + return(EMPTY_VALUE); +//--- result + return(ChartGetDouble(m_chart_id,CHART_FIXED_MAX)); + } +//+------------------------------------------------------------------+ +//| Set value of the "FixedMax" property | +//+------------------------------------------------------------------+ +bool CChart::FixedMax(const double fixed_max) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetDouble(m_chart_id,CHART_FIXED_MAX,fixed_max)); + } +//+------------------------------------------------------------------+ +//| Get value of the "FixedMin" property | +//+------------------------------------------------------------------+ +double CChart::FixedMin(void) const + { +//--- check + if(m_chart_id==-1) + return(EMPTY_VALUE); +//--- result + return(ChartGetDouble(m_chart_id,CHART_FIXED_MIN)); + } +//+------------------------------------------------------------------+ +//| Set value of the "FixedMin" property | +//+------------------------------------------------------------------+ +bool CChart::FixedMin(const double fixed_min) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetDouble(m_chart_id,CHART_FIXED_MIN,fixed_min)); + } +//+------------------------------------------------------------------+ +//| Get value of the "ScalePointsPerBar" property | +//+------------------------------------------------------------------+ +bool CChart::ScalePPB(void) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartGetInteger(m_chart_id,CHART_SCALE_PT_PER_BAR)); + } +//+------------------------------------------------------------------+ +//| Set value of the "ScalePointsPerBar" property | +//+------------------------------------------------------------------+ +bool CChart::ScalePPB(const bool scale_ppb) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_SCALE_PT_PER_BAR,scale_ppb)); + } +//+------------------------------------------------------------------+ +//| Get value of the "PointsPerBar" property | +//+------------------------------------------------------------------+ +double CChart::PointsPerBar(void) const + { +//--- check + if(m_chart_id==-1) + return(EMPTY_VALUE); +//--- result + return(ChartGetDouble(m_chart_id,CHART_POINTS_PER_BAR)); + } +//+------------------------------------------------------------------+ +//| Set value of the "PointsPerBar" property | +//+------------------------------------------------------------------+ +bool CChart::PointsPerBar(const double points_per_bar) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetDouble(m_chart_id,CHART_POINTS_PER_BAR,points_per_bar)); + } +//+------------------------------------------------------------------+ +//| Get value of the "ShowOHLC" property | +//+------------------------------------------------------------------+ +bool CChart::ShowOHLC(void) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartGetInteger(m_chart_id,CHART_SHOW_OHLC)); + } +//+------------------------------------------------------------------+ +//| Set value of the "ShowOHLC" property | +//+------------------------------------------------------------------+ +bool CChart::ShowOHLC(const bool show) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_SHOW_OHLC,show)); + } +//+------------------------------------------------------------------+ +//| Get value of the "ShowLineBid" property | +//+------------------------------------------------------------------+ +bool CChart::ShowLineBid(void) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartGetInteger(m_chart_id,CHART_SHOW_BID_LINE)); + } +//+------------------------------------------------------------------+ +//| Set value of the "ShowLineBid" property | +//+------------------------------------------------------------------+ +bool CChart::ShowLineBid(const bool show) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_SHOW_BID_LINE,show)); + } +//+------------------------------------------------------------------+ +//| Get value of the "ShowLineAsk" property | +//+------------------------------------------------------------------+ +bool CChart::ShowLineAsk(void) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartGetInteger(m_chart_id,CHART_SHOW_ASK_LINE)); + } +//+------------------------------------------------------------------+ +//| Set value of the "ShowLineAsk" property | +//+------------------------------------------------------------------+ +bool CChart::ShowLineAsk(const bool show) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_SHOW_ASK_LINE,show)); + } +//+------------------------------------------------------------------+ +//| Get value of the "ShowLastLine" property | +//+------------------------------------------------------------------+ +bool CChart::ShowLastLine(void) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartGetInteger(m_chart_id,CHART_SHOW_LAST_LINE)); + } +//+------------------------------------------------------------------+ +//| Set value of the "ShowLastLine" property | +//+------------------------------------------------------------------+ +bool CChart::ShowLastLine(const bool show) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_SHOW_LAST_LINE,show)); + } +//+------------------------------------------------------------------+ +//| Get value of the "ShowPeriodSep" property | +//+------------------------------------------------------------------+ +bool CChart::ShowPeriodSep(void) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartGetInteger(m_chart_id,CHART_SHOW_PERIOD_SEP)); + } +//+------------------------------------------------------------------+ +//| Set value of the "ShowPeriodSep" property | +//+------------------------------------------------------------------+ +bool CChart::ShowPeriodSep(const bool show) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_SHOW_PERIOD_SEP,show)); + } +//+------------------------------------------------------------------+ +//| Get value of the "ShowGrid" property | +//+------------------------------------------------------------------+ +bool CChart::ShowGrid(void) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartGetInteger(m_chart_id,CHART_SHOW_GRID)); + } +//+------------------------------------------------------------------+ +//| Set value of the "ShowGrid" property | +//+------------------------------------------------------------------+ +bool CChart::ShowGrid(const bool show) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_SHOW_GRID,show)); + } +//+------------------------------------------------------------------+ +//| Get value of the "ShowVolumes" property | +//+------------------------------------------------------------------+ +ENUM_CHART_VOLUME_MODE CChart::ShowVolumes(void) const + { +//--- check + if(m_chart_id==-1) + return(WRONG_VALUE); +//--- result + return((ENUM_CHART_VOLUME_MODE)ChartGetInteger(m_chart_id,CHART_SHOW_VOLUMES)); + } +//+------------------------------------------------------------------+ +//| Set value of the "ShowVolumes" property | +//+------------------------------------------------------------------+ +bool CChart::ShowVolumes(const ENUM_CHART_VOLUME_MODE show) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_SHOW_VOLUMES,show)); + } +//+------------------------------------------------------------------+ +//| Get value of the "ShowObjectDescr" property | +//+------------------------------------------------------------------+ +bool CChart::ShowObjectDescr(void) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartGetInteger(m_chart_id,CHART_SHOW_OBJECT_DESCR)); + } +//+------------------------------------------------------------------+ +//| Set value of the "ShowObjectDescr" property | +//+------------------------------------------------------------------+ +bool CChart::ShowObjectDescr(const bool show) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_SHOW_OBJECT_DESCR,show)); + } +//+------------------------------------------------------------------+ +//| Set value of the "ShowDateScale" property | +//+------------------------------------------------------------------+ +bool CChart::ShowDateScale(const bool show) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_SHOW_DATE_SCALE,show)); + } +//+------------------------------------------------------------------+ +//| Set value of the "ShowPriceScale" property | +//+------------------------------------------------------------------+ +bool CChart::ShowPriceScale(const bool show) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_SHOW_PRICE_SCALE,show)); + } +//+------------------------------------------------------------------+ +//| Get color value of the "Background" property | +//+------------------------------------------------------------------+ +color CChart::ColorBackground(void) const + { +//--- check + if(m_chart_id==-1) + return(CLR_NONE); +//--- result + return((color)ChartGetInteger(m_chart_id,CHART_COLOR_BACKGROUND)); + } +//+------------------------------------------------------------------+ +//| Set color value of the "Background" property | +//+------------------------------------------------------------------+ +bool CChart::ColorBackground(const color new_color) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_COLOR_BACKGROUND,new_color)); + } +//+------------------------------------------------------------------+ +//| Get color value of the "Foreground" property | +//+------------------------------------------------------------------+ +color CChart::ColorForeground(void) const + { +//--- check + if(m_chart_id==-1) + return(CLR_NONE); +//--- result + return((color)ChartGetInteger(m_chart_id,CHART_COLOR_FOREGROUND)); + } +//+------------------------------------------------------------------+ +//| Set color value for the "Foreground" property | +//+------------------------------------------------------------------+ +bool CChart::ColorForeground(const color new_color) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_COLOR_FOREGROUND,new_color)); + } +//+------------------------------------------------------------------+ +//| Get color value of the "Grid" property | +//+------------------------------------------------------------------+ +color CChart::ColorGrid(void) const + { +//--- check + if(m_chart_id==-1) + return(CLR_NONE); +//--- result + return((color)ChartGetInteger(m_chart_id,CHART_COLOR_GRID)); + } +//+------------------------------------------------------------------+ +//| Set color value for the "Grid" property | +//+------------------------------------------------------------------+ +bool CChart::ColorGrid(const color new_color) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_COLOR_GRID,new_color)); + } +//+------------------------------------------------------------------+ +//| Get color value of the "Bar Up" property | +//+------------------------------------------------------------------+ +color CChart::ColorBarUp(void) const + { +//--- check + if(m_chart_id==-1) + return(CLR_NONE); +//--- result + return((color)ChartGetInteger(m_chart_id,CHART_COLOR_CHART_UP)); + } +//+------------------------------------------------------------------+ +//| Set color value of the "Bar Up" property | +//+------------------------------------------------------------------+ +bool CChart::ColorBarUp(const color new_color) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_COLOR_CHART_UP,new_color)); + } +//+------------------------------------------------------------------+ +//| Get color value of the "Bar Down" property | +//+------------------------------------------------------------------+ +color CChart::ColorBarDown(void) const + { +//--- check + if(m_chart_id==-1) + return(CLR_NONE); +//--- result + return((color)ChartGetInteger(m_chart_id,CHART_COLOR_CHART_DOWN)); + } +//+------------------------------------------------------------------+ +//| Set color value of the "Bar Down" property | +//+------------------------------------------------------------------+ +bool CChart::ColorBarDown(const color new_color) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_COLOR_CHART_DOWN,new_color)); + } +//+------------------------------------------------------------------+ +//| Get color value of the "Candle Bull" property | +//+------------------------------------------------------------------+ +color CChart::ColorCandleBull(void) const + { +//--- check + if(m_chart_id==-1) + return(CLR_NONE); +//--- result + return((color)ChartGetInteger(m_chart_id,CHART_COLOR_CANDLE_BULL)); + } +//+------------------------------------------------------------------+ +//| Set color value of the "Candle Bull" property | +//+------------------------------------------------------------------+ +bool CChart::ColorCandleBull(const color new_color) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_COLOR_CANDLE_BULL,new_color)); + } +//+------------------------------------------------------------------+ +//| Get color value of the "Candle Bear" property | +//+------------------------------------------------------------------+ +color CChart::ColorCandleBear(void) const + { +//--- check + if(m_chart_id==-1) + return(CLR_NONE); +//--- result + return((color)ChartGetInteger(m_chart_id,CHART_COLOR_CANDLE_BEAR)); + } +//+------------------------------------------------------------------+ +//| Set color value of the "Candle Bear" property | +//+------------------------------------------------------------------+ +bool CChart::ColorCandleBear(const color new_color) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_COLOR_CANDLE_BEAR,new_color)); + } +//+------------------------------------------------------------------+ +//| Get color value of the "Chart Line" property | +//+------------------------------------------------------------------+ +color CChart::ColorChartLine(void) const + { +//--- check + if(m_chart_id==-1) + return(CLR_NONE); +//--- result + return((color)ChartGetInteger(m_chart_id,CHART_COLOR_CHART_LINE)); + } +//+------------------------------------------------------------------+ +//| Set color value of the "Chart Line" property | +//+------------------------------------------------------------------+ +bool CChart::ColorChartLine(const color new_color) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_COLOR_CHART_LINE,new_color)); + } +//+------------------------------------------------------------------+ +//| Get color value of the "Volumes" property | +//+------------------------------------------------------------------+ +color CChart::ColorVolumes(void) const + { +//--- check + if(m_chart_id==-1) + return(CLR_NONE); +//--- result + return((color)ChartGetInteger(m_chart_id,CHART_COLOR_VOLUME)); + } +//+------------------------------------------------------------------+ +//| Set color value of the "Volumes" property | +//+------------------------------------------------------------------+ +bool CChart::ColorVolumes(const color new_color) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_COLOR_VOLUME,new_color)); + } +//+------------------------------------------------------------------+ +//| Get color value of the "Line Bid" property | +//+------------------------------------------------------------------+ +color CChart::ColorLineBid(void) const + { +//--- check + if(m_chart_id==-1) + return(CLR_NONE); +//--- result + return((color)ChartGetInteger(m_chart_id,CHART_COLOR_BID)); + } +//+------------------------------------------------------------------+ +//| Set color value of the "Line Bid" property | +//+------------------------------------------------------------------+ +bool CChart::ColorLineBid(const color new_color) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_COLOR_BID,new_color)); + } +//+------------------------------------------------------------------+ +//| Get color value of the "Line Ask" property | +//+------------------------------------------------------------------+ +color CChart::ColorLineAsk(void) const + { +//--- check + if(m_chart_id==-1) + return(CLR_NONE); +//--- result + return((color)ChartGetInteger(m_chart_id,CHART_COLOR_ASK)); + } +//+------------------------------------------------------------------+ +//| Set color value of the "Line Ask" property | +//+------------------------------------------------------------------+ +bool CChart::ColorLineAsk(const color new_color) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_COLOR_ASK,new_color)); + } +//+------------------------------------------------------------------+ +//| Get color value of the "Line Last" property | +//+------------------------------------------------------------------+ +color CChart::ColorLineLast(void) const + { +//--- check + if(m_chart_id==-1) + return(CLR_NONE); +//--- result + return((color)ChartGetInteger(m_chart_id,CHART_COLOR_LAST)); + } +//+------------------------------------------------------------------+ +//| Set color value of the "Line Last" property | +//+------------------------------------------------------------------+ +bool CChart::ColorLineLast(const color new_color) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_COLOR_LAST,new_color)); + } +//+------------------------------------------------------------------+ +//| Get color value of the "Stop Levels" property | +//+------------------------------------------------------------------+ +color CChart::ColorStopLevels(void) const + { +//--- check + if(m_chart_id==-1) + return(CLR_NONE); +//--- result + return((color)ChartGetInteger(m_chart_id,CHART_COLOR_STOP_LEVEL)); + } +//+------------------------------------------------------------------+ +//| Set color value of the "Stop Levels" property | +//+------------------------------------------------------------------+ +bool CChart::ColorStopLevels(const color new_color) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_COLOR_STOP_LEVEL,new_color)); + } +//+------------------------------------------------------------------+ +//| Shows chart always on top | +//+------------------------------------------------------------------+ +bool CChart::BringToTop(void) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_BRING_TO_TOP,true)); + } +//+------------------------------------------------------------------+ +//| Sets flag to generate event of creating objects | +//+------------------------------------------------------------------+ +bool CChart::EventObjectCreate(const bool flag) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_EVENT_OBJECT_CREATE,flag)); + } +//+------------------------------------------------------------------+ +//| Sets flag to generate event of deleting objects | +//+------------------------------------------------------------------+ +bool CChart::EventObjectDelete(const bool flag) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_EVENT_OBJECT_DELETE,flag)); + } +//+------------------------------------------------------------------+ +//| Sets flag to generate event of moving mouse cursor | +//+------------------------------------------------------------------+ +bool CChart::EventMouseMove(const bool flag) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_EVENT_MOUSE_MOVE,flag)); + } +//+------------------------------------------------------------------+ +//| Sets flag to mouse scrolling | +//+------------------------------------------------------------------+ +bool CChart::MouseScroll(const bool flag) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetInteger(m_chart_id,CHART_MOUSE_SCROLL,flag)); + } +//+------------------------------------------------------------------+ +//| Get value of the "VisibleBars" property | +//+------------------------------------------------------------------+ +int CChart::VisibleBars(void) const + { +//--- check + if(m_chart_id==-1) + return(0); +//--- result + return((int)ChartGetInteger(m_chart_id,CHART_WIDTH_IN_BARS)); + } +//+------------------------------------------------------------------+ +//| Get value of the "WindowsTotal" property | +//+------------------------------------------------------------------+ +int CChart::WindowsTotal(void) const + { +//--- check + if(m_chart_id==-1) + return(0); +//--- result + return((int)ChartGetInteger(m_chart_id,CHART_WINDOWS_TOTAL)); + } +//+------------------------------------------------------------------+ +//| Get value of the "WindowIsVisible" property | +//+------------------------------------------------------------------+ +bool CChart::WindowIsVisible(const int num) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartGetInteger(m_chart_id,CHART_WINDOW_IS_VISIBLE,num)); + } +//+------------------------------------------------------------------+ +//| Get value of the "WindowHandle" property | +//+------------------------------------------------------------------+ +int CChart::WindowHandle(void) const + { +//--- check + if(m_chart_id==-1) + return(INVALID_HANDLE); +//--- result + return((int)ChartGetInteger(m_chart_id,CHART_WINDOW_HANDLE)); + } +//+------------------------------------------------------------------+ +//| Get value of the "FirstVisibleBar" property | +//+------------------------------------------------------------------+ +int CChart::FirstVisibleBar(void) const + { +//--- check + if(m_chart_id==-1) + return(-1); +//--- result + return((int)ChartGetInteger(m_chart_id,CHART_FIRST_VISIBLE_BAR)); + } +//+------------------------------------------------------------------+ +//| Get value of the "WidthInBars" property | +//+------------------------------------------------------------------+ +int CChart::WidthInBars(void) const + { +//--- check + if(m_chart_id==-1) + return(0); +//--- result + return((int)ChartGetInteger(m_chart_id,CHART_WIDTH_IN_BARS)); + } +//+------------------------------------------------------------------+ +//| Get value of the "WidthInPixels" property | +//+------------------------------------------------------------------+ +int CChart::WidthInPixels(void) const + { +//--- check + if(m_chart_id==-1) + return(0); +//--- result + return((int)ChartGetInteger(m_chart_id,CHART_WIDTH_IN_PIXELS)); + } +//+------------------------------------------------------------------+ +//| Get value of the "HeightInPixels" property | +//+------------------------------------------------------------------+ +int CChart::HeightInPixels(const int num) const + { +//--- check + if(m_chart_id==-1) + return(0); +//--- result + return((int)ChartGetInteger(m_chart_id,CHART_HEIGHT_IN_PIXELS,num)); + } +//+------------------------------------------------------------------+ +//| Get value of the "WindowYDistance" property | +//+------------------------------------------------------------------+ +int CChart::SubwindowY(const int num) const + { +//--- check + if(m_chart_id==-1) + return(0); +//--- result + return((int)ChartGetInteger(m_chart_id,CHART_WINDOW_YDISTANCE,num)); + } +//+------------------------------------------------------------------+ +//| Get value of the "PriceMin" property | +//+------------------------------------------------------------------+ +double CChart::PriceMin(const int num) const + { +//--- check + if(m_chart_id==-1) + return(EMPTY_VALUE); +//--- result + return(ChartGetDouble(m_chart_id,CHART_PRICE_MIN,num)); + } +//+------------------------------------------------------------------+ +//| Get value of the "PriceMax" property | +//+------------------------------------------------------------------+ +double CChart::PriceMax(const int num) const + { +//--- check + if(m_chart_id==-1) + return(EMPTY_VALUE); +//--- result + return(ChartGetDouble(m_chart_id,CHART_PRICE_MAX,num)); + } +//+------------------------------------------------------------------+ +//| Get value of the "IsObject" property | +//+------------------------------------------------------------------+ +bool CChart::IsObject(void) const + { +//--- check + if(m_chart_id==-1) + return(EMPTY_VALUE); +//--- result + return((bool)ChartGetInteger(m_chart_id,CHART_IS_OBJECT)); + } +//+------------------------------------------------------------------+ +//| Chart close | +//+------------------------------------------------------------------+ +void CChart::Close(void) + { + if(m_chart_id!=-1) + { + ChartClose(m_chart_id); + m_chart_id=-1; + } + } +//+------------------------------------------------------------------+ +//| Chart navigation | +//+------------------------------------------------------------------+ +bool CChart::Navigate(const ENUM_CHART_POSITION position,const int shift) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartNavigate(m_chart_id,position,shift)); + } +//+------------------------------------------------------------------+ +//| Access functions long ChartGetInteger(...) | +//+------------------------------------------------------------------+ +long CChart::GetInteger(const ENUM_CHART_PROPERTY_INTEGER prop_id,const int subwindow) const + { +//--- check + if(m_chart_id==-1) + return(0); +//--- result + return(ChartGetInteger(m_chart_id,prop_id,subwindow)); + } +//+------------------------------------------------------------------+ +//| Access function bool ChartGetInteger(...) | +//+------------------------------------------------------------------+ +bool CChart::GetInteger(const ENUM_CHART_PROPERTY_INTEGER prop_id,const int subwindow,long &value) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartGetInteger(m_chart_id,prop_id,subwindow,value)); + } +//+------------------------------------------------------------------+ +//| Access function ChartSetInteger(...) | +//+------------------------------------------------------------------+ +bool CChart::SetInteger(const ENUM_CHART_PROPERTY_INTEGER prop_id,const long value) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- + return(ChartSetInteger(m_chart_id,prop_id,value)); + } +//+------------------------------------------------------------------+ +//| Access function double ChartGetDouble(...) | +//+------------------------------------------------------------------+ +double CChart::GetDouble(const ENUM_CHART_PROPERTY_DOUBLE prop_id,const int subwindow) const + { +//--- check + if(m_chart_id==-1) + return(EMPTY_VALUE); +//--- result + return(ChartGetDouble(m_chart_id,prop_id,subwindow)); + } +//+------------------------------------------------------------------+ +//| Access function bool ChartGetDouble(...) | +//+------------------------------------------------------------------+ +bool CChart::GetDouble(const ENUM_CHART_PROPERTY_DOUBLE prop_id,const int subwindow,double &value) const + { +//--- check + if(m_chart_id==-1) + return(0); +//--- result + return(ChartGetDouble(m_chart_id,prop_id,subwindow,value)); + } +//+------------------------------------------------------------------+ +//| Access function ChartSetDouble(...) | +//+------------------------------------------------------------------+ +bool CChart::SetDouble(const ENUM_CHART_PROPERTY_DOUBLE prop_id,const double value) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetDouble(m_chart_id,prop_id,value)); + } +//+------------------------------------------------------------------+ +//| Access function string ChartGetString(...) | +//+------------------------------------------------------------------+ +string CChart::GetString(const ENUM_CHART_PROPERTY_STRING prop_id) const + { +//--- check + if(m_chart_id==-1) + return(""); +//--- result + return(ChartGetString(m_chart_id,prop_id)); + } +//+------------------------------------------------------------------+ +//| Access functions bool ChartGetString(...) | +//+------------------------------------------------------------------+ +bool CChart::GetString(const ENUM_CHART_PROPERTY_STRING prop_id,string &value) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartGetString(m_chart_id,prop_id,value)); + } +//+------------------------------------------------------------------+ +//| Access function ChartSetString(...) | +//+------------------------------------------------------------------+ +bool CChart::SetString(const ENUM_CHART_PROPERTY_STRING prop_id,const string value) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetString(m_chart_id,prop_id,value)); + } +//+------------------------------------------------------------------+ +//| Access function ChartSetSymbolPeriod(...) | +//+------------------------------------------------------------------+ +bool CChart::SetSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartSetSymbolPeriod(m_chart_id,symbol,period)); + } +//+------------------------------------------------------------------+ +//| Access function ChartApplyTemplate(...) | +//+------------------------------------------------------------------+ +bool CChart::ApplyTemplate(const string filename) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartApplyTemplate(m_chart_id,filename)); + } +//+------------------------------------------------------------------+ +//| Access function ChartScreenShot(...) | +//+------------------------------------------------------------------+ +bool CChart::ScreenShot(const string filename,const int width,const int height,const ENUM_ALIGN_MODE align_mode) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartScreenShot(m_chart_id,filename,width,height,align_mode)); + } +//+------------------------------------------------------------------+ +//| Access function WindowOnDropped() | +//+------------------------------------------------------------------+ +int CChart::WindowOnDropped(void) const + { +//--- check + if(m_chart_id==-1) + return(0); +//--- result + return(ChartWindowOnDropped()); + } +//+------------------------------------------------------------------+ +//| Access function PriceOnDropped() | +//+------------------------------------------------------------------+ +double CChart::PriceOnDropped(void) const + { +//--- check + if(m_chart_id==-1) + return(EMPTY_VALUE); +//--- result + return(ChartPriceOnDropped()); + } +//+------------------------------------------------------------------+ +//| Access function TimeOnDropped() | +//+------------------------------------------------------------------+ +datetime CChart::TimeOnDropped(void) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartTimeOnDropped()); + } +//+------------------------------------------------------------------+ +//| Access functions XOnDropped() | +//+------------------------------------------------------------------+ +int CChart::XOnDropped(void) const + { +//--- check + if(m_chart_id==-1) + return(0); +//--- result + return(ChartXOnDropped()); + } +//+------------------------------------------------------------------+ +//| Access functions YOnDropped() | +//+------------------------------------------------------------------+ +int CChart::YOnDropped(void) const + { +//--- check + if(m_chart_id==-1) + return(0); +//--- result + return(ChartYOnDropped()); + } +//+------------------------------------------------------------------+ +//| Adds indicator to chart | +//+------------------------------------------------------------------+ +bool CChart::IndicatorAdd(const int subwin,const int handle) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartIndicatorAdd(m_chart_id,subwin,handle)); + } +//+------------------------------------------------------------------+ +//| Deletes indicator from chart | +//+------------------------------------------------------------------+ +bool CChart::IndicatorDelete(const int subwin,const string name) const + { +//--- check + if(m_chart_id==-1) + return(false); +//--- result + return(ChartIndicatorDelete(m_chart_id,subwin,name)); + } +//+------------------------------------------------------------------+ +//| Gets number of indicators in chart subwindow | +//+------------------------------------------------------------------+ +int CChart::IndicatorsTotal(const int subwin) const + { +//--- check + if(m_chart_id==-1) + return(0); +//--- result + return(ChartIndicatorsTotal(m_chart_id,subwin)); + } +//+------------------------------------------------------------------+ +//| Gets short name of indicator | +//+------------------------------------------------------------------+ +string CChart::IndicatorName(const int subwin,const int index) const + { +//--- check + if(m_chart_id==-1) + return(""); +//--- result + return(ChartIndicatorName(m_chart_id,subwin,index)); + } +//+------------------------------------------------------------------+ +//| Writing parameters of chart to file | +//+------------------------------------------------------------------+ +bool CChart::Save(const int file_handle) + { + string work_str; + int work_int; +//--- check + if(file_handle==INVALID_HANDLE || m_chart_id==-1) + return(false); +//--- write start marker - 0xFFFFFFFFFFFFFFFF + if(FileWriteLong(file_handle,-1)!=sizeof(long)) + return(false); +//--- write chart type + if(FileWriteInteger(file_handle,Type(),INT_VALUE)!=INT_VALUE) + return(false); +//--- write chart symbol + work_str=Symbol(); + work_int=StringLen(work_str); + if(FileWriteInteger(file_handle,work_int,INT_VALUE)!=INT_VALUE) + return(false); + if(work_int!=0) if(FileWriteString(file_handle,work_str,work_int)!=work_int) + return(false); +//--- write period of chart + if(FileWriteInteger(file_handle,Period(),INT_VALUE)!=sizeof(int)) + return(false); +//--- write value of the "Mode" property + if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_MODE),INT_VALUE)!=sizeof(int)) + return(false); +//--- write value of the "Foreground" property + if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_FOREGROUND),CHAR_VALUE)!=sizeof(char)) + return(false); +//--- write value of the "Shift" property + if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SHIFT),CHAR_VALUE)!=sizeof(char)) + return(false); +//--- write value of the "ShiftSize" property + if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SHIFT),INT_VALUE)!=sizeof(int)) + return(false); +//--- write value of the "AutoScroll" property + if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_AUTOSCROLL),CHAR_VALUE)!=sizeof(char)) + return(false); +//--- write value of the "Scale" property + if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SCALE),INT_VALUE)!=sizeof(int)) + return(false); +//--- write value of the "ScaleFix" property + if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SCALEFIX),CHAR_VALUE)!=sizeof(char)) + return(false); +//--- write value of the "ScaleFix_11" property + if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SCALEFIX_11),CHAR_VALUE)!=sizeof(char)) + return(false); +//--- write value of the "FixedMax" property + if(FileWriteDouble(file_handle,ChartGetDouble(m_chart_id,CHART_FIXED_MAX))!=sizeof(double)) + return(false); +//--- write value of the "FixedMin" property + if(FileWriteDouble(file_handle,ChartGetDouble(m_chart_id,CHART_FIXED_MIN))!=sizeof(double)) + return(false); +//--- write the "ScalePPB" property + if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SCALE_PT_PER_BAR),CHAR_VALUE)!=sizeof(char)) + return(false); +//--- write value of the "PointsPerBar" property + if(FileWriteDouble(file_handle,ChartGetDouble(m_chart_id,CHART_POINTS_PER_BAR))!=sizeof(double)) + return(false); +//--- write value of the "ShowOHLC" property + if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SHOW_OHLC),CHAR_VALUE)!=sizeof(char)) + return(false); +//--- write value of the "ShowLineBid" property + if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SHOW_BID_LINE),CHAR_VALUE)!=sizeof(char)) + return(false); +//--- write value of the "ShowLineAsk" property + if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SHOW_ASK_LINE),CHAR_VALUE)!=sizeof(char)) + return(false); +//--- write value of the "ShowLastLine" property + if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SHOW_LAST_LINE),CHAR_VALUE)!=sizeof(char)) + return(false); +//--- write value of the "ShowPeriodSep" property + if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SHOW_PERIOD_SEP),CHAR_VALUE)!=sizeof(char)) + return(false); +//--- write value of the "ShowGrid" property + if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SHOW_GRID),CHAR_VALUE)!=sizeof(char)) + return(false); +//--- write value of the "ShowVolumes" property + if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SHOW_VOLUMES),INT_VALUE)!=sizeof(int)) + return(false); +//--- write value of the "ShowObjectDescr" property + if(FileWriteInteger(file_handle,(int)ChartGetInteger(m_chart_id,CHART_SHOW_OBJECT_DESCR),CHAR_VALUE)!=sizeof(char)) + return(false); +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| Reading parameters of chart from file | +//+------------------------------------------------------------------+ +bool CChart::Load(const int file_handle) + { + bool resutl=true; + string work_str; + int work_int; +//--- check + if(file_handle==INVALID_HANDLE || m_chart_id==-1) + return(false); +//--- read and checking start marker - 0xFFFFFFFFFFFFFFFF + if(FileReadLong(file_handle)!=-1) return(false); +//--- read and checking chart type + if(FileReadInteger(file_handle,INT_VALUE)!=Type()) return(false); +//--- read chart symbol + work_int=FileReadInteger(file_handle); + if(work_int!=0) work_str=FileReadString(file_handle,work_int); + else work_str=""; +//--- read chart period + work_int=FileReadInteger(file_handle); + SetSymbolPeriod(work_str,(ENUM_TIMEFRAMES)work_int); +//--- read value of the "Mode" property + if(!ChartSetInteger(m_chart_id,CHART_MODE,FileReadInteger(file_handle,INT_VALUE))) + return(false); +//--- read value of the "Foreground" property + if(!ChartSetInteger(m_chart_id,CHART_FOREGROUND,FileReadInteger(file_handle,CHAR_VALUE))) + return(false); +//--- read value of the "Shift" property + if(!ChartSetInteger(m_chart_id,CHART_SHIFT,FileReadInteger(file_handle,CHAR_VALUE))) + return(false); +//--- read value of the "ShiftSize" property + if(!ChartSetInteger(m_chart_id,CHART_SHIFT,FileReadInteger(file_handle,INT_VALUE))) + return(false); +//--- read value of the "AutoScroll" property + if(!ChartSetInteger(m_chart_id,CHART_AUTOSCROLL,FileReadInteger(file_handle,CHAR_VALUE))) + return(false); +//--- read value of the "Scale" property + if(!ChartSetInteger(m_chart_id,CHART_SCALE,FileReadInteger(file_handle,INT_VALUE))) + return(false); +//--- read value of the "ScaleFix" property + if(!ChartSetInteger(m_chart_id,CHART_SCALEFIX,FileReadInteger(file_handle,CHAR_VALUE))) + return(false); +//--- read value of the "ScaleFix_11" property + if(!ChartSetInteger(m_chart_id,CHART_SCALEFIX_11,FileReadInteger(file_handle,CHAR_VALUE))) + return(false); +//--- read value of the "FixedMax" property + if(!ChartSetDouble(m_chart_id,CHART_FIXED_MAX,FileReadDatetime(file_handle))) + return(false); +//--- read value of the "FixedMin" property + if(!ChartSetDouble(m_chart_id,CHART_FIXED_MIN,FileReadDatetime(file_handle))) + return(false); +//--- read value of the "ScalePPB" property + if(!ChartSetInteger(m_chart_id,CHART_SCALE_PT_PER_BAR,FileReadInteger(file_handle,CHAR_VALUE))) + return(false); +//--- read value of the "PointsPerBar" property + if(!ChartSetDouble(m_chart_id,CHART_POINTS_PER_BAR,FileReadDatetime(file_handle))) + return(false); +//--- read value of the "ShowOHLC" property + if(!ChartSetInteger(m_chart_id,CHART_SHOW_OHLC,FileReadInteger(file_handle,CHAR_VALUE))) + return(false); +//--- read value of the "ShowLineBid" property + if(!ChartSetInteger(m_chart_id,CHART_SHOW_BID_LINE,FileReadInteger(file_handle,CHAR_VALUE))) + return(false); +//--- read value of the "ShowLineAsk" property + if(!ChartSetInteger(m_chart_id,CHART_SHOW_ASK_LINE,FileReadInteger(file_handle,CHAR_VALUE))) + return(false); +//--- read value of the "ShowLastLine" property + if(!ChartSetInteger(m_chart_id,CHART_SHOW_LAST_LINE,FileReadInteger(file_handle,CHAR_VALUE))) + return(false); +//--- read value of the "ShowPeriodSep" property + if(!ChartSetInteger(m_chart_id,CHART_SHOW_PERIOD_SEP,FileReadInteger(file_handle,CHAR_VALUE))) + return(false); +//--- read value of the "ShowGrid" property + if(!ChartSetInteger(m_chart_id,CHART_SHOW_GRID,FileReadInteger(file_handle,CHAR_VALUE))) + return(false); +//--- read value of the "ShowVolumes" property + if(!ChartSetInteger(m_chart_id,CHART_SHOW_VOLUMES,FileReadInteger(file_handle,INT_VALUE))) + return(false); +//--- read value of the "ShowObjectDescr" property + if(!ChartSetInteger(m_chart_id,CHART_SHOW_OBJECT_DESCR,FileReadInteger(file_handle,CHAR_VALUE))) + return(false); +//--- successful + return(resutl); + } +//+------------------------------------------------------------------+ diff --git a/Include/Controls/BmpButton.mqh b/Include/Controls/BmpButton.mqh new file mode 100644 index 0000000..080541d --- /dev/null +++ b/Include/Controls/BmpButton.mqh @@ -0,0 +1,268 @@ +//+------------------------------------------------------------------+ +//| BmpButton.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include "WndObj.mqh" +#include +//+------------------------------------------------------------------+ +//| Class CBmpButton | +//| Usage: control that is displayed by | +//| the CChartObjectBmpLabel object | +//+------------------------------------------------------------------+ +class CBmpButton : public CWndObj + { +private: + CChartObjectBmpLabel m_button; // chart object + //--- parameters of the chart object + int m_border; // border width + string m_bmp_off_name; // name of BMP file for the "OFF" state (default state) + string m_bmp_on_name; // name of BMP file for the "ON" state + string m_bmp_passive_name; + string m_bmp_active_name; + +public: + CBmpButton(void); + ~CBmpButton(void); + //--- create + virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2); + //--- parameters of the chart object + int Border(void) const { return(m_border); } + bool Border(const int value); + bool BmpNames(const string off="",const string on=""); + string BmpOffName(void) const { return(m_bmp_off_name); } + bool BmpOffName(const string name); + string BmpOnName(void) const { return(m_bmp_on_name); } + bool BmpOnName(const string name); + string BmpPassiveName(void) const { return(m_bmp_passive_name); } + bool BmpPassiveName(const string name); + string BmpActiveName(void) const { return(m_bmp_active_name); } + bool BmpActiveName(const string name); + //--- state + bool Pressed(void) const { return(m_button.State()); } + bool Pressed(const bool pressed) { return(m_button.State(pressed)); } + //--- properties + bool Locking(void) const { return(IS_CAN_LOCK); } + void Locking(const bool locking); + +protected: + //--- handlers of object settings + virtual bool OnSetZOrder(void) { return(m_button.Z_Order(m_zorder)); } + //--- internal event handlers + virtual bool OnCreate(void); + virtual bool OnShow(void); + virtual bool OnHide(void); + virtual bool OnMove(void); + virtual bool OnChange(void); + //--- íîâûå îáðàáîò÷èêè + virtual bool OnActivate(void); + virtual bool OnDeactivate(void); + virtual bool OnMouseDown(void); + virtual bool OnMouseUp(void); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CBmpButton::CBmpButton(void) : m_border(0), + m_bmp_off_name(NULL), + m_bmp_on_name(NULL), + m_bmp_passive_name(NULL), + m_bmp_active_name(NULL) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CBmpButton::~CBmpButton(void) + { + } +//+------------------------------------------------------------------+ +//| Create a control | +//+------------------------------------------------------------------+ +bool CBmpButton::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) + { +//--- call method of the parent class + if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2)) + return(false); +//--- create the chart object + if(!m_button.Create(chart,name,subwin,x1,y1)) + return(false); +//--- call the settings handler + return(OnChange()); + } +//+------------------------------------------------------------------+ +//| Set border width | +//+------------------------------------------------------------------+ +bool CBmpButton::Border(const int value) + { +//--- save new value of parameter + m_border=value; +//--- set up the chart object + return(m_button.Width(value)); + } +//+------------------------------------------------------------------+ +//| Set two images at once | +//+------------------------------------------------------------------+ +bool CBmpButton::BmpNames(const string off,const string on) + { +//--- save new values of parameters + m_bmp_off_name=off; + m_bmp_on_name =on; +//--- set up the chart object + if(!m_button.BmpFileOff(off)) + return(false); + if(!m_button.BmpFileOn(on)) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Set image for the "OFF" state | +//+------------------------------------------------------------------+ +bool CBmpButton::BmpOffName(const string name) + { +//--- save new value of parameter + m_bmp_off_name=name; +//--- set up the chart object + if(!m_button.BmpFileOff(name)) + return(false); +//--- set size by image dimensions + Width(m_button.X_Size()); + Height(m_button.Y_Size()); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Set image for the "ON" state | +//+------------------------------------------------------------------+ +bool CBmpButton::BmpOnName(const string name) + { +//--- save new value of parameter + m_bmp_on_name=name; +//--- set up the chart object + if(!m_button.BmpFileOn(name)) + return(false); +//--- set size by image dimensions + Width(m_button.X_Size()); + Height(m_button.Y_Size()); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Set image for the "OFF" state (passive) | +//+------------------------------------------------------------------+ +bool CBmpButton::BmpPassiveName(const string name) + { +//--- save new value of parameter + m_bmp_passive_name=name; +//--- set up the chart object + if(!IS_ACTIVE) + return(BmpOffName(name)); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Set image for the "OFF" state (active) | +//+------------------------------------------------------------------+ +bool CBmpButton::BmpActiveName(const string name) + { +//--- save new value of parameter + m_bmp_active_name=name; +//--- set up the chart object + if(IS_ACTIVE) + return(BmpOffName(name)); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Locking flag | +//+------------------------------------------------------------------+ +void CBmpButton::Locking(const bool flag) + { + if(flag) + PropFlagsSet(WND_PROP_FLAG_CAN_LOCK); + else + PropFlagsReset(WND_PROP_FLAG_CAN_LOCK); + } +//+------------------------------------------------------------------+ +//| Create object on chart | +//+------------------------------------------------------------------+ +bool CBmpButton::OnCreate(void) + { +//--- create the chart object by previously set parameters + return(m_button.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top)); + } +//+------------------------------------------------------------------+ +//| Display object on chart | +//+------------------------------------------------------------------+ +bool CBmpButton::OnShow(void) + { + return(m_button.Timeframes(OBJ_ALL_PERIODS)); + } +//+------------------------------------------------------------------+ +//| Hide object from chart | +//+------------------------------------------------------------------+ +bool CBmpButton::OnHide(void) + { + return(m_button.Timeframes(OBJ_NO_PERIODS)); + } +//+------------------------------------------------------------------+ +//| Absolute movement of the chart object | +//+------------------------------------------------------------------+ +bool CBmpButton::OnMove(void) + { +//--- position the chart object + return(m_button.X_Distance(m_rect.left) && m_button.Y_Distance(m_rect.top)); + } +//+------------------------------------------------------------------+ +//| Set up the chart object | +//+------------------------------------------------------------------+ +bool CBmpButton::OnChange(void) + { +//--- set up the chart object + return(m_button.Width(m_border) && m_button.BmpFileOff(m_bmp_off_name) && m_button.BmpFileOn(m_bmp_on_name)); + } +//+------------------------------------------------------------------+ +//| Handler of activating the group of controls | +//+------------------------------------------------------------------+ +bool CBmpButton::OnActivate(void) + { + if(m_bmp_active_name!=NULL) + BmpOffName(m_bmp_active_name); +//--- handled + return(true); + } +//+------------------------------------------------------------------+ +//| Handler of deactivating the group of controls | +//+------------------------------------------------------------------+ +bool CBmpButton::OnDeactivate(void) + { + if(m_bmp_passive_name!=NULL) + BmpOffName(m_bmp_passive_name); + if(!IS_CAN_LOCK) + Pressed(false); +//--- handled + return(true); + } +//+------------------------------------------------------------------+ +//| Handler of click on the left mouse button | +//+------------------------------------------------------------------+ +bool CBmpButton::OnMouseDown(void) + { + if(!IS_CAN_LOCK) + Pressed(!Pressed()); +//--- call of the method of the parent class + return(CWnd::OnMouseDown()); + } +//+------------------------------------------------------------------+ +//| Handler of click on the left mouse button | +//+------------------------------------------------------------------+ +bool CBmpButton::OnMouseUp(void) + { +//--- depress the button if it is not fixed + if(m_button.State() && !IS_CAN_LOCK) + m_button.State(false); +//--- call of the method of the parent class + return(CWnd::OnMouseUp()); + } +//+------------------------------------------------------------------+ diff --git a/Include/Controls/Button.mqh b/Include/Controls/Button.mqh new file mode 100644 index 0000000..08d5a76 --- /dev/null +++ b/Include/Controls/Button.mqh @@ -0,0 +1,146 @@ +//+------------------------------------------------------------------+ +//| Button.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include "WndObj.mqh" +#include +//+------------------------------------------------------------------+ +//| Class CButton | +//| Usage: control that is displayed by | +//| the CChartObjectButton object | +//+------------------------------------------------------------------+ +class CButton : public CWndObj + { +private: + CChartObjectButton m_button; // chart object + +public: + CButton(void); + ~CButton(void); + //--- create + virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2); + //--- state + bool Pressed(void) const { return(m_button.State()); } + bool Pressed(const bool pressed) { return(m_button.State(pressed)); } + //--- properties + bool Locking(void) const { return(IS_CAN_LOCK); } + void Locking(const bool flag); + +protected: + //--- handlers of object settings + virtual bool OnSetText(void) { return(m_button.Description(m_text)); } + virtual bool OnSetColor(void) { return(m_button.Color(m_color)); } + virtual bool OnSetColorBackground(void) { return(m_button.BackColor(m_color_background)); } + virtual bool OnSetColorBorder(void) { return(m_button.BorderColor(m_color_border)); } + virtual bool OnSetFont(void) { return(m_button.Font(m_font)); } + virtual bool OnSetFontSize(void) { return(m_button.FontSize(m_font_size)); } + //--- internal event handlers + virtual bool OnCreate(void); + virtual bool OnShow(void); + virtual bool OnHide(void); + virtual bool OnMove(void); + virtual bool OnResize(void); + //--- íîâûå îáðàáîò÷èêè + virtual bool OnMouseDown(void); + virtual bool OnMouseUp(void); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CButton::CButton(void) + { + m_color =CONTROLS_BUTTON_COLOR; + m_color_background=CONTROLS_BUTTON_COLOR_BG; + m_color_border =CONTROLS_BUTTON_COLOR_BORDER; + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CButton::~CButton(void) + { + } +//+------------------------------------------------------------------+ +//| Create a control | +//+------------------------------------------------------------------+ +bool CButton::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) + { +//--- call method of the parent class + if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2)) + return(false); +//--- create the chart object + if(!m_button.Create(chart,name,subwin,x1,y1,Width(),Height())) + return(false); +//--- call the settings handler + return(OnChange()); + } +//+------------------------------------------------------------------+ +//| Locking flag | +//+------------------------------------------------------------------+ +void CButton::Locking(const bool flag) + { + if(flag) + PropFlagsSet(WND_PROP_FLAG_CAN_LOCK); + else + PropFlagsReset(WND_PROP_FLAG_CAN_LOCK); + } +//+------------------------------------------------------------------+ +//| Create object on chart | +//+------------------------------------------------------------------+ +bool CButton::OnCreate(void) + { +//--- create the chart object by previously set parameters + return(m_button.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top,m_rect.Width(),m_rect.Height())); + } +//+------------------------------------------------------------------+ +//| Display object on chart | +//+------------------------------------------------------------------+ +bool CButton::OnShow(void) + { + return(m_button.Timeframes(OBJ_ALL_PERIODS)); + } +//+------------------------------------------------------------------+ +//| Hide object from chart | +//+------------------------------------------------------------------+ +bool CButton::OnHide(void) + { + return(m_button.Timeframes(OBJ_NO_PERIODS)); + } +//+------------------------------------------------------------------+ +//| Absolute movement of the chart object | +//+------------------------------------------------------------------+ +bool CButton::OnMove(void) + { +//--- position the chart object + return(m_button.X_Distance(m_rect.left) && m_button.Y_Distance(m_rect.top)); + } +//+------------------------------------------------------------------+ +//| Resize the chart object | +//+------------------------------------------------------------------+ +bool CButton::OnResize(void) + { +//--- resize the chart object + return(m_button.X_Size(m_rect.Width()) && m_button.Y_Size(m_rect.Height())); + } +//+------------------------------------------------------------------+ +//| Handler of click on the left mouse button | +//+------------------------------------------------------------------+ +bool CButton::OnMouseDown(void) + { + if(!IS_CAN_LOCK) + Pressed(!Pressed()); +//--- call of the method of the parent class + return(CWnd::OnMouseDown()); + } +//+------------------------------------------------------------------+ +//| Handler of click on the left mouse button | +//+------------------------------------------------------------------+ +bool CButton::OnMouseUp(void) + { +//--- depress the button if it is not fixed + if(m_button.State() && !IS_CAN_LOCK) + m_button.State(false); +//--- call of the method of the parent class + return(CWnd::OnMouseUp()); + } +//+------------------------------------------------------------------+ diff --git a/Include/Controls/CheckBox.mqh b/Include/Controls/CheckBox.mqh new file mode 100644 index 0000000..e8186fd --- /dev/null +++ b/Include/Controls/CheckBox.mqh @@ -0,0 +1,183 @@ +//+------------------------------------------------------------------+ +//| CheckBox.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include "WndContainer.mqh" +#include "BmpButton.mqh" +#include "Edit.mqh" +//+------------------------------------------------------------------+ +//| Resources | +//+------------------------------------------------------------------+ +#resource "res\\CheckBoxOn.bmp" +#resource "res\\CheckBoxOff.bmp" +//+------------------------------------------------------------------+ +//| Class CCheckBox | +//| Usage: class that implements the "CheckBox" control | +//+------------------------------------------------------------------+ +class CCheckBox : public CWndContainer + { +private: + //--- dependent controls + CBmpButton m_button; // button object + CEdit m_label; // label object + //--- data + int m_value; // value + +public: + CCheckBox(void); + ~CCheckBox(void); + //--- create + virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2); + //--- chart event handler + virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam); + //--- settings + string Text(void) const { return(m_label.Text()); } + bool Text(const string value) { return(m_label.Text(value)); } + color Color(void) const { return(m_label.Color()); } + bool Color(const color value) { return(m_label.Color(value)); } + //--- state + bool Checked(void) const { return(m_button.Pressed()); } + bool Checked(const bool flag) { return(m_button.Pressed(flag)); } + //--- data + int Value(void) const { return(m_value); } + void Value(const int value) { m_value=value; } + //--- methods for working with files + virtual bool Save(const int file_handle); + virtual bool Load(const int file_handle); + +protected: + //--- create dependent controls + virtual bool CreateButton(void); + virtual bool CreateLabel(void); + //--- handlers of the dependent controls events + virtual bool OnClickButton(void); + virtual bool OnClickLabel(void); + }; +//+------------------------------------------------------------------+ +//| Common handler of chart events | +//+------------------------------------------------------------------+ +EVENT_MAP_BEGIN(CCheckBox) + ON_EVENT(ON_CLICK,m_button,OnClickButton) + ON_EVENT(ON_CLICK,m_label,OnClickLabel) +EVENT_MAP_END(CWndContainer) +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CCheckBox::CCheckBox(void) : m_value(0) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CCheckBox::~CCheckBox(void) + { + } +//+------------------------------------------------------------------+ +//| Create a control | +//+------------------------------------------------------------------+ +bool CCheckBox::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) + { +//--- call method of the parent class + if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2)) + return(false); +//--- create dependent controls + if(!CreateButton()) + return(false); + if(!CreateLabel()) + return(false); +//--- succeeded + return(true); + } +//+------------------------------------------------------------------+ +//| Create button | +//+------------------------------------------------------------------+ +bool CCheckBox::CreateButton(void) + { +//--- calculate coordinates + int x1=CONTROLS_CHECK_BUTTON_X_OFF; + int y1=CONTROLS_CHECK_BUTTON_Y_OFF; + int x2=x1+CONTROLS_BUTTON_SIZE; + int y2=y1+CONTROLS_BUTTON_SIZE-CONTROLS_BORDER_WIDTH; +//--- create + if(!m_button.Create(m_chart_id,m_name+"Button",m_subwin,x1,y1,x2,y2)) + return(false); + if(!m_button.BmpNames("::res\\CheckBoxOff.bmp","::res\\CheckBoxOn.bmp")) + return(false); + if(!Add(m_button)) + return(false); + m_button.Locking(true); +//--- succeeded + return(true); + } +//+------------------------------------------------------------------+ +//| Create label | +//+------------------------------------------------------------------+ +bool CCheckBox::CreateLabel(void) + { +//--- calculate coordinates + int x1=CONTROLS_CHECK_LABEL_X_OFF; + int y1=CONTROLS_CHECK_LABEL_Y_OFF; + int x2=Width(); + int y2=Height(); +//--- create + if(!m_label.Create(m_chart_id,m_name+"Label",m_subwin,x1,y1,x2,y2)) + return(false); + if(!m_label.Text(m_name)) + return(false); + if(!Add(m_label)) + return(false); + m_label.ReadOnly(true); + m_label.ColorBackground(CONTROLS_CHECKGROUP_COLOR_BG); + m_label.ColorBorder(CONTROLS_CHECKGROUP_COLOR_BG); +//--- succeeded + return(true); + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool CCheckBox::Save(const int file_handle) + { +//--- check + if(file_handle==INVALID_HANDLE) + return(false); +//--- + FileWriteInteger(file_handle,Checked()); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool CCheckBox::Load(const int file_handle) + { +//--- check + if(file_handle==INVALID_HANDLE) + return(false); +//--- + if(!FileIsEnding(file_handle)) + Checked(FileReadInteger(file_handle)); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Handler of click on button | +//+------------------------------------------------------------------+ +bool CCheckBox::OnClickButton(void) + { +//--- send the "changed state" event + EventChartCustom(CONTROLS_SELF_MESSAGE,ON_CHANGE,m_id,0.0,m_name); +//--- handled + return(true); + } +//+------------------------------------------------------------------+ +//| Handler of click on label | +//+------------------------------------------------------------------+ +bool CCheckBox::OnClickLabel(void) + { +//--- change button state + m_button.Pressed(!m_button.Pressed()); +//--- return the result of the button click handler + return(OnClickButton()); + } +//+------------------------------------------------------------------+ diff --git a/Include/Controls/CheckGroup.mqh b/Include/Controls/CheckGroup.mqh new file mode 100644 index 0000000..6d5de34 --- /dev/null +++ b/Include/Controls/CheckGroup.mqh @@ -0,0 +1,377 @@ +//+------------------------------------------------------------------+ +//| CheckGroup.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include "WndClient.mqh" +#include "CheckBox.mqh" +#include +#include +#include +//+------------------------------------------------------------------+ +//| Class CCheckGroup | +//| Usage: view and edit group of flags | +//+------------------------------------------------------------------+ +class CCheckGroup : public CWndClient + { +private: + //--- dependent controls + CCheckBox m_rows[]; // array of the row objects + //--- set up + int m_offset; // index of first visible row in array of rows + int m_total_view; // number of visible rows + int m_item_height; // height of visible row + //--- data + CArrayString m_strings; // array of rows + CArrayLong m_values; // array of values + CArrayInt m_states; // array of states + long m_value; // current value + int m_current; // index of current row in array of rows + +public: + CCheckGroup(void); + ~CCheckGroup(void); + //--- create + virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2); + virtual void Destroy(const int reason=0); + //--- chart event handler + virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam); + //--- fill + virtual bool AddItem(const string item,const long value=0); + //--- data + long Value(void) const; + bool Value(const long value); + int Check(const int idx) const; + bool Check(const int idx,const int value); + //--- state + virtual bool Show(void); + //--- methods for working with files + virtual bool Save(const int file_handle); + virtual bool Load(const int file_handle); + +protected: + //--- create dependent controls + bool CreateButton(int index); + //--- handlers of the dependent controls events + virtual bool OnVScrollShow(void); + virtual bool OnVScrollHide(void); + virtual bool OnScrollLineDown(void); + virtual bool OnScrollLineUp(void); + virtual bool OnChangeItem(const int row_index); + //--- redraw + bool Redraw(void); + bool RowState(const int index,const bool select); + }; +//+------------------------------------------------------------------+ +//| Common handler of chart events | +//+------------------------------------------------------------------+ +EVENT_MAP_BEGIN(CCheckGroup) + ON_INDEXED_EVENT(ON_CHANGE,m_rows,OnChangeItem) +EVENT_MAP_END(CWndClient) +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CCheckGroup::CCheckGroup(void) : m_offset(0), + m_total_view(0), + m_item_height(CONTROLS_LIST_ITEM_HEIGHT), + m_current(CONTROLS_INVALID_INDEX), + m_value(0) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CCheckGroup::~CCheckGroup(void) + { + } +//+------------------------------------------------------------------+ +//| Create a control | +//+------------------------------------------------------------------+ +bool CCheckGroup::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) + { +//--- determine the number of visible rows + m_total_view=(y2-y1)/m_item_height; +//--- check the number of visible rows + if(m_total_view<1) + return(false); +//--- call method of the parent class + if(!CWndClient::Create(chart,name,subwin,x1,y1,x2,y2)) + return(false); +//--- set up + if(!m_background.ColorBackground(CONTROLS_CHECKGROUP_COLOR_BG)) + return(false); + if(!m_background.ColorBorder(CONTROLS_CHECKGROUP_COLOR_BORDER)) + return(false); +//--- create dependent controls + ArrayResize(m_rows,m_total_view); + for(int i=0;i=m_values.Total()) + return(0); +//--- + return(m_states[idx]); + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool CCheckGroup::Check(const int idx,const int value) + { +//--- check + if(idx>=m_values.Total()) + return(false); +//--- + bool res=(m_states.Update(idx,value) && Redraw()); +//--- change value + if(res && idx<64) + { + if(m_rows[idx].Checked()) + Value(m_value|m_values.At(idx)); + else + Value(m_value&(~m_values.At(idx))); + } +//--- + return(res); + } +//+------------------------------------------------------------------+ +//| Makes the group visible | +//+------------------------------------------------------------------+ +bool CCheckGroup::Show(void) + { +//--- call of the method of the parent class + if(!CWndClient::Show()) + return(false); +//--- loop by rows + int total=m_values.Total(); + for(int i=total;i=ArraySize(m_rows)) + return(true); +//--- change state + return(m_rows[index].Checked(select)); + } +//+------------------------------------------------------------------+ +//| Handler of the "Show vertical scrollbar" event | +//+------------------------------------------------------------------+ +bool CCheckGroup::OnVScrollShow(void) + { +//--- loop by "rows" + for(int i=0;i

2vZtz)~9DTKnXb%dlU{UBd3c*Xv_F zly$NFzftite=@s{7O~JCe;VEU-16$eDW3?vmTRi~^QEli*l)B>RrmYMJgKW z2?WdZ1G;v<%%$Kr==S<#GxTQPu6&$#P&p%ZU+039n@}rJG8`lD#Q4fsX`dxuebtCxinB_Vfp7Pg= z|DN%Krg1fE?}KBogJ;h5p{TE`Zqi=0a3V#SuHzVse9rLbJZ!BP zXBs^1{m#BroJ@x{!?Vat&ZljL2m8kS7I98s$)ulJMfhiU_N{7ohXdz&DU^bLUAbg@ zl9oRyXWlFvo~!LiTTY@b?{72B+V^Sw+(q4O^>wFu*Z!i$ry8S=tWQw%wzg(j8}c>H z+P6V!I&|Cn=F+L`&7ShU%lX%`o#?(b^=3uNUffPx#H*&5o#rQVjI7R2R$FvvDbcqy z=1)P}v6t(^r9WgxKc|L*~u=-wFoeEbxP5uA(&K@cTI6jd6INHcqr2 zGfo}rTc;!PWO#)!TE)5-V*6F_x!NB#)h4m{^SE_0mXqZ4)mnF+F}dwG$SN1~}$ z%dmJ`zJDP5fNTrA`NSK2Z1ufGOzX;<1k|zWr$)v#ojniZSc}XeQwjSgR>#yCI-L+h z_4(CvG5N~-6B$dtZ^)QDO|ZrW8hbs8V}wy2HS@r0>A^Ek-wd=(qzBGFCQI|2pUCdo z3bXnstXYID_d>%wkbZf+X0MOa!uSfQ?s_0|-a4^tbPYK1{Vw53_o>0L+#Xd5%rgT@ zGGKU8HJ-1J25tHv-Fp@D^i_T&w84p8y|3cj<%{p)EKyD8j}+uoag{W5^XM37|8$@o ziw$Ug?Po%>WQ>)0m8UYjVy5~!CN7^}M;~I6usqSXQZ1;SD4aEhL z9J}sVvZOBG^QAlEY(6_3qkF#oAZyI4WwCY7*V|;(>RxdF#6+;&9=yj;&$w(ZU4 z&es~p0sjdliuiWK(<=UKWQLjtsVR2ud`874u nJ+An9a1FiNe4nezQq$bkW3PQ9gtT%`q}ne&v&j~Da*7@MXv literal 0 HcmV?d00001 diff --git a/Include/Math/Stat/NegativeBinomial.mqh b/Include/Math/Stat/NegativeBinomial.mqh new file mode 100644 index 0000000..ca5f4a9 --- /dev/null +++ b/Include/Math/Stat/NegativeBinomial.mqh @@ -0,0 +1,645 @@ +//+------------------------------------------------------------------+ +//| NegativeBinomial.mqh | +//| Copyright 2016-2017, MetaQuotes Software Corp. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2016-2017, MetaQuotes Software Corp." +#property link "https://www.mql5.com" + +#include "Math.mqh" +#include "Gamma.mqh" +#include "Poisson.mqh" +//+------------------------------------------------------------------+ +//| Negative Binomial probability mass function (PDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability mass function | +//| of the Negative Binomial distribution with parameters r and p. | +//| | +//| Arguments: | +//| x : Random variable | +//| r : Number of successes | +//| p : Probability of success | +//| log_mode : Logarithm mode flag, if true it returns Log values | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The probability mass evaluated at x. | +//+------------------------------------------------------------------+ +double MathProbabilityDensityNegativeBinomial(const double x,const double r,const double p,const bool log_mode,int &error_code) + { +//--- check NaN + if(!MathIsValidNumber(x) || !MathIsValidNumber(r) || !MathIsValidNumber(p)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- check arguments + if(r!=MathRound(r) || r<1.0 || p<0.0 || p>1.0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + + error_code=ERR_OK; + if(x<0.0) + return TailLog0(true,log_mode); +//--- calculate gamma factor for the density + double coef=MathRound(MathExp(MathGammaLog(r+x)-MathGammaLog(x+1.0)-MathGammaLog(r))); +//--- return density + return TailLogValue(coef*MathPow(p,r)*MathPow(1.0-p,x),true,log_mode); + } +//+------------------------------------------------------------------+ +//| Negative Binomial probability mass function (PDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability mass function | +//| of the Negative Binomial distribution with parameters r and p. | +//| | +//| Arguments: | +//| x : Random variable | +//| r : Number of successes | +//| p : Probability of success | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The probability mass evaluated at x. | +//+------------------------------------------------------------------+ +double MathProbabilityDensityNegativeBinomial(const double x,const double r,const double p,int &error_code) + { + return MathProbabilityDensityNegativeBinomial(x,r,p,false,error_code); + } +//+------------------------------------------------------------------+ +//| Negative Binomial probability mass function (PDF) | +//+------------------------------------------------------------------+ +//| The function calculates the probability mass function | +//| of the Negative Binomial distribution with parameters r and p | +//| for values from x[] array. | +//| | +//| Arguments: | +//| x : Array with random variables | +//| r : Number of successes | +//| p : Probability of success | +//| log_mode : Logarithm mode flag, if true it returns Log values | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathProbabilityDensityNegativeBinomial(const double &x[],const double r,const double p,const bool log_mode,double &result[]) + { +//--- check NaN + if(!MathIsValidNumber(r) || !MathIsValidNumber(p)) + return false; +//--- check arguments + if(r!=MathRound(r) || r<1.0 || p<0.0 || p>1.0) + return false; + + int data_count=ArraySize(x); + if(data_count==0) + return false; + + double power_p_r=MathPow(p,r); + double log_gamma_r=MathGammaLog(r); + int error_code=0; + ArrayResize(result,data_count); + for(int i=0; i1.0 || x<0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + + error_code=ERR_OK; + if(x<0.0) + return TailLog0(tail,log_mode); + int err_code=0; +//--- calculate max term of the sum + int max_j=(int)MathFloor(x); + double p1=1.0-p; +//--- initial factors + double factor1=MathFactorial((int)r-1); + double factor2=1.0; + double factor_p=1.0; + double factor_r=1.0/factor1; + double power_p_r=MathPowInt(p,int(r))*factor_r; + double cdf=0.0; + for(int j=0; j<=max_j; j++) + { + if(j>0) + { + factor1*=(j+1); + factor2*=j; + factor_p*=p1; + } + double pdf=power_p_r*factor1*factor_p/factor2; + cdf+=pdf; + } +//--- take into account round-off errors for probability + return TailLogValue(MathMin(cdf,1.0),tail,log_mode); + } +//+------------------------------------------------------------------+ +//| Negative Binomial cumulative distribution function (CDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability that an observation | +//| from the Negative Binomial distribution with parameters r and p | +//| is less than or equal to x. | +//| | +//| Arguments: | +//| x : The desired quantile | +//| r : Number of successes | +//| p : Probability of success | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The value of the Negative Binomial cumulative distribution | +//| function with parameters r and p, evaluated at x. | +//+------------------------------------------------------------------+ +double MathCumulativeDistributionNegativeBinomial(const double x,const double r,double p,int error_code) + { + return MathCumulativeDistributionNegativeBinomial(x,r,p,true,false,error_code); + } +//+------------------------------------------------------------------+ +//| Negative Binomial cumulative distribution function (CDF) | +//+------------------------------------------------------------------+ +//| The function calculates the cumulative distribution function | +//| of the Negative Binomial distribution with parameters r and p | +//| for values from x[] array. | +//| | +//| Arguments: | +//| x : Array with random variables | +//| r : Number of successes | +//| p : Probability of success | +//| tail : Flag to calculate lower tail | +//| log_mode : Logarithm mode, if true it calculates Log values | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathCumulativeDistributionNegativeBinomial(const double &x[],const double r,double p,const bool tail,const bool log_mode,double &result[]) + { +//--- check NaN + if(!MathIsValidNumber(r) || !MathIsValidNumber(p)) + return false; +//--- check arguments + if(r!=MathRound(r) || r<1.0 || p<0.0 || p>1.0) + return false; + + int data_count=ArraySize(x); + if(data_count==0) + return false; +//--- common factors + double fact1=MathFactorial((int)r-1); + double factor_r=1.0/fact1; + double power_p_r=MathPowInt(p,int(r))*factor_r; + double p1=1.0-p; + int error_code=0; + ArrayResize(result,data_count); + for(int i=0; i0) + { + factor1*=(j+1); + factor2*=j; + factor_p*=p1; + } + double pdf=power_p_r*factor1*factor_p/factor2; + cdf+=pdf; + } + //--- take into account round-off errors for probability + result[i]=TailLogValue(MathMin(cdf,1.0),tail,log_mode); + } + } + return true; + } +//+------------------------------------------------------------------+ +//| Negative Binomial cumulative distribution function (CDF) | +//+------------------------------------------------------------------+ +//| The function calculates the cumulative distribution function | +//| of the Negative Binomial distribution with parameters r and p | +//| for values from x[] array. | +//| | +//| Arguments: | +//| x : Array with random variables | +//| r : Number of successes | +//| p : Probability of success | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathCumulativeDistributionNegativeBinomial(const double &x[],const double r,double p,double &result[]) + { + return MathCumulativeDistributionNegativeBinomial(x,r,p,true,false,result); + } +//+------------------------------------------------------------------+ +//| Negative Binomial distribution quantile function (inverse CDF) | +//+------------------------------------------------------------------+ +//| The function returns the inverse cumulative distribution | +//| function of the Negative Binomial distribution with parameters | +//| r and p for the desired probability. | +//| | +//| Arguments: | +//| probability : The desired probability | +//| r : Number of successes | +//| p : Probability of success | +//| tail : Flag to calculate lower tail | +//| log_mode : Logarithm mode, if true it calculates Log values | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The value of the inverse cumulative distribution function | +//| of the Negative Binomial distribution with parameters r and p. | +//+------------------------------------------------------------------+ +double MathQuantileNegativeBinomial(const double probability,const double r,const double p,const bool tail,const bool log_mode,int &error_code) + { +//--- check NaN + if(!MathIsValidNumber(probability) || !MathIsValidNumber(r) || !MathIsValidNumber(p)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- check arguments + if(r!=MathRound(r) || r<1.0 || p<0.0 || p>1.0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } +//--- calculate real probability + double prob=TailLogProbability(probability,tail,log_mode); +//--- check probability range + if(prob<0.0 || prob>1.0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } +//--- check cases p=0 and p=1 + if(prob==1.0) + { + error_code=ERR_RESULT_INFINITE; + return QPOSINF; + } + error_code=ERR_OK; + if(prob==0.0) + return 0.0; + + int max_terms=1000; + int err_code=0; +//--- factors + double fact1=MathFactorial((int)r-1); + double factor_r=1.0/fact1; + double power_p_r=MathPowInt(p,int(r))*factor_r; + double p1=1.0-p; +//--- initial factors + double factor1=fact1; + double factor2=1.0; + double factor_p=1.0; + double cdf=0.0; + int j=0; + while(cdf0) + { + factor1*=(j+1); + factor2*=j; + factor_p*=p1; + } + double pdf=power_p_r*factor1*factor_p/factor2; + cdf+=pdf; + j++; + } +//--- check convergence + if(j1.0) + return false; + + int data_count=ArraySize(probability); + if(data_count==0) + return false; +//--- common factors + double fact1=MathFactorial((int)r-1); + double factor_r=1.0/fact1; + double power_p_r=MathPowInt(p,int(r))*factor_r; + double p1=1.0-p; + int max_terms=500; + ArrayResize(result,data_count); + for(int i=0; i1.0) + return false; + + if(prob==0.0) + result[i]=0.0; + else + if(prob==1.0) + result[i]=QPOSINF; + else + { + double factor1=fact1; + double factor2=1.0; + double factor_p=1.0; + double cdf=0.0; + int j=0; + while(cdf0) + { + factor1*=(j+1); + factor2*=j; + factor_p*=p1; + } + double pdf=power_p_r*factor1*factor_p/factor2; + cdf+=pdf; + j++; + } + if(j=1.0) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } + double r_gamma=MathRandomGamma(r,(1-p)/p); + return MathRandomPoisson(r_gamma,error_code); + } +//+------------------------------------------------------------------+ +//| Random variate from the Negative Binomial distribution | +//+------------------------------------------------------------------+ +//| Generates random variables from the Negative Binomial | +//| distribution with parameters r and p. | +//| | +//| Arguments: | +//| r : Number of successes | +//| p : Probability of success | +//| data_count : Number of values needed | +//| result : Output array with random values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathRandomNegativeBinomial(const double r,const double p,const int data_count,double &result[]) + { +//--- check NaN + if(!MathIsValidNumber(r) || !MathIsValidNumber(p)) + return false; +//--- check arguments + if(r<=0.0 || p<=0.0 || p>=1.0) + return false; + + double p_coef=(1-p)/p; + int error_code=0; +//--- prepare output array and calculate random values + ArrayResize(result,data_count); + for(int i=0; i=1.0) + { + error_code=ERR_ARGUMENTS_INVALID; + return false; + } + + error_code=ERR_OK; +//--- calculate moments + mean =r*(1.0-p)/p; + variance=mean/p; + skewness=(2.0-p)/MathSqrt((r*(1.0-p))); + kurtosis=(p*p-6*p+6)/(r*(1.0-p)); +//--- successful + return true; + } +//+------------------------------------------------------------------+ diff --git a/Include/Math/Stat/NoncentralBeta.mqh b/Include/Math/Stat/NoncentralBeta.mqh new file mode 100644 index 0000000..87f63e6 --- /dev/null +++ b/Include/Math/Stat/NoncentralBeta.mqh @@ -0,0 +1,957 @@ +//+------------------------------------------------------------------+ +//| NoncentralBeta.mqh | +//| Copyright 2016-2017, MetaQuotes Software Corp. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2016-2017, MetaQuotes Software Corp." +#property link "https://www.mql5.com" + +#include "Math.mqh" +#include "Beta.mqh" +#include "NoncentralChiSquare.mqh" +//+------------------------------------------------------------------+ +//| Noncental Beta density function (PDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability density function | +//| of the Noncental Beta distribution with parameters a,b,lambda | +//| Infinity | +//| f(x,a,b,lambda)=Sum [p(k)*x^(a+k-1)*(1-x)^(b-1)]/Beta(a+k,b) | +//| k=0 | +//| | +//| where p(k)=(1/k!)*exp(-lambda/2)*(lambda/2)^k, | +//| Beta(a,b)=Gamma(a)*Gamma(b)/Gamma(a+b) | +//| | +//| Arguments: | +//| x : Random variable | +//| a : First shape parameter | +//| b : Second shape parameter | +//| lambda : Noncentrality parameter | +//| log_mode : Logarithm mode flag, if true it returns Log values | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The probability density evaluated at x. | +//+------------------------------------------------------------------+ +double MathProbabilityDensityNoncentralBeta(const double x,const double a,const double b,const double lambda,const bool log_mode,int &error_code) + { +//--- if lambda==0, return Beta density + if(lambda==0.0) + return MathProbabilityDensityBeta(x,a,b,error_code); +//--- check parameters + if(!MathIsValidNumber(x) || !MathIsValidNumber(a) || !MathIsValidNumber(b)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- a,b,lambda must be positive + if(a<=0.0 || b<=0.0 || lambda<0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + + error_code=ERR_OK; + if(x<=0.0 || x>=1.0) + return TailLog0(true,log_mode); +//--- factors + double lambda_half=lambda*0.5; + double fact_mult=1.0; + double pwr_lambda_half=1.0; + double pwr_x=MathExp((a-1.0)*MathLog(x)); + double r_beta=MathBeta(a,b); + double pdf=0; +//--- direct sum calculation + for(int j=0;; j++) + { + if(j>0) + { + pwr_x*=x; + pwr_lambda_half*=lambda_half; + fact_mult/=j; + double jm1=j-1; + r_beta*=((a+jm1)/(a+b+jm1)); + } + double term=pwr_x*fact_mult*pwr_lambda_half/r_beta; + //--- + if(term<10E-18) + break; + pdf+=term; + } +//--- calculate density coef + pdf*=MathExp((b-1.0)*MathLog(1.0-x))*MathExp(-lambda_half); +//--- return density + return TailLogValue(pdf,true,log_mode); + } +//+------------------------------------------------------------------+ +//| Noncental Beta density function (PDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability density function | +//| of the Noncental Beta distribution with parameters a,b,lambda. | +//| | +//| Arguments: | +//| x : Random variable | +//| a : First shape parameter | +//| b : Second shape parameter | +//| lambda : Noncentrality parameter | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The probability density evaluated at x. | +//+------------------------------------------------------------------+ +double MathProbabilityDensityNoncentralBeta(const double x,const double a,const double b,const double lambda,int &error_code) + { + return MathProbabilityDensityNoncentralBeta(x,a,b,lambda,false,error_code); + } +//+------------------------------------------------------------------+ +//| Noncental Beta density function (PDF) | +//+------------------------------------------------------------------+ +//| The function calculates the probability density function of | +//| the Noncentral Beta distribution with parameters a,b,lambda | +//| for values in x. | +//| | +//| Arguments: | +//| x : Array with random variables | +//| a : First shape parameter | +//| b : Second shape parameter | +//| lambda : Noncentrality parameter | +//| tail : Flag to calculate lower tail | +//| log_mode : Logarithm mode flag, if true it returns Log values | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathProbabilityDensityNoncentralBeta(const double &x[],const double a,const double b,const double lambda,const bool log_mode,double &result[]) + { +//--- if lambda==0, return Beta density + if(lambda==0.0) + return MathProbabilityDensityBeta(x,a,b,log_mode,result); +//--- check parameters + if(!MathIsValidNumber(a) || !MathIsValidNumber(b)) + return false; +//--- a,b,lambda must be positive + if(a<=0.0 || b<=0.0 || lambda<0) + return false; + + int data_count=ArraySize(x); + if(data_count==0) + return false; +//--- common factors + double lambda_half=lambda*0.5; + double exp_lambda_half=MathExp(-lambda_half); + double r_beta0=MathBeta(a,b); + ArrayResize(result,data_count); + for(int i=0; i=1.0) + result[i]=TailLog0(true,log_mode); + else + { + double fact_mult=1.0; + double pwr_lambda_half=1.0; + double pwr_x=MathExp((a-1.0)*MathLog(x_arg)); + double r_beta=r_beta0; + double pdf=0; + for(int j=0;; j++) + { + if(j>0) + { + pwr_x*=x_arg; + pwr_lambda_half*=lambda_half; + fact_mult/=j; + double jm1=j-1; + r_beta*=((a+jm1)/(a+b+jm1)); + } + double term=pwr_x*fact_mult*pwr_lambda_half/r_beta; + //--- + if(term<10E-18) + break; + pdf+=term; + } + //--- calculate density coef + pdf*=MathExp((b-1.0)*MathLog(1.0-x_arg))*exp_lambda_half; + result[i]=TailLogValue(pdf,true,log_mode); + } + } + return true; + } +//+------------------------------------------------------------------+ +//| Noncental Beta density function (PDF) | +//+------------------------------------------------------------------+ +//| The function calculates the probability density function of | +//| the Noncentral Beta distribution with parameters a,b,lambda | +//| for values in x. | +//| | +//| Arguments: | +//| x : Array with random variables | +//| a : First shape parameter | +//| b : Second shape parameter | +//| lambda : Noncentrality parameter | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathProbabilityDensityNoncentralBeta(const double &x[],const double a,const double b,const double lambda,double &result[]) + { + return MathProbabilityDensityNoncentralBeta(x,a,b,lambda,false,result); + } +//+------------------------------------------------------------------+ +//| Noncental Beta cumulative distribution function (CDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability that an observation | +//| from the Noncental Beta distribution with parameters a,b,lambda | +//| is less than or equal to x. | +//| | +//| Input parameters: | +//| x : The desired quantile | +//| a : First shape parameter | +//| b : Second shape parameter | +//| lambda : Noncentrality parameter | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The value of the Noncental Beta cumulative distribution function | +//| with parameters a,b,lambda, evaluated at x. | +//| | +//| Infinity | +//| F(x,a,b,lambda)=Sum p(k)*Ix(a+k,b) | +//| k=0 | +//| | +//| where p(k)=(1/k!)*exp(-lambda/2)*(lambda/2)^k, | +//| Ix(a,b) - incomplete Beta function | +//| | +//| Author: John Burkardt | +//| | +//| Reference: | +//| Harry Posten,"An Effective Algorithm for the Noncentral Beta | +//| Distribution Function", The American Statistician, | +//| Volume 47, Number 2, May 1993, pages 129-131. | +//+------------------------------------------------------------------+ +double MathCumulativeDistributionNoncentralBeta(const double x,const double a,const double b,const double lambda,const bool tail,const bool log_mode,int &error_code) + { +//--- if lambda==0, return Beta CDF + if(lambda==0.0) + return MathCumulativeDistributionBeta(x,a,b,error_code); +//--- check parameters + if(!MathIsValidNumber(x) || !MathIsValidNumber(a) || !MathIsValidNumber(b)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- a,b,lambda must be positive + if(a<=0.0 || b<=0.0 || lambda<0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + + error_code=ERR_OK; + if(x<=0.0) + return TailLog0(tail,log_mode); + if(x>=1.0) + return TailLog1(tail,log_mode); + + const int max_terms=100; + double c=lambda*0.5; + double x0 = int(MathMax(c - 5*MathSqrt(c), 0)); + double a0 = a + x0; + double beta = MathGammaLog(a0) + MathGammaLog(b) - MathGammaLog(a0+b); + double temp = MathBetaIncomplete(x, a0, b); + double gx=MathExp(a0*MathLog(x)+b*MathLog(1-x)-beta-MathLog(a0)); + + double q=0; + if(a0>a) + q=MathExp(-c+x0*MathLog(c)-MathGammaLog(x0+1)); + else + q=MathExp(-c); + + double sumq=1-q; + double betanc=q*temp; + double ab=a+b; + int j=0; + for(;;) + { + j++; + temp-=gx; + gx*=x*(ab+j-1)/(a+j); + q*=c/j; + sumq-=q; + betanc+=temp*q; + double err=(temp-gx)*sumq; + if(j>max_terms || err<1E-18) + break; + } + double cdf=MathMin(betanc,1.0); + return TailLogValue(cdf,tail,log_mode); + } +//+------------------------------------------------------------------+ +//| Noncental Beta cumulative distribution function (CDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability that an observation | +//| from the Noncental Beta distribution with parameters a,b,lambda | +//| is less than or equal to x. | +//| | +//| Input parameters: | +//| x : The desired quantile | +//| a : First shape parameter | +//| b : Second shape parameter | +//| lambda : Noncentrality parameter | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The value of the Noncental Beta cumulative distribution function | +//| with parameters a,b,lambda, evaluated at x. | +//+------------------------------------------------------------------+ +double MathCumulativeDistributionNoncentralBeta(const double x,const double a,const double b,const double lambda,int &error_code) + { + return MathCumulativeDistributionNoncentralBeta(x,a,b,lambda,true,false,error_code); + } +//+------------------------------------------------------------------+ +//| Noncental Beta cumulative distribution function (CDF) | +//+------------------------------------------------------------------+ +//| The function calculates the cumulative distribution function of | +//| the Noncentral Beta distribution with parameters a,b,lambda | +//| for values in x. | +//| | +//| Arguments: | +//| x : Array with random variables | +//| a : First shape parameter | +//| b : Second shape parameter | +//| lambda : Noncentrality parameter | +//| log_mode : Logarithm mode, if true it calculates Log values | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathCumulativeDistributionNoncentralBeta(const double &x[],const double a,const double b,const double lambda,const bool tail,const bool log_mode,double &result[]) + { +//--- if lambda==0, return Beta CDF + if(lambda==0.0) + return MathCumulativeDistributionBeta(x,a,b,tail,log_mode,result); +//--- check parameters + if(!MathIsValidNumber(a) || !MathIsValidNumber(b)) + return false; +//--- a,b,lambda must be positive + if(a<=0.0 || b<=0.0 || lambda<0) + return false; + + int data_count=ArraySize(x); + if(data_count==0) + return false; + + const int max_terms=100; + ArrayResize(result,data_count); + for(int i=0; i=1.0) + result[i]=TailLog1(tail,log_mode); + else + { + double c=lambda*0.5; + double x0 = int(MathMax(c - 5*MathSqrt(c), 0)); + double a0 = a + x0; + double beta = MathGammaLog(a0) + MathGammaLog(b) - MathGammaLog(a0+b); + double temp = MathBetaIncomplete(x_arg, a0, b); + double gx=MathExp(a0*MathLog(x_arg)+b*MathLog(1-x_arg)-beta-MathLog(a0)); + + double q=0; + if(a0>a) + q=MathExp(-c+x0*MathLog(c)-MathGammaLog(x0+1)); + else + q=MathExp(-c); + + double sumq=1-q; + double betanc=q*temp; + int j=0; + double ab=a+b; + for(;;) + { + j++; + temp-=gx; + gx*=x_arg*(ab+j-1)/(a+j); + q*=c/j; + sumq-=q; + betanc+=temp*q; + double err=(temp-gx)*sumq; + if(j>max_terms || err<1E-18) + break; + } + double cdf=MathMin(betanc,1.0); + result[i]=TailLogValue(cdf,tail,log_mode); + } + } + return true; + } +//+------------------------------------------------------------------+ +//| Noncental Beta cumulative distribution function (CDF) | +//+------------------------------------------------------------------+ +//| The function calculates the cumulative distribution function of | +//| the Noncentral Beta distribution with parameters a,b,lambda | +//| for values in x[] array. | +//| | +//| Arguments: | +//| x : Array with random variables | +//| a : First shape parameter | +//| b : Second shape parameter | +//| lambda : Noncentrality parameter | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathCumulativeDistributionNoncentralBeta(const double &x[],const double a,const double b,const double lambda,double &result[]) + { + return MathCumulativeDistributionNoncentralBeta(x,a,b,lambda,true,false,result); + } +//+------------------------------------------------------------------+ +//| Noncental Beta distribution quantile function (inverse CDF) | +//+------------------------------------------------------------------+ +//| The function returns the inverse cumulative distribution | +//| function of the Noncental Beta distribution with parameters a,b | +//| and lambda for the desired probability. | +//| | +//| Arguments: | +//| probability : The desired probability | +//| a : First shape parameter | +//| b : Second shape parameter | +//| lambda : Noncentrality parameter | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The value of the inverse cumulative distribution function of | +//| of Noncental Beta distribution with parameters a,b and lambda. | +//+------------------------------------------------------------------+ +double MathQuantileNoncentralBeta(const double probability,const double a,const double b,const double lambda,const bool tail,const bool log_mode,int &error_code) + { + if(log_mode==true && probability==QNEGINF) + return 0.0; + if(log_mode==false && probability==0) + return 0.0; +//--- if lambda==0, return beta quantile + if(lambda==0.0) + return MathQuantileBeta(probability,a,b,error_code); +//--- check parameters + if(!MathIsValidNumber(probability) || !MathIsValidNumber(a) || !MathIsValidNumber(b) || !MathIsValidNumber(lambda)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- a,b,lambda must be positive + if(a<=0.0 || b<=0.0 || lambda<0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + +//--- calculate real probability + double prob=TailLogProbability(probability,tail,log_mode); +//--- check probability range + if(prob<0.0 || prob>1.0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + + error_code=ERR_OK; +//--- check probabilty + if(prob==0.0) + return 0.0; + if(prob==1.0) + return 1.0; + + double lambda_half=lambda*0.5; + double lambda_half_log=MathLog(lambda_half); + double lambda_half_sqrt=MathSqrt(lambda_half); + double lambda_half_exp=MathExp(-lambda_half); + + double x0=int(MathMax(lambda_half-5*lambda_half_sqrt,0)); + double b_gamma_log=MathGammaLog(b); + double eps=10E-18; + double h_min=MathSqrt(eps); + +//double lambda_half=lambda*0.5; + double r_beta0=MathBeta(a,b); + + int err_code=0; + double x=0.5; + double h=1.0; + const int max_terms=100; +//--- Newton iterations + const int max_iterations=50; + int iterations=0; + while(iterationsh_min*MathAbs(x) && MathAbs(h)>h_min)==false) + break; + + //--- calculate PDF + double pdf=0; + if(x<=0.0 || x>=1.0) + pdf=0; + else + { + double fact_mult=1.0; + double pwr_lambda_half=1.0; + double pwr_x=MathExp((a-1.0)*MathLog(x)); + double r_beta=r_beta0; + //--- direct sum calculation + for(int j=0;; j++) + { + if(j>0) + { + pwr_x*=x; + pwr_lambda_half*=lambda_half; + fact_mult/=j; + double jm1=j-1; + r_beta*=((a+jm1)/(a+b+jm1)); + } + double term=pwr_x*fact_mult*pwr_lambda_half/r_beta; + //--- + if(term<10E-18) + break; + pdf+=term; + } + //--- calculate density coef + pdf*=MathExp((b-1.0)*MathLog(1.0-x))*lambda_half_exp; + } + + //--- calculate CDF + double cdf=0; + if(x<=0.0) + cdf=0; + if(x>=1.0) + cdf=1; + else + { + double a0=a+x0; + double beta = MathGammaLog(a0) + b_gamma_log - MathGammaLog(a0+b); + double temp = MathBetaIncomplete(x, a0, b); + double gx=MathExp(a0*MathLog(x)+b*MathLog(1-x)-beta-MathLog(a0)); + + double q=0; + if(a0>a) + q=MathExp(-lambda_half+x0*lambda_half_log-MathGammaLog(x0+1)); + else + q=lambda_half_exp; + + double sumq=1-q; + double betanc=q*temp; + int j=0; + double ab=a+b; + for(;;) + { + j++; + temp-=gx; + gx*=x*(ab+j-1)/(a+j); + q*=lambda_half/j; + sumq-=q; + betanc+=temp*q; + double err=(temp-gx)*sumq; + if(j>max_terms || err<1E-18) + break; + } + cdf=MathMin(betanc,1.0); + } + + //--- calculate ratio + h=(cdf-prob)/pdf; + + double x_new=x-h; + if(x_new<0.0) + x_new=x*0.1; + else + if(x_new>1.0) + x_new=1.0-(1-x)*0.1; + + if(MathAbs(x_new-x)<10E-16) + break; + x=x_new; + + iterations++; + } +//--- check convergence + if(iterationsh_min*MathAbs(x) && MathAbs(h)>h_min)==false) + break; + + //--- calculate PDF + double pdf=0; + if(x<=0.0 || x>=1.0) + pdf=0; + else + { + double fact_mult=1.0; + double pwr_lambda_half=1.0; + double pwr_x=MathExp((a-1.0)*MathLog(x)); + double r_beta=r_beta0; + //--- direct sum calculation + for(int j=0;; j++) + { + if(j>0) + { + pwr_x*=x; + pwr_lambda_half*=lambda_half; + fact_mult/=j; + double jm1=j-1; + r_beta*=((a+jm1)/(a+b+jm1)); + } + double term=pwr_x*fact_mult*pwr_lambda_half/r_beta; + //--- + if(term<10E-18) + break; + pdf+=term; + } + //--- calculate density coef + pdf*=MathExp((b-1.0)*MathLog(1.0-x))*lambda_half_exp; + } + + //--- calculate CDF + double cdf=0; + if(x<=0.0) + cdf=0; + if(x>=1.0) + cdf=1; + else + { + double a0=a+x0; + double beta = MathGammaLog(a0) + b_gamma_log - MathGammaLog(a0+b); + double temp = MathBetaIncomplete(x, a0, b); + double gx=MathExp(a0*MathLog(x)+b*MathLog(1-x)-beta-MathLog(a0)); + + double q=0; + if(a0>a) + q=MathExp(-lambda_half+x0*lambda_half_log-MathGammaLog(x0+1)); + else + q=lambda_half_exp; + + double sumq=1-q; + double betanc=q*temp; + int j=0; + double ab=a+b; + for(;;) + { + j++; + temp-=gx; + gx*=x*(ab+j-1)/(a+j); + q*=lambda_half/j; + sumq-=q; + betanc+=temp*q; + double err=(temp-gx)*sumq; + if(j>max_terms || err<1E-18) + break; + } + cdf=MathMin(betanc,1.0); + } + + //--- calculate ratio + h=(cdf-prob)/pdf; + + double x_new=x-h; + if(x_new<0.0) + x_new=x*0.1; + else + if(x_new>1.0) + x_new=1.0-(1-x)*0.1; + + if(MathAbs(x_new-x)<10E-16) + break; + x=x_new; + + iterations++; + } + //--- check convergence + if(iterations0) + { + pwr_lambda*=lambda; + pwr_x*=x; + pwr_two*=0.5; + fact_mult*=1.0/j; + inv_factor*=1.0/(j+half_nu-1); + } + double dp=coef_gamma*inv_factor*pwr_lambda*pwr_two*pwr_x*fact_mult*coef_lambda_x; + pdf=pdf+dp; + //--- check stop + if(dp/(pdf+10E-10)<10E-16) + break; + j++; + } +//--- check convergence + if(j0) + { + pwr_lambda*=lambda; + pwr_x*=x_arg; + pwr_two*=0.5; + fact_mult*=1.0/j; + inv_factor*=1.0/(j+half_nu-1); + } + double dp=coef_gamma*inv_factor*pwr_lambda*pwr_two*pwr_x*fact_mult*coef_lambda_x; + pdf=pdf+dp; + //--- check stop + if(dp/(pdf+10E-10)<10E-16) + break; + j++; + } + //--- check convergence + if(j0) + { + pwr_lambda*=lambda; + fact_mult/=j; + } + double coef1=coef_lambda*pwr_lambda*fact_mult; + double coef2=MathMin(MathGammaIncomplete(half_x,half_nu+j),1.0); + double dp=coef1*coef2; + cdf=cdf+dp; + if((dp/(cdf+10E-10))<10E-16) + break; + j++; + } +//--- + if(j0) + { + pwr_lambda*=lambda; + fact_mult/=j; + } + double coef1=coef_lambda*pwr_lambda*fact_mult; + double coef2=MathMin(MathGammaIncomplete(half_x,half_nu+j),1.0); + double dp=coef1*coef2; + cdf=cdf+dp; + if((dp/(cdf+10E-10))<10E-16) + break; + j++; + } + //--- + if(j1.0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + + error_code=ERR_OK; + if(prob==0.0) + return 0.0; + + if(prob==1.0) + return QPOSINF; + + error_code=ERR_OK; +//--- common factors for pdf and cdf calculation + const int max_terms=1000; + double lambda=sigma*0.5; + double half_nu=nu*0.5; + double coef_lambda=MathExp(-lambda); + double half_nu_m1=half_nu-1.0; + double coef_gamma=1.0/MathGamma(half_nu); + double pwr_two2=MathExp(-half_nu*MathLog(2)); + double pwr_half_num1=(half_nu-1.0); +//--- prepare values for initial x estimation + double x=0.5; + double h=1.0; + double h_min=10E-10; +//--- Newton iterations + const int max_iterations=50; + int iterations=0; +// int err_code=0; + while(iterationsh_min && MathAbs(h)>MathAbs(h_min*x))==false) + break; + + //double pdf=MathProbabilityDensityNoncentralChiSquare(x,nu,sigma,false,err_code); + double half_x=x*0.5; + double pwr_lambda=1.0; + double pwr_two=pwr_two2; + double pwr_x=MathPow(x,pwr_half_num1); + double fact_mult=1.0; + double coef_lambda_x=coef_lambda*MathExp(-half_x); + double inv_factor=1.0; + //--- calculate density using direct summation + int j=0; + double pdf=0; + while(j0) + { + pwr_lambda*=lambda; + pwr_x*=x; + pwr_two*=0.5; + fact_mult*=1.0/j; + inv_factor*=1.0/(j+half_nu-1); + } + double dp=coef_gamma*inv_factor*pwr_lambda*pwr_two*pwr_x*fact_mult*coef_lambda_x; + pdf=pdf+dp; + //--- check stop + if(dp/(pdf+10E-10)<10E-16) + break; + j++; + } + //--- check convergence + if(j>max_terms) + { + error_code=ERR_NON_CONVERGENCE; + return QNaN; + } + + //--- calculate cdf + pwr_lambda=1.0; + fact_mult=1.0; + double cdf=0.0; + j=0; + //--- direct summation + while(j0) + { + pwr_lambda*=lambda; + fact_mult/=j; + } + double coef1=coef_lambda*pwr_lambda*fact_mult; + double coef2=MathMin(MathGammaIncomplete(half_x,half_nu+j),1.0); + double dp=coef1*coef2; + cdf=cdf+dp; + if((dp/(cdf+10E-10))<10E-16) + break; + j++; + } + //--- + if(j>max_terms) + { + error_code=ERR_NON_CONVERGENCE; + return QNaN; + } + + //--- calculate ratio + h=(cdf-prob)/pdf; + + double x_new=x-h; + if(x_new<0.0) + x_new=x*0.1; + else + if(x_new>1.0) + x_new=1.0-(1-x)*0.1; + x=x_new; + + iterations++; + } +//--- check convergence + if(iterations1.0) + return false; + + //--- prepare values for initial x estimation + int err_code=0; + double x=0.5; + double h=1.0; + //--- Newton iterations + int iterations=0; + while(iterationsh_min && MathAbs(h)>MathAbs(h_min*x))==false) + break; + + //double pdf=MathProbabilityDensityNoncentralChiSquare(x,nu,sigma,false,err_code); + double half_x=x*0.5; + double pwr_lambda=1.0; + double pwr_two=pwr_two0; + double pwr_x=MathPow(x,half_nu_m1); + double fact_mult=1.0; + double coef_lambda_x=coef_lambda*MathExp(-half_x); + double inv_factor=1.0; + //--- calculate density using direct summation + int j=0; + double pdf=0; + while(j0) + { + pwr_lambda*=lambda; + pwr_x*=x; + pwr_two*=0.5; + fact_mult*=1.0/j; + inv_factor*=1.0/(j+half_nu-1); + } + double dp=pwr_gamma0*inv_factor*pwr_lambda*pwr_two*pwr_x*fact_mult*coef_lambda_x; + pdf=pdf+dp; + //--- check stop + if(dp/(pdf+10E-10)<10E-16) + break; + j++; + } + //--- check convergence + if(j>max_terms) + return false; + + //--- calculate cdf + pwr_lambda=1.0; + fact_mult=1.0; + pwr_lambda=1.0; + fact_mult=1.0; + double cdf=0.0; + j=0; + //--- direct summation + while(j0) + { + pwr_lambda*=lambda; + fact_mult/=j; + } + double coef1=coef_lambda*pwr_lambda*fact_mult; + double coef2=MathMin(MathGammaIncomplete(half_x,half_nu+j),1.0); + double dp=coef1*coef2; + cdf=cdf+dp; + if((dp/(cdf+10E-10))<10E-16) + break; + j++; + } + //--- + if(j>max_terms) + return false; + + //--- calculate ratio + h=(cdf-prob)/pdf; + + double x_new=x-h; + if(x_new<0.0) + x_new=x*0.1; + else + if(x_new>1.0) + x_new=1.0-(1-x)*0.1; + x=x_new; + + iterations++; + } + //--- check convergence + if(iterations1.0) + { + double rnd_chisquare=MathRandomGamma((nu-1)*0.5,2.0,err_code); + double rnd_normal=MathSqrt(sigma)+MathRandomNormal(0,1,err_code); + return rnd_chisquare+rnd_normal*rnd_normal; + } + else + { + int rnd_poisson=(int)MathRandomPoisson(sigma*0.5); + return MathRandomChiSquare(nu+2*rnd_poisson,err_code); + } + } +//+------------------------------------------------------------------+ +//| Random variate from the Noncentral Chi-Square distribution | +//+------------------------------------------------------------------+ +//| Generates random variables from the Noncentral Chi-Square | +//| distribution with parameters nu and sigma. | +//| | +//| Arguments: | +//| nu : Degrees of freedom | +//| sigma : Noncentrality parameter | +//| data_count : Number of values needed | +//| result : Output array with random values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +//| Author: Robert Kern | +//+------------------------------------------------------------------+ +bool MathRandomNoncentralChiSquare(const double nu,const double sigma,const int data_count,double &result[]) + { +//--- return ChiSquare if sigma==0 + if(sigma==0.0) + return MathRandomChiSquare(nu,data_count,result); +//--- check NaN + if(!MathIsValidNumber(nu) || !MathIsValidNumber(sigma)) + return false; +//--- check nu + if(nu!=MathRound(nu) || nu<=0) + return false; +//--- check sigma + if(sigma<0.0) + return false; + + int err_code=0; +//--- prepare output array and calculate random values + ArrayResize(result,data_count); + for(int i=0; i1.0) + { + double rnd_chisquare=MathRandomGamma((nu-1)*0.5,2.0,err_code); + double rnd_normal=MathSqrt(sigma)+MathRandomNormal(0,1,err_code); + result[i]=rnd_chisquare+rnd_normal*rnd_normal; + } + else + { + int rnd_poisson=(int)MathRandomPoisson(sigma*0.5); + result[i]=MathRandomChiSquare(nu+2*rnd_poisson,err_code); + } + } + return true; + } +//+------------------------------------------------------------------+ +//| Noncentral Chi-Square distribution moments | +//+------------------------------------------------------------------+ +//| The function calculates 4 first moments of Noncental Chi-Square | +//| distribution with parameters nu and sigma. | +//| | +//| Arguments: | +//| nu : Degrees of freedom | +//| sigma : Noncentrality parameter | +//| mean : Variable for mean value (1st moment) | +//| variance : Variable for variance value (2nd moment) | +//| skewness : Variable for skewness value (3rd moment) | +//| kurtosis : Variable for kurtosis value (4th moment) | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| true if moments calculated successfully, otherwise false. | +//+------------------------------------------------------------------+ +bool MathMomentsNoncentralChiSquare(const double nu,const double sigma,double &mean,double &variance,double &skewness,double &kurtosis,int &error_code) + { +//--- default values + mean =QNaN; + variance=QNaN; + skewness=QNaN; + kurtosis=QNaN; +//--- check NaN + if(!MathIsValidNumber(nu) || !MathIsValidNumber(sigma)) + { + error_code=ERR_ARGUMENTS_NAN; + return false; + } +//--- check nu + if(nu!=MathRound(nu) || nu<=0.0) + { + error_code=ERR_ARGUMENTS_INVALID; + return false; + } + + error_code=ERR_OK; +//--- calculate moments + mean =nu+sigma; + variance=2*nu+4*sigma; + skewness=2*M_SQRT2*(nu+3*sigma)*MathPow(nu+2*sigma,-1.5); + kurtosis=12*(nu+4*sigma)*MathPow(nu+2*sigma,-2); +//--- successful + return true; + } +//+------------------------------------------------------------------+ diff --git a/Include/Math/Stat/NoncentralF.mqh b/Include/Math/Stat/NoncentralF.mqh new file mode 100644 index 0000000..8bffbb7 --- /dev/null +++ b/Include/Math/Stat/NoncentralF.mqh @@ -0,0 +1,792 @@ +//+------------------------------------------------------------------+ +//| NoncentralF.mqh | +//| Copyright 2016-2017, MetaQuotes Software Corp. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2016-2017, MetaQuotes Software Corp." +#property link "https://www.mql5.com" + +#include "Math.mqh" +#include "F.mqh" +#include "Gamma.mqh" +#include "NoncentralBeta.mqh" +//+------------------------------------------------------------------+ +//| Noncentral-F probability density function (PDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability density function | +//| of the Noncentral-F distribution with parameters nu1,nu2,sigma. | +//| | +//| Arguments: | +//| x : Random variable | +//| nu1 : Numerator degrees of freedom | +//| nu2 : Denominator degrees of freedom | +//| sigma : Noncentrality parameter | +//| log_mode : Logarithm mode flag, if true it returns Log values | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The probability density evaluated at x. | +//+------------------------------------------------------------------+ +double MathProbabilityDensityNoncentralF(const double x,const double nu1,const double nu2,const double sigma,const bool log_mode,int &error_code) + { +//--- return F if sigma==0 + if(sigma==0.0) + return MathProbabilityDensityF(x,nu1,nu2,error_code); +//--- check NaN + if(!MathIsValidNumber(x) || !MathIsValidNumber(nu1) || !MathIsValidNumber(nu2) || !MathIsValidNumber(sigma)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- check arguments + if(nu1!=MathRound(nu1) || nu2!=MathRound(nu2) || nu1<=0 || nu2<=0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + + error_code=ERR_OK; + if(x<=0.0) + return TailLog0(true,log_mode); +//--- factors + double nu1_half=nu1*0.5; + double nu2_half=nu2*0.5; + double nu12_half=nu1_half+nu2_half; + double lambda=sigma*0.5; + double coef_lambda=MathExp(-lambda); + double nu_coef=nu1/nu2; + double g=x*nu_coef; + double pwr_g=MathExp((nu1_half-1)*MathLog(g)); + double g1=g+1.0; + double pwr_g1=MathExp(-nu12_half*MathLog(g1)); + double pwr_lambda=1.0; + double fact_mult=1.0; +//--- initial value for recurrent calculation + double r_beta=MathBeta(nu1_half,nu2_half); +//--- direct calculation of the sum + int max_terms=100; + int j=0; + double pdf=0; + while(j0) + { + pwr_g*=g; + pwr_lambda*=lambda; + fact_mult/=j; + pwr_g1/=g1; + double jm1=j-1; + r_beta*=((nu1_half+jm1)/(nu12_half+jm1)); + } + double dp=pwr_g*pwr_g1*coef_lambda*pwr_lambda*fact_mult/r_beta; + pdf+=dp; + if(dp/(pdf+10E-10)<10E-14) + break; + j++; + } +//--- check convergence + if(j0) + { + pwr_g*=g; + pwr_lambda*=lambda; + fact_mult/=j; + pwr_g1/=g1; + double jm1=j-1; + r_beta*=((nu1_half+jm1)/(nu12_half+jm1)); + } + double dp=pwr_g*pwr_g1*coef_lambda*pwr_lambda*fact_mult/r_beta; + pdf+=dp; + if(dp/(pdf+10E-10)<10E-14) + break; + j++; + } + //--- check convergence + if(j1.0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + + if(prob==1.0) + { + error_code=ERR_RESULT_INFINITE; + return QPOSINF; + } + error_code=ERR_OK; + if(prob==0.0) + return 0.0; +//--- + int max_iterations=50; + int iterations=0; +//--- initial values + double h=1.0; + double h_min=10E-10; + double x=0.5; + int err_code=0; +//--- Newton iterations + while(iterationsh_min && MathAbs(h)>MathAbs(h_min*x))==false) + break; + //--- calculate pdf and cdf + double pdf=MathProbabilityDensityNoncentralF(x,nu1,nu2,sigma,err_code); + double cdf=MathCumulativeDistributionNoncentralF(x,nu1,nu2,sigma,err_code); + //--- calculate ratio + h=(cdf-prob)/pdf; + //--- + double x_new=x-h; + //--- check x + if(x_new<0.0) + x_new=x*0.1; + else + if(x_new>1.0) + x_new=1.0-(1.0-x)*0.1; + + x=x_new; + + iterations++; + } +//--- check convergence + if(iterations1.0) + return false; + + if(prob==1.0) + result[i]=QPOSINF; + else + if(prob==0.0) + result[i]=0.0; + else + { + int max_iterations=50; + int iterations=0; + //--- initial values + double h=1.0; + double h_min=10E-10; + double x=0.5; + int err_code=0; + //--- Newton iterations + while(iterationsh_min && MathAbs(h)>MathAbs(h_min*x))==false) + break; + //--- calculate pdf and cdf + double pdf=MathProbabilityDensityNoncentralF(x,nu1,nu2,sigma,err_code); + double cdf=MathCumulativeDistributionNoncentralF(x,nu1,nu2,sigma,err_code); + //--- calculate ratio + h=(cdf-prob)/pdf; + //--- + double x_new=x-h; + //--- check x + if(x_new<0.0) + x_new=x*0.1; + else + if(x_new>1.0) + x_new=1.0-(1.0-x)*0.1; + + x=x_new; + + iterations++; + } + //--- check convergence + if(iterations2) + mean=nu2*(nu1+sigma)/(nu1*(nu2-2)); +//--- variance + if(nu2>4) + variance=2*MathPow(nu2/nu1,2)*((nu2-2)*(nu1+2*sigma)+MathPow(nu1+sigma,2))/((nu2-4)*MathPow(nu2-2,2)); +//--- factors + double sigma_sqr=MathPow(sigma,2); + double sigma_cube=sigma_sqr*sigma; + double nu12m2=(nu1+nu2-2); + double nu2p10=(nu2+10); +//--- skewness + if(nu2>6) + { + skewness=2*M_SQRT2*MathSqrt(nu2-4); + skewness*=(nu12m2*(6*sigma_sqr+(2*nu1+nu2-2)*(3*sigma+nu1))+2*sigma_cube); + skewness/=(nu2-6); + skewness/=MathPow(nu12m2*(2*sigma+nu1)+sigma_sqr,1.5); + } +//--- kurtosis + if(nu2>8) + { + double coef=nu2p10*(MathPow(nu1,2)+nu1*(nu2-2))+4*MathPow(nu2-2,2); + kurtosis=1; + kurtosis=3*(nu2-4); + kurtosis*=(nu12m2*(coef*(4*sigma+nu1)+nu2p10*(4*sigma_cube+2*sigma_sqr*(3*nu1+2*nu2-4)))+nu2p10*MathPow(sigma,4)); + kurtosis/=(nu2-8)*(nu2-6); + kurtosis/=MathPow((nu12m2*(2*sigma+nu1)+sigma_sqr),2); + kurtosis-=3; + } +//--- successful + return true; + } +//+------------------------------------------------------------------+ diff --git a/Include/Math/Stat/NoncentralT.mqh b/Include/Math/Stat/NoncentralT.mqh new file mode 100644 index 0000000..d3b9f1d --- /dev/null +++ b/Include/Math/Stat/NoncentralT.mqh @@ -0,0 +1,1194 @@ +//+------------------------------------------------------------------+ +//| NoncentralT.mqh | +//| Copyright 2016-2017, MetaQuotes Software Corp. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2016-2017, MetaQuotes Software Corp." +#property link "https://www.mql5.com" + +#include "Math.mqh" +#include "T.mqh" +#include "Normal.mqh" +//+------------------------------------------------------------------+ +//| Noncentral T probability density function (PDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability density function | +//| of the Noncentral T distribution with parameters nu and delta. | +//| | +//| Arguments: | +//| x : Random variable | +//| nu : Degrees of freedom | +//| delta : Noncentrality parameter | +//| log_mode : Logarithm mode, if true it calculates Log values | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The probability density evaluated at x. | +//+------------------------------------------------------------------+ +double MathProbabilityDensityNoncentralT(const double x,const double nu,const double delta,const bool log_mode,int &error_code) + { +//--- return T + if(delta==0.0) + return MathProbabilityDensityT(x,nu,error_code); +//--- check NaN + if(!MathIsValidNumber(x) || !MathIsValidNumber(nu) || !MathIsValidNumber(delta)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- check nu + if(nu!=MathRound(nu) || nu<=0.0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + + error_code=ERR_OK; +//--- + double nu_1=nu+1.0; + double nu_1_half=nu_1*0.5; + double log_nu=MathLog(nu); + double factor1=MathExp(-0.5*(MathLog(M_PI)+log_nu)-(delta*delta)*0.5-MathGammaLog(nu*0.5)+nu_1_half*log_nu); + + double nu_xx=nu+x*x; + double log_nu_xx=MathLog(nu_xx); + double factor2=MathExp(-nu_1_half*log_nu_xx); +//--- + const int max_terms=500; + double pwr=1.0; + double pwr_factor=x*delta*M_SQRT2; + double pwr_nuxx=1.0; + double pwr_nuxx_factor=1.0/MathSqrt(nu_xx); + double pwr_gamma=1.0; + int j=0; + double pdf=0.0; + while(j0) + { + pwr_nuxx*=pwr_nuxx_factor; + pwr_gamma/=j; + pwr*=pwr_factor; + } + double t=pwr*pwr_gamma*pwr_nuxx*MathGamma((nu_1+j)*0.5); + pdf+=t; + //--- check precision + if((t/(pdf+10E-10))<10E-20) + break; + j++; + } +//--- check convergence + if(j0) + { + pwr_nuxx*=pwr_nuxx_factor; + pwr_gamma/=j; + pwr*=pwr_factor; + } + double t=pwr*pwr_gamma*pwr_nuxx*MathGamma((nu_1+j)*0.5); + pdf+=t; + //--- check precision + if((t/(pdf+10E-10))<10E-20) + break; + j++; + } + //--- check convergence + if(j=max_iterations) + break; + } + else + { + if(error<=errtol || j>=max_iterations) + break; + } + } +//--- check convergence + if(j=max_iterations) + break; + } + else + { + if(error<=errtol || j>=max_iterations) + break; + } + } + //--- check convergence + if(j1.0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + + if(prob==0.0 || prob==1.0) + { + error_code=ERR_RESULT_INFINITE; + if(prob==0.0) + return QNEGINF; + else + return QPOSINF; + } +//--- coefficients for pdf and cdf + double sqr_delta_half=delta*delta*0.5; + double nu_half=nu*0.5; + double log_sqr_delta_half=MathLog(sqr_delta_half); + double exp_sqr_delta_half=MathExp(-sqr_delta_half); + double sqrt_sqr_delta_half=MathSqrt(sqr_delta_half); + double nu_1=nu+1.0; + double nu_1_half=nu_1*0.5; + double log_nu=MathLog(nu); + double factor1=MathExp(-0.5*(MathLog(M_PI)+log_nu)-sqr_delta_half-MathGammaLog(nu*0.5)+nu_1_half*log_nu); + +//--- probability for -delta + int err_code=0; + double p0=MathCumulativeDistributionNormal(-delta,0.0,1.0,err_code); +//--- + error_code=ERR_OK; + double precision=10E-20; + const int max_iterations=150; + int iterations=0; + double x=0.5; + double h=1.0; + double h_min=precision; + const int max_terms=500; +//--- Newton iterations + while(iterationsh_min && MathAbs(h)>MathAbs(h_min*x))==false) + break; + + //--- calculate pdf + double x_arg_sqr=x*x; + double nu_xx=nu+x_arg_sqr; + double log_nu_xx=MathLog(nu_xx); + double factor2=MathExp(-nu_1_half*log_nu_xx); + double pwr=1.0; + double pwr_factor=x*delta*M_SQRT2; + double pwr_nuxx=1.0; + double pwr_nuxx_factor=1.0/MathSqrt(nu_xx); + double pwr_gamma=1.0; + int j=0; + double pdf=0.0; + while(j0) + { + pwr_nuxx*=pwr_nuxx_factor; + pwr_gamma/=j; + pwr*=pwr_factor; + } + double t=pwr*pwr_gamma*pwr_nuxx*MathGamma((nu_1+j)*0.5); + pdf+=t; + //--- check precision + if((t/(pdf+10E-10))<10E-20) + break; + j++; + } + //--- check convergence + if(j>max_terms) + return false; + pdf=factor1*factor2*pdf; + + //--- calculate cdf + double t=(x*x)/(nu+x*x); + double sum1 = 0.0; + double sum2 = 0.0; + //--- + double pwr_coef1=1.0; + double pwr_coef2=1.0; + double fact=1.0; + j=0; + if(x!=0) + { + while(j0) + { + pwr_coef1*=sqrt_sqr_delta_half; + pwr_coef2*=sqr_delta_half; + fact/=j; + } + double coef=1.0/MathGamma(j*0.5+1.0); + //--- term1: t between 0 and x + double t1=pwr_coef1*coef*MathBetaIncomplete(t,(j+1.0)*0.5,nu_half); + sum1+=t1; + //--- term2: t between x and -x + double t2=pwr_coef2*fact*MathBetaIncomplete(t,(j+0.5),nu_half); + sum2+=t2; + //--- check precision + if((MathAbs(t1/(sum1+10E-10))max_terms) + return false; + + //--- compute probability for positive x + double cdf=p0+exp_sqr_delta_half*sum1*0.5; + //--- compute probability for negative x + if(x<0) + cdf=cdf-exp_sqr_delta_half*sum2; + //--- take into account round-off errors for probability + cdf=MathMin(cdf,1.0); + + //--- calculate ratio + h=(cdf-prob)/pdf; + + double x_new=x-h; + if(x_new<0.0) + x_new=x*0.1; + else + if(x_new>1.0) + x_new=1.0-(1.0-x)*0.1; + + if(MathAbs(x_new-x)<10E-15) + break; + + x=x_new; + iterations++; + } +//--- check convergence + if(iterations1.0) + return false; + + if(prob==0.0 || prob==1.0) + { + if(prob==0.0) + result[i]=QNEGINF; + else + result[i]=QPOSINF; + } + else + { + double x=0.5; + double h=1.0; + int iterations=0; + //--- Newton iterations + while(iterationsh_min && MathAbs(h)>MathAbs(h_min*x))==false) + break; + + //--- calculate pdf and cdf + //double cdf=MathCumulativeDistributionNoncentralT(x,nu,delta,err_code); + //double pdf=MathProbabilityDensityNoncentralT(x,nu,delta,err_code); + + //--- calculate pdf + double x_arg_sqr=x*x; + double nu_xx=nu+x_arg_sqr; + double log_nu_xx=MathLog(nu_xx); + double factor2=MathExp(-nu_1_half*log_nu_xx); + double pwr=1.0; + double pwr_factor=x*delta*M_SQRT2; + double pwr_nuxx=1.0; + double pwr_nuxx_factor=1.0/MathSqrt(nu_xx); + double pwr_gamma=1.0; + int j=0; + double pdf=0.0; + while(j0) + { + pwr_nuxx*=pwr_nuxx_factor; + pwr_gamma/=j; + pwr*=pwr_factor; + } + double t=pwr*pwr_gamma*pwr_nuxx*MathGamma((nu_1+j)*0.5); + pdf+=t; + //--- check precision + if((t/(pdf+10E-10))<10E-20) + break; + j++; + } + //--- check convergence + if(j>max_terms) + return false; + + pdf=factor1*factor2*pdf; + + //--- calculate cdf + double t=(x*x)/(nu+x*x); + double sum1 = 0.0; + double sum2 = 0.0; + //--- + double pwr_coef1=1.0; + double pwr_coef2=1.0; + double fact=1.0; + j=0; + if(x!=0) + { + while(j0) + { + pwr_coef1*=sqrt_sqr_delta_half; + pwr_coef2*=sqr_delta_half; + fact/=j; + } + double coef=1.0/MathGamma(j*0.5+1.0); + //--- term1: t between 0 and x + double t1=pwr_coef1*coef*MathBetaIncomplete(t,(j+1.0)*0.5,nu_half); + sum1+=t1; + //--- term2: t between x and -x + double t2=pwr_coef2*fact*MathBetaIncomplete(t,(j+0.5),nu_half); + sum2+=t2; + //--- check precision + if((MathAbs(t1/(sum1+10E-10))max_terms) + return false; + + //--- compute probability for positive x + double cdf=p0+exp_sqr_delta_half*sum1*0.5; + //--- compute probability for negative x + if(x<0) + cdf=cdf-exp_sqr_delta_half*sum2; + //--- take into account round-off errors for probability + cdf=MathMin(cdf,1.0); + + //--- calculate ratio + h=(cdf-prob)/pdf; + + double x_new=x-h; + if(x_new<0.0) + x_new=x*0.1; + else + if(x_new>1.0) + x_new=1.0-(1.0-x)*0.1; + + if(MathAbs(x_new-x)<10E-15) + break; + + x=x_new; + iterations++; + } + //--- check convergence + if(iterations1) + mean=delta*MathSqrt(nu)*MathGamma((nu-1)*0.5)/(MathSqrt(2)*MathGamma(nu*0.5)); +//--- delta^2 + double delta_sqr=delta*delta; +//--- 1/((nu-3)*(nu-2)) + double nu32=1/((nu-3)*(nu-2)); + if(nu>2) + variance=((delta_sqr+1)*nu)/(nu-2)-MathPow(mean,2); +//--- skewness + if(nu>3) + { + skewness=-2*variance; + skewness+= nu*(delta_sqr+2*nu-3)*nu32; + skewness*= mean*MathPow(variance,-1.5); + } +//--- kurtosis + if(nu>4) + { + kurtosis=-3*variance; + kurtosis+= nu*(delta_sqr*(nu+1)+3*(3*nu-5))*nu32; + kurtosis*= -MathPow(mean,2); + kurtosis+= MathPow(nu,2)*(MathPow(delta,4)+6*delta_sqr+3)/((nu-4)*(nu-2)); + kurtosis*= MathPow(variance,-2); + kurtosis-=3; + } +//--- successful + return true; + } +//+------------------------------------------------------------------+ diff --git a/Include/Math/Stat/Normal.mqh b/Include/Math/Stat/Normal.mqh new file mode 100644 index 0000000..36e38ca --- /dev/null +++ b/Include/Math/Stat/Normal.mqh @@ -0,0 +1,917 @@ +//+------------------------------------------------------------------+ +//| Normal.mqh | +//| Copyright 2016-2017, MetaQuotes Software Corp. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2016-2017, MetaQuotes Software Corp." +#property link "https://www.mql5.com" + +#include "Math.mqh" + +const static double normal_cdf_a[5]= + { + 2.2352520354606839287E00,1.6102823106855587881E02, + 1.0676894854603709582E03,1.8154981253343561249E04, + 6.5682337918207449113E-2 + }; +const static double normal_cdf_b[4]= + { + 4.7202581904688241870E01,9.7609855173777669322E02, + 1.0260932208618978205E04,4.5507789335026729956E04 + }; +//--- coefficients for approximation in second interval +const static double normal_cdf_c[9]= + { + 3.9894151208813466764E-1,8.8831497943883759412E00, + 9.3506656132177855979E01,5.9727027639480026226E02, + 2.4945375852903726711E03,6.8481904505362823326E03, + 1.1602651437647350124E04,9.8427148383839780218E03, + 1.0765576773720192317E-8 + }; +const static double normal_cdf_d[8]= + { + 2.2266688044328115691E01,2.3538790178262499861E02, + 1.5193775994075548050E03,6.4855582982667607550E03, + 1.8615571640885098091E04,3.4900952721145977266E04, + 3.8912003286093271411E04,1.9685429676859990727E04 + }; +//--- coefficients for approximation in third interval +const static double normal_cdf_p[6]= + { + 2.1589853405795699E-1,1.274011611602473639E-1, + 2.2235277870649807E-2,1.421619193227893466E-3, + 2.9112874951168792E-5,2.307344176494017303E-2 + }; +const static double normal_cdf_q[5]= + { + 1.28426009614491121E00,4.68238212480865118E-1, + 6.59881378689285515E-2,3.78239633202758244E-3, + 7.29751555083966205E-5 + }; + +//--- coefficients for p close to 0.5 +const double normal_q_a0 = 3.3871328727963666080; +const double normal_q_a1 = 1.3314166789178437745E+2; +const double normal_q_a2 = 1.9715909503065514427E+3; +const double normal_q_a3 = 1.3731693765509461125E+4; +const double normal_q_a4 = 4.5921953931549871457E+4; +const double normal_q_a5 = 6.7265770927008700853E+4; +const double normal_q_a6 = 3.3430575583588128105E+4; +const double normal_q_a7 = 2.5090809287301226727E+3; +const double normal_q_b1 = 4.2313330701600911252E+1; +const double normal_q_b2 = 6.8718700749205790830E+2; +const double normal_q_b3 = 5.3941960214247511077E+3; +const double normal_q_b4 = 2.1213794301586595867E+4; +const double normal_q_b5 = 3.9307895800092710610E+4; +const double normal_q_b6 = 2.8729085735721942674E+4; +const double normal_q_b7 = 5.2264952788528545610E+3; +//--- coefficients for p not close to 0, 0.5 or 1 +const double normal_q_c0 = 1.42343711074968357734; +const double normal_q_c1 = 4.63033784615654529590; +const double normal_q_c2 = 5.76949722146069140550; +const double normal_q_c3 = 3.64784832476320460504; +const double normal_q_c4 = 1.27045825245236838258; +const double normal_q_c5 = 2.41780725177450611770E-1; +const double normal_q_c6 = 2.27238449892691845833E-2; +const double normal_q_c7 = 7.74545014278341407640E-4; +const double normal_q_d1 = 2.05319162663775882187; +const double normal_q_d2 = 1.67638483018380384940; +const double normal_q_d3 = 6.89767334985100004550E-1; +const double normal_q_d4 = 1.48103976427480074590E-1; +const double normal_q_d5 = 1.51986665636164571966E-2; +const double normal_q_d6 = 5.47593808499534494600E-4; +const double normal_q_d7 = 1.05075007164441684324E-9; +//--- coefficients for p near 0 or 1. +const double normal_q_e0 = 6.65790464350110377720E0; +const double normal_q_e1 = 5.46378491116411436990E0; +const double normal_q_e2 = 1.78482653991729133580E0; +const double normal_q_e3 = 2.96560571828504891230E-1; +const double normal_q_e4 = 2.65321895265761230930E-2; +const double normal_q_e5 = 1.24266094738807843860E-3; +const double normal_q_e6 = 2.71155556874348757815E-5; +const double normal_q_e7 = 2.01033439929228813265E-7; +const double normal_q_f1 = 5.99832206555887937690E-1; +const double normal_q_f2 = 1.36929880922735805310E-1; +const double normal_q_f3 = 1.48753612908506148525E-2; +const double normal_q_f4 = 7.86869131145613259100E-4; +const double normal_q_f5 = 1.84631831751005468180E-5; +const double normal_q_f6 = 1.42151175831644588870E-7; +const double normal_q_f7 = 2.04426310338993978564E-15; +//+------------------------------------------------------------------+ +//| Normal probability density function (PDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability density function | +//| of the Normal distribution with parameters mu and sigma. | +//| | +//| Arguments: | +//| x : Random variable | +//| mu : Mean | +//| sigma : Standard deviation (sigma>0) | +//| log_mode : Logarithm mode flag, if true it returns Log values | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The probability density evaluated at x. | +//+------------------------------------------------------------------+ +double MathProbabilityDensityNormal(const double x,const double mu,const double sigma,const bool log_mode,int &error_code) + { +//--- check NaN + if(!MathIsValidNumber(x) || !MathIsValidNumber(mu) || !MathIsValidNumber(sigma)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- check sigma + if(sigma<=0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + + error_code=ERR_OK; + +//--- prepare argument + double y=(x-mu)/sigma; +//--- check it + if(!MathIsValidNumber(y)) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } +//--- check overflow + y=MathAbs(y); + if(y>=2*MathSqrt(DBL_MAX)) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } +//--- return density + return TailLogValue(M_1_SQRT_2PI*MathExp(-0.5*y*y)/sigma,true,log_mode); + } +//+------------------------------------------------------------------+ +//| Normal probability density function (PDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability density function | +//| of the Normal distribution with parameters mu and sigma. | +//| | +//| Arguments: | +//| x : Random variable | +//| mu : Mean | +//| sigma : Standard deviation (sigma>0) | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The probability density evaluated at x. | +//+------------------------------------------------------------------+ +double MathProbabilityDensityNormal(const double x,const double mu,const double sigma,int &error_code) + { + return MathProbabilityDensityNormal(x,mu,sigma,false,error_code); + } +//+------------------------------------------------------------------+ +//| Normal probability density function (PDF) | +//+------------------------------------------------------------------+ +//| The function calculates the probability density function of | +//| the Normal distribution with parameters mu and sigma | +//| for values in x. | +//| | +//| Arguments: | +//| x : Array with random variables | +//| mu : Mean | +//| sigma : Standard deviation (sigma>0) | +//| log_mode : Logarithm mode flag, if true it returns Log values | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathProbabilityDensityNormal(const double &x[],const double mu,const double sigma,const bool log_mode,double &result[]) + { +//--- check NaN + if(!MathIsValidNumber(mu) || !MathIsValidNumber(sigma)) + return false; +//--- check sigma + if(sigma<=0) + return false; + + int data_count=ArraySize(x); + if(data_count==0) + return false; + + int error_code=0; + ArrayResize(result,data_count); + + for(int i=0; i=2*MathSqrt(DBL_MAX)) + return false; + + //--- calculate density + result[i]=TailLogValue(M_1_SQRT_2PI*MathExp(-0.5*y*y)/sigma,true,log_mode); + } + return true; + } +//+------------------------------------------------------------------+ +//| Normal probability density function (PDF) | +//+------------------------------------------------------------------+ +//| The function calculates the probability density function of | +//| the Normal distribution with parameters mu and sigma | +//| for values in x[] array. | +//| | +//| Arguments: | +//| x : Array with random variables | +//| mu : Mean | +//| sigma : Standard deviation (sigma>0) | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathProbabilityDensityNormal(const double &x[],const double mu,const double sigma,double &result[]) + { + return MathProbabilityDensityNormal(x,mu,sigma,false,result); + } +//+------------------------------------------------------------------+ +//| Normal cumulative distribution function (CDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability that an observation | +//| from the Normal distribution with parameters mu and sigma | +//| is less than or equal to x. | +//| | +//| Arguments: | +//| x : The desired quantile | +//| mu : Mean | +//| sigma : Standard deviation (must be positive) | +//| tail : Flag to calculate lower tail | +//| log_mode : Logarithm mode, if true it calculates Log values | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The value of the Normal cumulative distribution function with | +//| parameters mu and sigma, evaluated at x. | +//+------------------------------------------------------------------+ +//| Comment from original FORTRAN code | +//| http://www.netlib.org/toms-2014-06-10/639 | +//| http://www.netlib.org/toms-2014-06-10/715 | +//| | +//| This function evaluates the normal distribution function: | +//| | +//| / x | +//| 1 | -t*t/2 | +//| P(x) = ----------- | e dt | +//| sqrt(2 pi) | | +//| /-oo | +//| | +//| The main computation evaluates near-minimax approximations | +//| derived from those in "Rational Chebyshev approximations for | +//| the error function" by W. J. Cody, Math. Comp., 1969, 631-637. | +//| This transportable program uses rational functions that | +//| theoretically approximate the normal distribution function to | +//| at least 18 significant decimal digits. The accuracy achieved | +//| depends on the arithmetic system, the compiler, the intrinsic | +//| functions, and proper selection of the machine-dependent | +//| constants. | +//| | +//| Author: | +//| W. J. Cody, Mathematics and Computer Science Division | +//| Argonne National Laboratory, Argonne, IL 60439 | +//+------------------------------------------------------------------+ +double MathCumulativeDistributionNormal(const double x,const double mu,const double sigma,const bool tail,const bool log_mode,int &error_code) + { +//--- check NaN + if(!MathIsValidNumber(x) || !MathIsValidNumber(mu) || !MathIsValidNumber(sigma)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- check sigma + if(sigma<=0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + + error_code=ERR_OK; +//--- prepare argument + double xx=(x-mu)/sigma; +//--- mathematical constants +//--- sqrpi = 1 / sqrt(2*pi), root32 = sqrt(32), and +//--- thrsh is the argument for which anorm = 0.75. + const double sqrpi=1.0/MathSqrt(2*M_PI); + const double thrsh = 0.66291e0; + const double root32= MathSqrt(32); +//--- machine-dependent constants +//--- data eps/5.96e-8/,xlow/-12.949e0/,xuppr/5.768e0/ + const double eps=1.11e-16; + const double xlow=-37.519; + const double xuppr=8.572; + int k; +//--- + double xsq=0.0; + double y=MathAbs(xx); + double xnum=0.0; + double xden=0.0; + double cdf=0.0; + double del=0.0; +//--- + if(y<=thrsh) + { + //--- evaluate for |x| <= 0.66291 + if(y>eps) + xsq=xx*xx; + + xnum = normal_cdf_a[4] * xsq; + xden = xsq; + for(k=0; k<3; k++) + { + xnum=(xnum+normal_cdf_a[k])*xsq; + xden=(xden+normal_cdf_b[k])*xsq; + } + cdf = xx*(xnum+normal_cdf_a[3])/(xden+normal_cdf_b[3]); + cdf = 0.5 + cdf; + } + else + if(y<=root32) + { + //--- evaluate for 0.66291 <= |x| <= sqrt(32) + xnum = normal_cdf_c[8]*y; + xden = y; + for(k=0; k<7; k++) + { + xnum=(xnum+normal_cdf_c[k])*y; + xden=(xden+normal_cdf_d[k])*y; + } + cdf=(xnum+normal_cdf_c[7])/(xden+normal_cdf_d[7]); + xsq=int(y*16)/16; + del=(y-xsq)*(y+xsq); + cdf=MathExp(-xsq*xsq*0.5)*MathExp(-del*0.5)*cdf; + if(xx>0.0) cdf=1.0-cdf; + } +//--- evaluate for |x| > sqrt(32) + else + { + cdf=0.0; + if((xx>=xlow) && (xx0.0) cdf=1.0-cdf; + } +//--- take into account round-off errors for probability + return TailLogValue(MathMin(cdf,1.0),tail,log_mode); + } +//+------------------------------------------------------------------+ +//| Normal cumulative distribution function (CDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability that an observation | +//| from the Normal distribution with parameters mu and sigma | +//| is less than or equal to x. | +//| | +//| Arguments: | +//| x : The desired quantile | +//| mu : Mean | +//| sigma : Standard deviation (must be positive) | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The value of the Normal cumulative distribution function with | +//| parameters mu and sigma, evaluated at x. | +//+------------------------------------------------------------------+ +double MathCumulativeDistributionNormal(const double x,const double mu,const double sigma,int &error_code) + { + return MathCumulativeDistributionNormal(x,mu,sigma,true,false,error_code); + } +//+------------------------------------------------------------------+ +//| Normal cumulative distribution function (CDF) | +//+------------------------------------------------------------------+ +//| The function calculates the cumulative distribution function of | +//| the Normal distribution with parameters mu and sigma | +//| for values in x[] array. | +//| | +//| Arguments: | +//| x : Array with random variables | +//| mu : Mean | +//| sigma : Standard deviation (must be positive) | +//| tail : Flag to calculate lower tail | +//| log_mode : Logarithm mode, if true it calculates Log values | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathCumulativeDistributionNormal(const double &x[],const double mu,const double sigma,const bool tail,const bool log_mode,double &result[]) + { +//--- check NaN + if(!MathIsValidNumber(mu) || !MathIsValidNumber(sigma)) + return false; +//--- check sigma + if(sigma<=0) + return false; + + int data_count=ArraySize(x); + if(data_count==0) + return false; + + int error_code=0; + ArrayResize(result,data_count); + for(int i=0; ieps) + xsq=xx*xx; + + xnum = normal_cdf_a[4] * xsq; + xden = xsq; + for(k=0; k<3; k++) + { + xnum=(xnum+normal_cdf_a[k])*xsq; + xden=(xden+normal_cdf_b[k])*xsq; + } + cdf = xx*(xnum+normal_cdf_a[3])/(xden+normal_cdf_b[3]); + cdf = 0.5 + cdf; + } + else + if(y<=root32) + { + //--- evaluate for 0.66291 <= |x| <= sqrt(32) + xnum = normal_cdf_c[8]*y; + xden = y; + for(k=0; k<7; k++) + { + xnum=(xnum+normal_cdf_c[k])*y; + xden=(xden+normal_cdf_d[k])*y; + } + cdf=(xnum+normal_cdf_c[7])/(xden+normal_cdf_d[7]); + xsq=int(y*16)/16; + del=(y-xsq)*(y+xsq); + cdf=MathExp(-xsq*xsq*0.5)*MathExp(-del*0.5)*cdf; + if(xx>0.0) cdf=1.0-cdf; + } + //--- evaluate for |x| > sqrt(32) + else + { + cdf=0.0; + if((xx>=xlow) && (xx0.0) cdf=1.0-cdf; + } + //--- take into account round-off errors for probability + result[i]=TailLogValue(MathMin(cdf,1.0),tail,log_mode); + } + return true; + } +//+------------------------------------------------------------------+ +//| Normal cumulative distribution function (CDF) | +//+------------------------------------------------------------------+ +//| The function calculates the cumulative distribution function of | +//| the Normal distribution with parameters mu and sigma | +//| for values in x[] array. | +//| | +//| Arguments: | +//| x : Array with random variables | +//| mu : Mean | +//| sigma : Standard deviation (must be positive) | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathCumulativeDistributionNormal(const double &x[],const double mu,const double sigma,double &result[]) + { + return MathCumulativeDistributionNormal(x,mu,sigma,true,false,result); + } +//+------------------------------------------------------------------+ +//| Normal distribution quantile function (inverse CDF) | +//+------------------------------------------------------------------+ +//| The function returns the inverse cumulative distribution | +//| function of the Normal distribution with parameters mu and sigma | +//| for the desired probability. | +//| | +//| Arguments: | +//| probability : The desired probability | +//| mu : Mean | +//| sigma : Standard deviation (must be positive) | +//| tail : Flag to calculate lower tail | +//| log_mode : Logarithm mode,if true it calculates for Log values| +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The value of the inverse cumulative distribution function | +//| of the Normal distribution with parameters mu and sigma. | +//+------------------------------------------------------------------+ +//| Comment from original FORTRAN code | +//| http://www1.fpl.fs.fed.us/ni241.f | +//| Produces the normal deviate Z corresponding to a given lower | +//| tail area of P; Z is accurate to about 1 part in 10**16. | +//| Wichura, M.J. (1988). Algorithm AS 241: The Percentage Points of | +//| the Normal Distribution. Applied Statistics, v.37, N3, 477-484. | +//+------------------------------------------------------------------+ +double MathQuantileNormal(const double probability,const double mu,const double sigma,const bool tail,const bool log_mode,int &error_code) + { +//--- check NaN + if(!MathIsValidNumber(probability) || !MathIsValidNumber(mu) || !MathIsValidNumber(sigma)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- check sigma + if(sigma<=0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + +//--- calculate real probability + double prob=TailLogProbability(probability,tail,log_mode); +//--- check probability range + if(prob<0.0 || prob>1.0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } +//--- f(0)=-infinity + if(prob==0.0) + { + error_code=ERR_RESULT_INFINITE; + return QNEGINF; + } +//--- f(1)=+infinity + if(prob==1.0) + { + error_code=ERR_RESULT_INFINITE; + return QPOSINF; + } + + error_code=ERR_OK; + + double q=prob-0.5; + double r=0; + double ppnd16=0.0; +//--- + if(MathAbs(q)<=0.425) + { + r=0.180625-q*q; + ppnd16=q*(((((((normal_q_a7*r+normal_q_a6)*r+normal_q_a5)*r+normal_q_a4)*r+normal_q_a3)*r+normal_q_a2)*r+normal_q_a1)*r+normal_q_a0)/ + (((((((normal_q_b7*r+normal_q_b6)*r+normal_q_b5)*r+normal_q_b4)*r+normal_q_b3)*r+normal_q_b2)*r+normal_q_b1)*r+1.0); + //--- + error_code=ERR_OK; + return mu+sigma*ppnd16; + } + else + { + if(q<0.0) + r=prob; + else + r=1.0-prob; + //--- + r=MathSqrt(-MathLog(r)); + //--- + if(r<=5.0) + { + r=r-1.6; + ppnd16=(((((((normal_q_c7*r+normal_q_c6)*r+normal_q_c5)*r+normal_q_c4)*r+normal_q_c3)*r+normal_q_c2)*r+normal_q_c1)*r+normal_q_c0)/ + (((((((normal_q_d7*r+normal_q_d6)*r+normal_q_d5)*r+normal_q_d4)*r+normal_q_d3)*r+normal_q_d2)*r+normal_q_d1)*r+1.0); + } + else + { + r=r-5.0; + ppnd16=(((((((normal_q_e7*r+normal_q_e6)*r+normal_q_e5)*r+normal_q_e4)*r+normal_q_e3)*r+normal_q_e2)*r+normal_q_e1)*r+normal_q_e0)/ + (((((((normal_q_f7*r+normal_q_f6)*r+normal_q_f5)*r+normal_q_f4)*r+normal_q_f3)*r+normal_q_f2)*r+normal_q_f1)*r+1.0); + } + //--- + if(q<0.0) + ppnd16=-ppnd16; + } +//--- return rescaled/shifted value + return mu+sigma*ppnd16; + } +//+------------------------------------------------------------------+ +//| Normal distribution quantile function (inverse CDF) | +//+------------------------------------------------------------------+ +//| The function returns the inverse cumulative distribution | +//| function of Normal distribution with parameters mu and sigma | +//| for the desired probability. | +//| | +//| Arguments: | +//| probability : The desired probability | +//| mu : Mean | +//| sigma : Standard deviation (must be positive) | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The value of the inverse cumulative distribution function | +//| of the Normal distribution with parameters mu and sigma. | +//+------------------------------------------------------------------+ +double MathQuantileNormal(const double probability,const double mu,const double sigma,int &error_code) + { + return MathQuantileNormal(probability,mu,sigma,true,false,error_code); + } +//+------------------------------------------------------------------+ +//| Normal distribution quantile function (inverse CDF) | +//+------------------------------------------------------------------+ +//| The function calculates the inverse cumulative distribution | +//| function of the Normal distribution with parameters mu and sigma | +//| for the probability values from array. | +//| | +//| Arguments: | +//| probability : Array with probabilities | +//| mu : Mean | +//| sigma : Standard deviation (must be positive) | +//| tail : Flag to calculate lower tail | +//| log_mode : Logarithm mode, if true it calculates Log values | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathQuantileNormal(const double &probability[],const double mu,const double sigma,const bool tail,const bool log_mode,double &result[]) + { +//--- check NaN + if(!MathIsValidNumber(mu) || !MathIsValidNumber(sigma)) + return false; +//--- check sigma + if(sigma<0) + return false; + + int data_count=ArraySize(probability); + if(data_count==0) + return false; + + int error_code=0; + ArrayResize(result,data_count); + +//--- case sigma==0 + if(sigma==0.0) + { + for(int i=0; i1.0) + return false; + + //--- f(0)=-infinity, f(1)=+infinity + if(prob==0.0 || prob==1.0) + { + if(prob==0.0) + result[i]=QNEGINF; + else + result[i]=QPOSINF; + } + else + { + double q=prob-0.5; + double r=0; + double ppnd16=0.0; + //--- + if(MathAbs(q)<=0.425) + { + r=0.180625-q*q; + ppnd16=q*(((((((normal_q_a7*r+normal_q_a6)*r+normal_q_a5)*r+normal_q_a4)*r+normal_q_a3)*r+normal_q_a2)*r+normal_q_a1)*r+normal_q_a0)/ + (((((((normal_q_b7*r+normal_q_b6)*r+normal_q_b5)*r+normal_q_b4)*r+normal_q_b3)*r+normal_q_b2)*r+normal_q_b1)*r+1.0); + //--- set rescaled/shifted value + result[i]=mu+sigma*ppnd16; + } + else + { + if(q<0.0) + r=prob; + else + r=1.0-prob; + //--- + r=MathSqrt(-MathLog(r)); + //--- + if(r<=5.0) + { + r=r-1.6; + ppnd16=(((((((normal_q_c7*r+normal_q_c6)*r+normal_q_c5)*r+normal_q_c4)*r+normal_q_c3)*r+normal_q_c2)*r+normal_q_c1)*r+normal_q_c0)/ + (((((((normal_q_d7*r+normal_q_d6)*r+normal_q_d5)*r+normal_q_d4)*r+normal_q_d3)*r+normal_q_d2)*r+normal_q_d1)*r+1.0); + } + else + { + r=r-5.0; + ppnd16=(((((((normal_q_e7*r+normal_q_e6)*r+normal_q_e5)*r+normal_q_e4)*r+normal_q_e3)*r+normal_q_e2)*r+normal_q_e1)*r+normal_q_e0)/ + (((((((normal_q_f7*r+normal_q_f6)*r+normal_q_f5)*r+normal_q_f4)*r+normal_q_f3)*r+normal_q_f2)*r+normal_q_f1)*r+1.0); + } + //--- + if(q<0.0) + ppnd16=-ppnd16; + } + //--- set rescaled/shifted value + result[i]=mu+sigma*ppnd16; + } + } + return true; + } +//+------------------------------------------------------------------+ +//| Normal distribution quantile function (inverse CDF) | +//+------------------------------------------------------------------+ +//| The function calculates the inverse cumulative distribution | +//| function of the Normal distribution with parameters mu and sigma | +//| for the probability values from array. | +//| | +//| Arguments: | +//| probability : Array with probabilities | +//| mu : Mean | +//| sigma : Standard deviation (must be positive) | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathQuantileNormal(const double &probability[],const double mu,const double sigma,double &result[]) + { + return MathQuantileNormal(probability,mu,sigma,true,false,result); + } +//+------------------------------------------------------------------+ +//| Random variate from the Normal distribution | +//+------------------------------------------------------------------+ +//| Compute the random variable from the Normal distribution | +//| with given mean mu and standard deviation sigma. | +//| | +//| Arguments: | +//| mu : Mean | +//| sigma : Standard deviation (must be positive) | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The random value with Normal distribution. | +//+------------------------------------------------------------------+ +double MathRandomNormal(const double mu,const double sigma,int &error_code) + { +//--- check NaN + if(!MathIsValidNumber(mu) || !MathIsValidNumber(sigma)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- check sigma + if(sigma<0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + + error_code=ERR_OK; +//--- + if(sigma==0.0) + return mu; +//--- generate random number + double rnd=MathRandomNonZero(); +//--- return normal random using quantile + return MathQuantileNormal(rnd,mu,sigma,true,false,error_code); + } +//+------------------------------------------------------------------+ +//| Random variate from the Normal distribution | +//+------------------------------------------------------------------+ +//| Generates random variables from the Normal distribution with | +//| parameters mu and sigma. | +//| | +//| Arguments: | +//| mu : Mean | +//| sigma : Standard deviation (must be positive) | +//| data_count : Number of values needed | +//| result : Output array with random values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathRandomNormal(const double mu,const double sigma,const int data_count,double &result[]) + { +//--- check NaN + if(!MathIsValidNumber(mu) || !MathIsValidNumber(sigma)) + return false; +//--- check sigma + if(sigma<0) + return false; +//--- prepare output array and calculate random values + ArrayResize(result,data_count); + if(sigma==0.0) + { + for(int i=0; i0) | +//| mean : Variable for mean value (1st moment) | +//| variance : Variable for variance value (2nd moment) | +//| skewness : Variable for skewness value (3rd moment) | +//| kurtosis : Variable for kurtosis value (4th moment) | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| true if moments calculated successfully, otherwise false. | +//+------------------------------------------------------------------+ +bool MathMomentsNormal(const double mu,const double sigma,double &mean,double &variance,double &skewness,double &kurtosis,int &error_code) + { +//--- default values + mean =QNaN; + variance=QNaN; + skewness=QNaN; + kurtosis=QNaN; +//--- check NaN + if(!MathIsValidNumber(mu) || !MathIsValidNumber(sigma)) + { + error_code=ERR_ARGUMENTS_NAN; + return false; + } +//--- check sigma + if(sigma<=0) + { + error_code=ERR_ARGUMENTS_INVALID; + return false; + } + + error_code=ERR_OK; +//--- calculate moments + mean =mu; + variance=MathPow(sigma,2); + skewness=0; + kurtosis=0; +//--- successful + return true; + } +//+------------------------------------------------------------------+ diff --git a/Include/Math/Stat/Poisson.mqh b/Include/Math/Stat/Poisson.mqh new file mode 100644 index 0000000..ebc5c85 --- /dev/null +++ b/Include/Math/Stat/Poisson.mqh @@ -0,0 +1,793 @@ +//+------------------------------------------------------------------+ +//| Poisson.mqh | +//| Copyright 2016-2017, MetaQuotes Software Corp. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2016-2017, MetaQuotes Software Corp." +#property link "https://www.mql5.com" + +#include "Math.mqh" +#include "Gamma.mqh" +//+------------------------------------------------------------------+ +//| Poisson probability mass function (PDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability mass function | +//| of the Poisson distribution with parameter lambda. | +//| | +//| Arguments: | +//| x : Random variable | +//| lambda : Mean | +//| log_mode : Logarithm mode flag, if true it returns Log values | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The probability mass evaluated at x. | +//+------------------------------------------------------------------+ +double MathProbabilityDensityPoisson(const double x,const double lambda,const bool log_mode,int &error_code) + { +//--- check NaN + if(!MathIsValidNumber(x) || !MathIsValidNumber(lambda)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- lambda must be positive, x must be integer + if(lambda<=0.0 || x!=MathRound(x)) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + + error_code=ERR_OK; +//--- check x + if(x<0.0) + return TailLog0(true,log_mode); + +//--- calculate log pdf using LogGamma + double log_pdf=-lambda+x*MathLog(lambda)-MathGammaLog(x+1.0); + if(log_mode) + return log_pdf; +//--- return density + return MathExp(log_pdf); + } +//+------------------------------------------------------------------+ +//| Poisson probability mass function (PDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability mass function | +//| of the Poisson distribution with parameter lambda. | +//| | +//| Arguments: | +//| x : Random variable | +//| lambda : Mean | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The probability mass evaluated at x. | +//+------------------------------------------------------------------+ +double MathProbabilityDensityPoisson(const double x,const double lambda,int &error_code) + { + return MathProbabilityDensityPoisson(x,lambda,false,error_code); + } +//+------------------------------------------------------------------+ +//| Poisson probability mass function (PDF) | +//+------------------------------------------------------------------+ +//| The function calculates the probability density function of | +//| the Poisson distribution with parameter lambda for values in x[].| +//| | +//| Arguments: | +//| x : Array with random variables | +//| lambda : Mean | +//| log_mode : Logarithm mode flag, if true it returns Log values | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathProbabilityDensityPoisson(const double &x[],const double lambda,const bool log_mode,double &result[]) + { +//--- check NaN + if(!MathIsValidNumber(lambda)) + return false; +//--- lambda must be positive + if(lambda<=0.0) + return false; + + int data_count=ArraySize(x); + if(data_count==0) + return false; + + ArrayResize(result,data_count); + for(int i=0; i1.0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } +//--- check + if(prob==1.0) + { + error_code=ERR_RESULT_INFINITE; + return QPOSINF; + } + error_code=ERR_OK; + if(prob==0.0) + return 0.0; + + prob*=1-1000*DBL_EPSILON; + int err_code=0; + int j=0; + const int max_terms=500; + double coef_lambda=MathExp(-lambda); + double pwr_lambda=1.0; + double inverse_fact=1.0; + double sum=0; +//--- direct calculation of the quantile + while(sum0) + { + pwr_lambda*=lambda; + inverse_fact/=j; + } + sum+=coef_lambda*pwr_lambda*inverse_fact; + j++; + } +//--- check convergence + if(j1.0) + return false; + else + if(prob==1.0) + result[i]=QPOSINF; + if(prob==0.0) + result[i]=0; + else + { + prob*=1-1000*DBL_EPSILON; + int err_code=0; + int j=0; + double sum=0.0; + const int max_terms=500; + double pwr_lambda=1.0; + double inverse_fact=1.0; + //--- direct calculation + while(sum0) + { + pwr_lambda*=lambda; + inverse_fact/=j; + } + sum+=coef_lambda*pwr_lambda*inverse_fact; + j++; + } + //--- check convergence + if(j=1.0 || r2==0.0); + //--- Box-Muller transform + f=MathSqrt(-2.0*MathLog(r2)/r2); + double snorm=f*x2; + //--- normal sample + g=lambda+s*snorm; + + if(0.0<=g) + { + value=(int)(g); + //--- immediate acceptance if large enough + if(l<=value) + return value; + //--- squeeze acceptance + fk=(double)(value); + difmuk=lambda-fk; + u=MathRandomNonZero(); + //--- + if(difmuk*difmuk*difmuk<=d*u) + return value; + } + //--- preparation for steps P and Q + double omega=0.3989423/s; + double b1 = 0.04166667/lambda; + double b2 = 0.3*b1*b1; + double c3 = 0.1428571*b1*b2; + double c2 = b2 - 15.0*c3; + double c1 = b1 - 6.0*b2 + 45.0*c3; + double c0 = 1.0 - b1 + 3.0*b2 - 15.0*c3; + double c=0.1069/lambda; + double del=0; + + if(0.0<=g) + { + kflag=0; + + if(value<10) + { + px = -lambda; + py = MathPow(lambda,value)/MathFactorial(value); + } + else + { + del = 0.8333333E-01/fk; + del = del - 4.8*del*del*del; + v=difmuk/fk; + + if(0.25 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include \ No newline at end of file diff --git a/Include/Math/Stat/T.mqh b/Include/Math/Stat/T.mqh new file mode 100644 index 0000000..5e6a93e --- /dev/null +++ b/Include/Math/Stat/T.mqh @@ -0,0 +1,656 @@ +//+------------------------------------------------------------------+ +//| T.mqh | +//| Copyright 2016-2017, MetaQuotes Software Corp. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2016-2017, MetaQuotes Software Corp." +#property link "https://www.mql5.com" +//--- +#include "Math.mqh" +#include "Gamma.mqh" +//+------------------------------------------------------------------+ +//| T probability density function (PDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability density function | +//| of the T-distribution with parameter nu. | +//| | +//| Arguments: | +//| x : Random variable | +//| nu : Degrees of freedom | +//| log_mode : Logarithm mode, if true it calculates Log values | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The probability density evaluated at x. | +//+------------------------------------------------------------------+ +double MathProbabilityDensityT(const double x,const double nu,const bool log_mode,int &error_code) + { +//--- check NaN + if(!MathIsValidNumber(x) || !MathIsValidNumber(nu)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- check nu + if(nu!=MathRound(nu) || nu<=0.0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + + error_code=ERR_OK; +//--- calculate T density + double pdf=MathExp(MathGammaLog((nu+1.0)*0.5)-MathGammaLog(nu*0.5)); + pdf=pdf/(MathSqrt(nu*M_PI)*MathPow(1+x*x/nu,(nu+1.0)*0.5)); +//--- return density + return TailLogValue(pdf,true,log_mode); + } +//+------------------------------------------------------------------+ +//| T probability density function (PDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability density function | +//| of the T-distribution with parameter nu. | +//| | +//| Arguments: | +//| x : Random variable | +//| nu : Degrees of freedom | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The probability density evaluated at x. | +//+------------------------------------------------------------------+ +double MathProbabilityDensityT(const double x,const double nu,int &error_code) + { + return MathProbabilityDensityT(x,nu,false,error_code); + } +//+------------------------------------------------------------------+ +//| T probability density function (PDF) | +//+------------------------------------------------------------------+ +//| The function calculates the probability density function of | +//| the T distribution with parameter nu for values in x[] array. | +//| | +//| Arguments: | +//| x : Array with random variables | +//| nu : Degrees of freedom | +//| log_mode : Logarithm mode flag, if true it returns Log values | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathProbabilityDensityT(const double &x[],const double nu,const bool log_mode,double &result[]) + { +//--- check NaN + if(!MathIsValidNumber(nu)) + return false; +//--- check nu + if(nu!=MathRound(nu) || nu<=0.0) + return false; + + int data_count=ArraySize(x); + if(data_count==0) + return false; + + int error_code=0; + ArrayResize(result,data_count); + for(int i=0; i0.0) + cdf=1.0-cdf; +//--- take into account round-off errors for probability + return TailLogValue(MathMin(cdf,1.0),tail,log_mode); + } +//+------------------------------------------------------------------+ +//| T cumulative distribution function (CDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability that an observation from | +//| T-distribution with parameter nu is less than or equal to x. | +//| | +//| Arguments: | +//| x : The desired quantile | +//| nu : Degrees of freedom | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The value of T cumulative distribution function with parameter | +//| nu, evaluated at x. | +//+------------------------------------------------------------------+ +double MathCumulativeDistributionT(const double x,const double nu,int &error_code) + { + return MathCumulativeDistributionT(x,nu,true,false,error_code); + } +//+------------------------------------------------------------------+ +//| T cumulative distribution function (CDF) | +//+------------------------------------------------------------------+ +//| The function calculates the cumulative distribution function of | +//| the T distribution with parameter nu for values in x. | +//| | +//| Arguments: | +//| x : Array with random variables | +//| nu : Degrees of freedom | +//| tail : Flag to calculate lower tail | +//| log_mode : Logarithm mode, if true it calculates Log values | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathCumulativeDistributionT(const double &x[],const double nu,const bool tail,const bool log_mode,double &result[]) + { +//--- check NaN + if(!MathIsValidNumber(nu)) + return false; +//--- check nu (must be positive integer) + if(nu!=MathRound(nu) || nu<=0.0) + return false; + + int data_count=ArraySize(x); + if(data_count==0) + return false; + + int error_code=0; + ArrayResize(result,data_count); + for(int i=0; i0.0) + cdf=1.0-cdf; + //--- take into account round-off errors for probability + result[i]=TailLogValue(MathMin(cdf,1.0),tail,log_mode); + } + } + return true; + } +//+------------------------------------------------------------------+ +//| T cumulative distribution function (CDF) | +//+------------------------------------------------------------------+ +//| The function calculates the cumulative distribution function of | +//| the T distribution with parameter nu for values in x[] array. | +//| | +//| Arguments: | +//| x : Array with random variables | +//| nu : Degrees of freedom | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathCumulativeDistributionT(const double &x[],const double nu,double &result[]) + { + return MathCumulativeDistributionT(x,nu,true,false,result); + } +//+------------------------------------------------------------------+ +//| T distribution quantile function (inverse CDF) | +//+------------------------------------------------------------------+ +//| The function returns the inverse cumulative distribution | +//| function of the T distribution with parameter nu for the desired | +//| probability. | +//| | +//| Arguments: | +//| probability : The desired probability | +//| nu : Degrees of freedom | +//| tail : Flag to calculate lower tail | +//| log_mode : Logarithm mode, if true it calculates Log values | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The value of the inverse cumulative distribution function | +//| of the T-distribution with parameter nu. | +//+------------------------------------------------------------------+ +double MathQuantileT(const double probability,const double nu,const bool tail,const bool log_mode,int &error_code) + { +//--- check NaN + if(!MathIsValidNumber(probability) || !MathIsValidNumber(nu)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- check nu + if(nu!=MathRound(nu) || nu<0.0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } +//--- calculate real probability + double prob=TailLogProbability(probability,tail,log_mode); +//--- check probability range + if(prob<0.0 || prob>1.0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + +//--- check cases when probability==0 or 1 + if(prob==0.0 || prob==1.0) + { + error_code=ERR_RESULT_INFINITE; + //--- + if(prob==0.0) + return(QNEGINF); + else + return(QPOSINF); + } + + error_code=ERR_OK; +//--- special case nu=1 + if(nu==1.0) + return MathTan(M_PI*(prob-0.5)); +//--- special case + if(prob==0.5) + return 0.0; +//--- + int max_iterations=50; + int iterations=0; +//--- initial values + double h=1.0; + double h_min=10E-20; + double x=0.5; + int err_code=0; +//--- Newton iterations + while(iterationsh_min && MathAbs(h)>MathAbs(h_min*x))==false) + break; + //--- calculate pdf and cdf + double pdf=MathProbabilityDensityT(x,nu,err_code); + double cdf=MathCumulativeDistributionT(x,nu,err_code); + //--- calculate ratio + h=(cdf-prob)/pdf; + //--- + double x_new=x-h; + //--- check x + if(x_new<0.0) + x_new=x*0.1; + else + if(x_new>1.0) + x_new=1.0-(1.0-x)*0.1; + + x=x_new; + + iterations++; + } +//--- check convergence + if(iterations1.0) + return false; + + //--- special case p=0.5 + if(prob==0.5) + result[i]=0.0; + else + if(prob==0.0) + result[i]=QNEGINF; + else + if(prob==1.0) + result[i]=QPOSINF; + else + { + //--- special case nu=1 + if(nu==1.0) + result[i]=MathTan(M_PI*(prob-0.5)); + else + { + int max_iterations=50; + int iterations=0; + //--- initial values + double h=1.0; + double h_min=10E-18; + double x=0.5; + int err_code=0; + //--- Newton iterations + while(iterationsh_min && MathAbs(h)>MathAbs(h_min*x))==false) + break; + //--- calculate pdf and cdf + double pdf=MathProbabilityDensityT(x,nu,err_code); + double cdf=MathCumulativeDistributionT(x,nu,err_code); + //--- calculate ratio + h=(cdf-prob)/pdf; + //--- + double x_new=x-h; + //--- check x + if(x_new<0.0) + x_new=x*0.1; + else + if(x_new>1.0) + x_new=1.0-(1.0-x)*0.1; + + if (MathAbs(x_new-x)<10E-15) + break; + + x=x_new; + + iterations++; + } + //--- check convergence + if(iterations=1.0 || r2==0.0); +//--- generate normal and gamma random variables + double rnd_normal=x2*MathSqrt(-2.0*MathLog(r2)/r2); + double rnd_gamma=MathRandomGamma(nu*0.5,1,error_code); +//--- calculate ratio + double result=0; + if(rnd_gamma!=0) + result=MathSqrt(nu*0.5)*rnd_normal/MathSqrt(rnd_gamma); + return(result); + } +//+------------------------------------------------------------------+ +//| Random variate from the T distribution | +//+------------------------------------------------------------------+ +//| Generates random variables from the T distribution with | +//| parameter nu. | +//| | +//| Arguments: | +//| nu : Degrees of freedom | +//| data_count : Number of values needed | +//| result : Output array with random values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathRandomT(const double nu,const int data_count,double &result[]) + { +//--- check NaN + if(!MathIsValidNumber(nu)) + return false; +//--- check arguments + if(nu!=MathRound(nu) || nu<=0.0) + return false; + + int error_code=0; +//--- prepare output array and calculate random values + ArrayResize(result,data_count); + for(int i=0; i=1.0 || r2==0.0); + //--- generate normal and gamma random variables + double rnd_normal=x2*MathSqrt(-2.0*MathLog(r2)/r2); + double rnd_gamma=MathRandomGamma(nu*0.5,1,error_code); + //--- calculate ratio + double rnd=0; + if(rnd_gamma!=0) + rnd=MathSqrt(nu*0.5)*rnd_normal/MathSqrt(rnd_gamma); + result[i]=rnd; + } + return true; + } +//+------------------------------------------------------------------+ +//| T distribution moments | +//+------------------------------------------------------------------+ +//| The function calculates 4 first moments of the T distribution | +//| with parameter nu. | +//| | +//| Arguments: | +//| nu : Degrees of freedom | +//| mean : Variable for mean value (1st moment) | +//| variance : Variable for variance value (2nd moment) | +//| skewness : Variable for skewness value (3rd moment) | +//| kurtosis : Variable for kurtosis value (4th moment) | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| true if moments calculated successfully, otherwise false. | +//+------------------------------------------------------------------+ +double MathMomentsT(const double nu,double &mean,double &variance,double &skewness,double &kurtosis,int &error_code) + { +//--- default values + mean =QNaN; + variance=QNaN; + skewness=QNaN; + kurtosis=QNaN; +//--- check NaN + if(!MathIsValidNumber(nu)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- check nu + if(nu!=MathRound(nu) || nu<0.0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + + error_code=ERR_OK; +//--- calculate moments + mean=0; + if(nu>2) + variance=nu/(nu-2); + skewness=0; + if(nu>4) + kurtosis=6/(nu-4); +//--- successful + return true; + } +//+------------------------------------------------------------------+ diff --git a/Include/Math/Stat/Uniform.mqh b/Include/Math/Stat/Uniform.mqh new file mode 100644 index 0000000..f65bc2a --- /dev/null +++ b/Include/Math/Stat/Uniform.mqh @@ -0,0 +1,541 @@ +//+------------------------------------------------------------------+ +//| Uniform.mqh | +//| Copyright 2016-2017, MetaQuotes Software Corp. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2016-2017, MetaQuotes Software Corp." +#property link "https://www.mql5.com" + +#include "Math.mqh" +//+------------------------------------------------------------------+ +//| Uniform probability density function (PDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability density function of the | +//| Uniform distribution with parameters a and b. | +//| | +//| Arguments: | +//| x : Random variable | +//| a : Lower endpoint (minimum) | +//| b : Upper endpoint (maximum) | +//| log_mode : Logarithm mode flag, if true it returns Log values | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The probability density evaluated at x. | +//+------------------------------------------------------------------+ +double MathProbabilityDensityUniform(const double x,const double a,const double b,const bool log_mode,int &error_code) + { +//--- check NaN + if(!MathIsValidNumber(x) || !MathIsValidNumber(a) || !MathIsValidNumber(b)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- check range + if(b<=a) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + + error_code=ERR_OK; +//--- check ranges + if(x>=a && x<=b) + return TailLogValue(1.0/(b-a),true,log_mode); +//--- otherwise 0 + return TailLog0(true,log_mode); + } +//+------------------------------------------------------------------+ +//| Uniform probability density function (PDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability density function of the | +//| Uniform distribution with parameters a and b. | +//| | +//| Arguments: | +//| x : Random variable | +//| a : Lower endpoint (minimum) | +//| b : Upper endpoint (maximum) | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The probability density evaluated at x. | +//+------------------------------------------------------------------+ +double MathProbabilityDensityUniform(const double x,const double a,const double b,int &error_code) + { + return MathProbabilityDensityUniform(x,a,b,false,error_code); + } +//+------------------------------------------------------------------+ +//| Uniform probability density function (PDF) | +//+------------------------------------------------------------------+ +//| The function calculates the probability density function of the | +//| Uniform distribution with parameters a and b for values in x[]. | +//| | +//| Arguments: | +//| x : Array with random variables | +//| a : Lower endpoint (minimum) | +//| b : Upper endpoint (maximum) | +//| log_mode : Logarithm mode flag, if true it returns Log values | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathProbabilityDensityUniform(const double &x[],const double a,const double b,const bool log_mode,double &result[]) + { +//--- check NaN + if(!MathIsValidNumber(a) || !MathIsValidNumber(b)) + return false; +//--- check range + if(b<=a) + return false; + + int data_count=ArraySize(x); + if(data_count==0) + return false; + + int error_code=0; + ArrayResize(result,data_count); + for(int i=0; i=a && x_arg<=b) + result[i]=TailLogValue(1.0/(b-a),true,log_mode); + else + result[i]=TailLog0(true,log_mode); + } + return true; + } +//+------------------------------------------------------------------+ +//| Uniform probability density function (PDF) | +//+------------------------------------------------------------------+ +//| The function calculates the probability density function of the | +//| Uniform distribution with parameters a and b for values in x[]. | +//| | +//| Arguments: | +//| x : Array with random variables | +//| mu : Mean | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathProbabilityDensityUniform(const double &x[],const double a,const double b,double &result[]) + { + return MathProbabilityDensityUniform(x,a,b,false,result); + } +//+------------------------------------------------------------------+ +//| Uniform cumulative distribution function (CDF) | +//+------------------------------------------------------------------+ +//| The function returns the cumulative distribution function | +//| of the Uniform distribution with parameters a and b. | +//| | +//| Arguments: | +//| x : The desired quantile | +//| a : Lower endpoint (minimum) | +//| b : Upper endpoint (maximum) | +//| tail : Flag to calculate lower tail | +//| log_mode : Logarithm mode flag,if true it calculates Log values| +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The value of the Uniform cumulative distribution function with | +//| parameters a and b, evaluated at x. | +//+------------------------------------------------------------------+ +double MathCumulativeDistributionUniform(const double x,const double a,const double b,const bool tail,const bool log_mode,int &error_code) + { +//--- check parameters + if(!MathIsValidNumber(x) || !MathIsValidNumber(a) || !MathIsValidNumber(b)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- check ranges + if(b=a && x<=b) + return TailLogValue(MathMin((x-a)/(b-a),1.0),tail,log_mode); + + if(x>b) + return TailLog1(tail,log_mode); + return TailLog0(tail,log_mode); + } +//+------------------------------------------------------------------+ +//| Uniform cumulative distribution function (CDF) | +//+------------------------------------------------------------------+ +//| The function returns the cumulative distribution function of | +//| the Uniform distribution with parameters a and b. | +//| | +//| Arguments: | +//| x : The desired quantile | +//| a : Lower endpoint (minimum) | +//| b : Upper endpoint (maximum) | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The value of the Uniform cumulative distribution function with | +//| parameters a and b, evaluated at x. | +//+------------------------------------------------------------------+ +double MathCumulativeDistributionUniform(const double x,const double a,const double b,int &error_code) + { + return MathCumulativeDistributionUniform(x,a,b,true,false,error_code); + } +//+------------------------------------------------------------------+ +//| Uniform cumulative distribution function (CDF) | +//+------------------------------------------------------------------+ +//| The function calculates the cumulative distribution function of | +//| the Uniform distribution with parameters a and b for values in x.| +//| | +//| Arguments: | +//| x : Array with random variables | +//| a : Mean | +//| b : Scale | +//| tail : Flag to calculate lower tail | +//| log_mode : Logarithm mode flag,if true it calculates Log values| +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathCumulativeDistributionUniform(const double &x[],const double a,const double b,const bool tail,const bool log_mode,double &result[]) + { +//--- check parameters + if(!MathIsValidNumber(a) || !MathIsValidNumber(b)) + return false; +//--- check ranges + if(b=a && x_arg<=b) + result[i]=TailLogValue(MathMin((x_arg-a)/(b-a),1.0),tail,log_mode); + else + { + if(x_arg>b) + result[i]=TailLog1(tail,log_mode); + else + result[i]=TailLog0(tail,log_mode); + } + } + return true; + } +//+------------------------------------------------------------------+ +//| Uniform cumulative distribution function (CDF) | +//+------------------------------------------------------------------+ +//| The function calculates the cumulative distribution function of | +//| the Uniform distribution with parameters a and b for values in x.| +//| | +//| Arguments: | +//| x : Array with random variables | +//| a : Mean | +//| b : Scale | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathCumulativeDistributionUniform(const double &x[],const double a,const double b,double &result[]) + { + return MathCumulativeDistributionUniform(x,a,b,true,false,result); + } +//+------------------------------------------------------------------+ +//| Uniform distribution quantile function (inverse CDF) | +//+------------------------------------------------------------------+ +//| The function returns the inverse cumulative distribution | +//| function of the Uniform distribution with parameters a and b | +//| for the desired probability. | +//| | +//| Arguments: | +//| probability : The desired probability | +//| a : Lower endpoint (minimum) | +//| b : Upper endpoint (maximum) | +//| tail : Flag to calculate lower tail | +//| log_mode : Logarithm mode,if true it calculates for Log values| +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The value of the inverse cumulative distribution function | +//| of Uniform distribution with parameters a and b. | +//+------------------------------------------------------------------+ +double MathQuantileUniform(const double probability,const double a,const double b,const bool tail,const bool log_mode,int &error_code) + { + if(log_mode==true) + { + if(probability==QNEGINF) + return 0.0; + } +//--- check parameters + if(!MathIsValidNumber(a) || !MathIsValidNumber(b)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- check bounds + if(b1.0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + + error_code=ERR_OK; + + if(prob==0.0) + return a; + else + if(prob==1.0) + return b; + +//--- return quantile + return a+prob*(b-a); + } +//+------------------------------------------------------------------+ +//| Uniform distribution quantile function (inverse CDF) | +//+------------------------------------------------------------------+ +//| The function returns the inverse cumulative distribution | +//| function of the Uniform distribution with parameters a and b | +//| for the desired probability. | +//| | +//| Arguments: | +//| probability : The desired probability | +//| a : Lower endpoint (minimum) | +//| b : Upper endpoint (maximum) | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The value of the inverse cumulative distribution function | +//| of Uniform distribution with parameters a and b. | +//+------------------------------------------------------------------+ +double MathQuantileUniform(const double probability,const double a,const double b,int &error_code) + { + return MathQuantileUniform(probability,a,b,true,false,error_code); + } +//+------------------------------------------------------------------+ +//| Uniform distribution quantile function (inverse CDF) | +//+------------------------------------------------------------------+ +//| The function calculates the inverse cumulative distribution | +//| function of Uniform distribution with parameters a and b | +//| for values from the probability[] array. | +//| | +//| Arguments: | +//| probability : Array with probabilities | +//| a : Lower endpoint (minimum) | +//| b : Upper endpoint (maximum) | +//| tail : Flag to calculate lower tail | +//| log_mode : Logarithm mode, if true it calculates Log values | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathQuantileUniform(const double &probability[],const double a,const double b,const bool tail,const bool log_mode,double &result[]) + { +//--- check parameters + if(!MathIsValidNumber(a) || !MathIsValidNumber(b)) + return false; +//--- check ranges + if(b1.0) + return false; + + //--- check bounds + if(b==a) + result[i]=a; + else + if(prob==0.0) + result[i]=a; + else + if(prob==1.0) + result[i]=b; + else + //--- quantile + result[i]=(a+prob*(b-a)); + } + } + return true; + } +//+------------------------------------------------------------------+ +//| Uniform distribution quantile function (inverse CDF) | +//+------------------------------------------------------------------+ +//| The function calculates the inverse cumulative distribution | +//| function of Uniform distribution with parameters a and b | +//| for values from the probability[] array. | +//| | +//| Arguments: | +//| probability : Array with probabilities | +//| a : Lower endpoint (minimum) | +//| b : Upper endpoint (maximum) | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathQuantileUniform(const double &probability[],const double a,const double b,double &result[]) + { + return MathQuantileUniform(probability,a,b,true,false,result); + } +//+------------------------------------------------------------------+ +//| Random variate from the Uniform distribution | +//+------------------------------------------------------------------+ +//| Computes the random variable from the Uniform distribution | +//| with parameters a and b. | +//| | +//| Arguments: | +//| a : Lower endpoint (minimum) | +//| b : Upper endpoint (maximum) | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The random value with uniform distribution. | +//+------------------------------------------------------------------+ +double MathRandomUniform(const double a,const double b,int &error_code) + { +//--- check NaN + if(!MathIsValidNumber(a) || !MathIsValidNumber(b)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- check upper bound + if(b0) | +//| b : Scale parameter of the distribution (b>0) | +//| log_mode : Logarithm mode flag, if true it returns Log values | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The probability density evaluated at x. | +//+------------------------------------------------------------------+ +double MathProbabilityDensityWeibull(const double x,const double a,const double b,const bool log_mode,int &error_code) + { +//--- f(-infinity)=f(infinity)=0 + if(x==QPOSINF || x==QNEGINF) + { + error_code=ERR_OK; + return TailLog0(true,log_mode); + } +//--- check parameters + if(!MathIsValidNumber(x) || !MathIsValidNumber(a) || !MathIsValidNumber(b)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- a and b must be positive + if(a<=0 || b<=0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + + error_code=ERR_OK; +//--- check x + if(x<=0) + return TailLog0(true,log_mode); +//--- calculate factor + double pwr=MathPow(x/b,a-1); + double pdf=(a/b)*pwr*MathExp(-(x/b)*pwr); + if(log_mode==true) + return MathLog(pdf); +//--- return density + return pdf; + } +//+------------------------------------------------------------------+ +//| Weibull probability density function (PDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability density function | +//| of the Weibull distribution with parameters a and b. | +//| f(x,a,b)=[(a/b)*(x/b)^(a-1)]*exp(-(x/b)^a) | +//| Arguments: | +//| x : Random variable | +//| a : Shape parameter of the distribution (a>0) | +//| b : Scale parameter of the distribution (b>0) | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The probability density evaluated at x. | +//+------------------------------------------------------------------+ +double MathProbabilityDensityWeibull(const double x,const double a,const double b,int &error_code) + { + return MathProbabilityDensityWeibull(x,a,b,false,error_code); + } +//+------------------------------------------------------------------+ +//| Weibull probability density function (PDF) | +//+------------------------------------------------------------------+ +//| The function calculates the probability density function of the | +//| Weibull distribution with parameters a and b for values in x[]. | +//| | +//| Arguments: | +//| x : Array with random variables | +//| a : Shape parameter of the distribution (a>0) | +//| b : Scale parameter of the distribution (b>0) | +//| log_mode : Logarithm mode flag, if true it returns Log values | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathProbabilityDensityWeibull(const double &x[],const double a,const double b,const bool log_mode,double &result[]) + { +//--- check NaN + if(!MathIsValidNumber(a) || !MathIsValidNumber(b)) + return false; +//--- a and b must be positive + if(a<=0 || b<=0) + return false; + + int data_count=ArraySize(x); + if(data_count==0) + return false; + + int error_code=0; + ArrayResize(result,data_count); + for(int i=0; i0) | +//| b : Scale parameter of the distribution (b>0) | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathProbabilityDensityWeibull(const double &x[],const double a,const double b,double &result[]) + { + return MathProbabilityDensityWeibull(x,a,b,false,result); + } +//+------------------------------------------------------------------+ +//| Weibull cumulative distribution function (CDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability that an observation | +//| from the Weibull distribution with parameters a and b | +//| is less than or equal to x. | +//| | +//| Arguments: | +//| x : The desired quantile | +//| a : Shape parameter of the distribution (a>0) | +//| b : Scale parameter of the distribution (b>0) | +//| tail : Flag to calculate lower tail | +//| log_mode : Logarithm mode, if true it calculates Log values | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The value of the Weibull cumulative distribution function | +//| F(a,b)=1-exp(-(x/b)^a) | +//| with parameters a and b, evaluated at x. | +//+------------------------------------------------------------------+ +double MathCumulativeDistributionWeibull(const double x,const double a,const double b,const bool tail,const bool log_mode,int &error_code) + { +//--- f(-infinity)=0 + if(x==QNEGINF) + { + error_code=ERR_OK; + return TailLog0(tail,log_mode); + } +//--- f(+infinity)=1 + if(x==QPOSINF) + { + error_code=ERR_OK; + return TailLog1(tail,log_mode); + } +//--- check parameters + if(!MathIsValidNumber(x) || !MathIsValidNumber(a) || !MathIsValidNumber(b)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- a and b must be positive + if(a<=0 || b<=0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + + error_code=ERR_OK; +//--- check x + if(x<=0) + return TailLog0(tail,log_mode); +//--- calculate probability and take into account round-off errors + double cdf=MathMin(1.0-MathExp(-MathPow(x/b,a)),1.0); + return TailLogValue(cdf,tail,log_mode); + } +//+------------------------------------------------------------------+ +//| Weibull cumulative distribution function (CDF) | +//+------------------------------------------------------------------+ +//| The function returns the probability that an observation | +//| from the Weibull distribution with parameters a and b | +//| is less than or equal to x. | +//| | +//| Arguments: | +//| x : The desired quantile | +//| a : Shape parameter of the distribution (a>0) | +//| b : Scale parameter of the distribution (b>0) | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The value of the Weibull cumulative distribution function | +//| F(a,b)=1-exp(-(x/b)^a) | +//| with parameters a and b, evaluated at x. | +//+------------------------------------------------------------------+ +double MathCumulativeDistributionWeibull(const double x,const double a,const double b,int &error_code) + { + return MathCumulativeDistributionWeibull(x,a,b,true,false,error_code); + } +//+------------------------------------------------------------------+ +//| Weibull cumulative distribution function (CDF) | +//+------------------------------------------------------------------+ +//| The function calculates the cumulative distribution function of | +//| the Weibull distribution with parameters a and b for values in x.| +//| | +//| Arguments: | +//| x : Array with random variables | +//| a : Shape parameter of the distribution (a>0) | +//| b : Scale parameter of the distribution (b>0) | +//| tail : Flag to calculate lower tail | +//| log_mode : Logarithm mode, if true it calculates Log values | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathCumulativeDistributionWeibull(const double &x[],const double a,const double b,const bool tail,const bool log_mode,double &result[]) + { +//--- check NaN + if(!MathIsValidNumber(a) || !MathIsValidNumber(b)) + return false; +//--- a and b must be positive + if(a<=0 || b<=0) + return false; + + int data_count=ArraySize(x); + if(data_count==0) + return false; + + int error_code=0; + ArrayResize(result,data_count); + for(int i=0; i0) | +//| b : Scale parameter of the distribution (b>0) | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathCumulativeDistributionWeibull(const double &x[],const double a,const double b,double &result[]) + { + return MathCumulativeDistributionWeibull(x,a,b,true,false,result); + } +//+------------------------------------------------------------------+ +//| Weibull distribution quantile function (inverse CDF) | +//+------------------------------------------------------------------+ +//| The function returns the inverse cumulative distribution | +//| function of Weibull distribution | +//| Q(p,a,b)=b*((-ln(1-p)))^(1/a) | +//| with parameters a and b for the desired probability. | +//| | +//| Arguments: | +//| probability : The desired probability | +//| a : Shape parameter of the distribution (a>0) | +//| b : Scale parameter of the distribution (b>0) | +//| tail : Flag to calculate for lower tail | +//| log_mode : Logarithm mode,if true it calculates for Log values| +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The value of the inverse cumulative distribution function | +//| of the Weibull distribution with parameters a and b. | +//+------------------------------------------------------------------+ +double MathQuantileWeibull(const double probability,const double a,const double b,const bool tail,const bool log_mode,int &error_code) + { +//--- check NaN + if(!MathIsValidNumber(a) || !MathIsValidNumber(b)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- a and b must be positive + if(a<=0 || b<=0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + +//--- calculate real probability + double prob=TailLogProbability(probability,tail,log_mode); +//--- check probability range + if(prob<0.0 || prob>1.0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } +//--- f(1)=+infinity + if(prob==1.0) + { + error_code=ERR_RESULT_INFINITE; + return QPOSINF; + } + + error_code=ERR_OK; +//--- f(0)=0 + if(prob==0.0) + return 0.0; +//--- return quantile + return b*MathPow(-MathLog(1.0-prob),1.0/a); + } +//+------------------------------------------------------------------+ +//| Weibull distribution quantile function (inverse CDF) | +//+------------------------------------------------------------------+ +//| The function returns the inverse cumulative distribution | +//| function of the Weibull distribution | +//| Q(p,a,b)=b*((-ln(1-p)))^(1/a) | +//| with parameters a and b for the desired probability. | +//| | +//| Arguments: | +//| probability : The desired probability | +//| a : Shape parameter of the distribution (a>0) | +//| b : Scale parameter of the distribution (b>0) | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The value of the inverse cumulative distribution function | +//| of the Weibull distribution with parameters a and b. | +//+------------------------------------------------------------------+ +double MathQuantileWeibull(const double probability,const double a,const double b,int &error_code) + { + return MathQuantileWeibull(probability,a,b,true,false,error_code); + } +//+------------------------------------------------------------------+ +//| Weibull distribution quantile function (inverse CDF) | +//+------------------------------------------------------------------+ +//| The function calculates the inverse cumulative distribution | +//| function of the Weibull distribution with parameters a and b | +//| for the probability values from array. | +//| | +//| Arguments: | +//| probability : Array with probabilities | +//| a : Shape parameter of the distribution (a>0) | +//| b : Scale parameter of the distribution (b>0) | +//| tail : Flag to calculate lower tail | +//| log_mode : Logarithm mode, if true it calculates Log values | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathQuantileWeibull(const double &probability[],const double a,const double b,const bool tail,const bool log_mode,double &result[]) + { +//--- check NaN + if(!MathIsValidNumber(a) || !MathIsValidNumber(b)) + return false; +//--- a and b must be positive + if(a<=0 || b<=0) + return false; + + int data_count=ArraySize(probability); + if(data_count==0) + return false; + + int error_code=0; + ArrayResize(result,data_count); + for(int i=0; i1.0) + return false; + + //--- f(1)=+infinity + if(prob==1.0) + result[i]=QPOSINF; + //--- f(0)=0 + if(prob==0.0) + result[i]=0.0; + else + //--- calc quantile + result[i]=b*MathPow(-MathLog(1.0-prob),1.0/a); + } + return true; + } +//+------------------------------------------------------------------+ +//| Weibull distribution quantile function (inverse CDF) | +//+------------------------------------------------------------------+ +//| The function calculates the inverse cumulative distribution | +//| function of the Weibull distribution with parameters a and b | +//| for values from the probability[] array. | +//| | +//| Arguments: | +//| probability : Array with probabilities | +//| a : Shape parameter of the distribution (a>0) | +//| b : Scale parameter of the distribution (b>0) | +//| result : Array with calculated values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathQuantileWeibull(const double &probability[],const double a,const double b,double &result[]) + { + return MathQuantileWeibull(probability,a,b,true,false,result); + } +//+------------------------------------------------------------------+ +//| Random variate from the Weibull distribution | +//+------------------------------------------------------------------+ +//| Computes the random variable from the Weibull distribution | +//| with shape a and scale b. | +//| | +//| Arguments: | +//| a : Shape parameter of the distribution (a>0) | +//| b : Scale parameter of the distribution (b>0) | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| The random value with Weibull distribution. | +//+------------------------------------------------------------------+ +double MathRandomWeibull(const double a,const double b,int &error_code) + { +//--- check NaN + if(!MathIsValidNumber(a) || !MathIsValidNumber(b)) + { + error_code=ERR_ARGUMENTS_NAN; + return QNaN; + } +//--- a and b must be positive + if(a<=0 || b<=0) + { + error_code=ERR_ARGUMENTS_INVALID; + return QNaN; + } + + error_code=ERR_OK; +//--- generate random number + double rnd=MathRandomNonZero(); + return b*MathPow(-MathLog(rnd),1.0/a); + } +//+------------------------------------------------------------------+ +//| Random variate from the Weibull distribution | +//+------------------------------------------------------------------+ +//| Generates random variables from the Weibull distribution with | +//| parameters a and b. | +//| | +//| Arguments: | +//| a : Shape parameter of the distribution (a>0) | +//| b : Scale parameter of the distribution (b>0) | +//| data_count : Number of values needed | +//| result : Output array with random values | +//| | +//| Return value: | +//| true if successful, otherwise false. | +//+------------------------------------------------------------------+ +bool MathRandomWeibull(const double a,const double b,const int data_count,double &result[]) + { +//--- check NaN + if(!MathIsValidNumber(a) || !MathIsValidNumber(b)) + return false; +//--- a and b must be positive + if(a<=0 || b<=0) + return false; + +//--- prepare output array and calculate random values + ArrayResize(result,data_count); + for(int i=0; i0) | +//| b : Scale parameter of the distribution (b>0) | +//| mean : Variable for mean value (1st moment) | +//| variance : Variable for variance value (2nd moment) | +//| skewness : Variable for skewness value (3rd moment) | +//| kurtosis : Variable for kurtosis value (4th moment) | +//| error_code : Variable for error code | +//| | +//| Return value: | +//| true if moments calculated successfully, otherwise false. | +//+------------------------------------------------------------------+ +bool MathMomentsWeibull(const double a,const double b,double &mean,double &variance,double &skewness,double &kurtosis,int &error_code) + { +//--- default values + mean =QNaN; + variance=QNaN; + skewness=QNaN; + kurtosis=QNaN; +//--- check NaN + if(!MathIsValidNumber(a) || !MathIsValidNumber(b)) + { + error_code=ERR_ARGUMENTS_NAN; + return false; + } +//--- a and b must be positive + if(a<=0 || b<=0) + { + error_code=ERR_ARGUMENTS_INVALID; + return false; + } + + error_code=ERR_OK; +//--- Gamma function values + double g1 = MathGamma(1+1.0/a); + double g2 = MathGamma(1+2.0/a); + double g3 = MathGamma(1+3.0/a); + double g4 = MathGamma(1+4.0/a); +//--- calculate moments + mean =b*g1; + variance=b*b*g2-MathPow(g1,2); + skewness=(2*g1*g1*g1-3*g1*g2+g3)*MathPow(g2-g1*g1,-1.5); + kurtosis=(-6*MathPow(g1,4)+12*MathPow(g1,2)*g2-3*MathPow(g2,2)-4*g1*g3+g4)*MathPow(g2-g1*g1,-2); +//--- successful + return true; + } +//+------------------------------------------------------------------+ diff --git a/Include/MovingAverages.mqh b/Include/MovingAverages.mqh new file mode 100644 index 0000000..c690f69 --- /dev/null +++ b/Include/MovingAverages.mqh @@ -0,0 +1,240 @@ +//+------------------------------------------------------------------+ +//| MovingAverages.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +//+------------------------------------------------------------------+ +//| Simple Moving Average | +//+------------------------------------------------------------------+ +double SimpleMA(const int position,const int period,const double &price[]) + { +//--- + double result=0.0; +//--- check position + if(position>=period-1 && period>0) + { + //--- calculate value + for(int i=0;i0) + { + double pr=2.0/(period+1.0); + result=price[position]*pr+prev_value*(1-pr); + } +//--- + return(result); + } +//+------------------------------------------------------------------+ +//| Smoothed Moving Average | +//+------------------------------------------------------------------+ +double SmoothedMA(const int position,const int period,const double prev_value,const double &price[]) + { +//--- + double result=0.0; +//--- check position + if(period>0) + { + if(position==period-1) + { + for(int i=0;i=period) + result=(prev_value*(period-1)+price[position])/period; + } +//--- + return(result); + } +//+------------------------------------------------------------------+ +//| Linear Weighted Moving Average | +//+------------------------------------------------------------------+ +double LinearWeightedMA(const int position,const int period,const double &price[]) + { +//--- + double result=0.0,sum=0.0; + int i,wsum=0; +//--- calculate value + if(position>=period-1 && period>0) + { + for(i=period;i>0;i--) + { + wsum+=i; + sum+=price[position-i+1]*(period-i+1); + } + result=sum/wsum; + } +//--- + return(result); + } +//+------------------------------------------------------------------+ +//| Simple moving average on price array | +//+------------------------------------------------------------------+ +int SimpleMAOnBuffer(const int rates_total,const int prev_calculated,const int begin, + const int period,const double& price[],double& buffer[]) + { + int i,limit; +//--- check for data + if(period<=1 || rates_total-begin + bool BufferFromArray(const int buffer_index,T &data[],const uint data_array_offset,const uint data_array_count,const uint flags); + template + bool BufferRead(const int buffer_index,T &data[],const uint cl_buffer_offset,const uint data_array_offset,const uint data_array_count); + template + bool BufferWrite(const int buffer_index,T &data[],const uint cl_buffer_offset,const uint data_array_offset,const uint data_array_count); + //--- set kernel arguments + template + bool SetArgument(const int kernel_index,const int arg_index,T value); + bool SetArgumentBuffer(const int kernel_index,const int arg_index,const int buffer_index); + bool SetArgumentLocalMemory(const int kernel_index,const int arg_index,const int local_memory_size); + //--- kernel execution + bool Execute(const int kernel_index,const int work_dim,const uint &work_offset[],const uint &work_size[]); + bool Execute(const int kernel_index,const int work_dim,const uint &work_offset[],const uint &work_size[],const uint &local_work_size[]); + }; +//+------------------------------------------------------------------+ +//| COpenCL class constructor | +//+------------------------------------------------------------------+ +COpenCL::COpenCL() + { + m_context=INVALID_HANDLE; + m_program=INVALID_HANDLE; + m_buffers_total=0; + m_kernels_total=0; + m_device_extensions=""; + m_support_cl_khr_fp64=false; + } +//+------------------------------------------------------------------+ +//| COpenCL class destructor | +//+------------------------------------------------------------------+ +COpenCL::~COpenCL() + { + Shutdown(); + } +//+------------------------------------------------------------------+ +//| GetKernel | +//+------------------------------------------------------------------+ +int COpenCL::GetKernel(const int kernel_index) const + { + if(m_kernels_total<=0 || kernel_index<0 || kernel_index>=m_kernels_total) + return(INVALID_HANDLE); +//--- + return m_kernels[kernel_index]; + } +//+------------------------------------------------------------------+ +//| GetKernelName | +//+------------------------------------------------------------------+ +string COpenCL::GetKernelName(const int kernel_index) const + { + if(m_kernels_total<=0 || kernel_index<0 || kernel_index>=m_kernels_total) + return(""); +//--- + return m_kernel_names[kernel_index]; + } +//+------------------------------------------------------------------+ +//| GetGlobalMemorySize | +//+------------------------------------------------------------------+ +bool COpenCL::GetGlobalMemorySize(long &global_memory_size) + { + if(m_context==INVALID_HANDLE) + return(false); + +//--- get global memory size + global_memory_size=CLGetInfoInteger(m_context,CL_DEVICE_GLOBAL_MEM_SIZE); + if(global_memory_size==-1) + return(false); +//--- + return(true); + } +//+------------------------------------------------------------------+ +//| Initialize | +//+------------------------------------------------------------------+ +bool COpenCL::Initialize(const string program,const bool show_log=true) + { + if((m_context=CLContextCreate(CL_USE_ANY))==INVALID_HANDLE) + { + Print("OpenCL not found. Error code=",GetLastError()); + return(false); + } +//--- check support working with doubles (cl_khr_fp64) + if(CLGetInfoString(m_context,CL_DEVICE_EXTENSIONS,m_device_extensions)) + { + string extenstions[]; + StringSplit(m_device_extensions,' ',extenstions); + m_support_cl_khr_fp64=false; + int size=ArraySize(extenstions); + for(int i=0; i=m_kernels_total) + return(false); +//--- + int kernel_handle=m_kernels[kernel_index]; + if(kernel_handle==INVALID_HANDLE || m_kernel_names[kernel_index]!=kernel_name) + { + //--- create kernel + if((kernel_handle=CLKernelCreate(m_program,kernel_name))==INVALID_HANDLE) + { + CLProgramFree(m_program); + CLContextFree(m_context); + Print("OpenCL kernel create failed. Error code=",GetLastError()); + return(false); + } + else + { + m_kernels[kernel_index]=kernel_handle; + m_kernel_names[kernel_index]=kernel_name; + } + } + return(true); + } +//+------------------------------------------------------------------+ +//| KernelFree | +//+------------------------------------------------------------------+ +bool COpenCL::KernelFree(const int kernel_index) + { +//--- check kernel index + if(kernel_index<0 || kernel_index>=m_kernels_total) + return(false); + if(m_kernels[kernel_index]==INVALID_HANDLE) + return(false); +//--- free kernel handle + CLKernelFree(m_kernels[kernel_index]); + m_kernels[kernel_index]=INVALID_HANDLE; +//--- + return(true); + } +//+------------------------------------------------------------------+ +//| BufferCreate | +//+------------------------------------------------------------------+ +bool COpenCL::BufferCreate(const int buffer_index,const uint size_in_bytes,const uint flags) + { +//--- check parameters + if(buffer_index<0 || buffer_index>=m_buffers_total) + return(false); + + if(m_context==INVALID_HANDLE || m_program==INVALID_HANDLE) + return(false); +//--- + int buffer_handle=CLBufferCreate(m_context,size_in_bytes,flags); + if(buffer_handle!=INVALID_HANDLE) + { + m_buffers[buffer_index]=buffer_handle; + return(true); + } + else + return(false); + } +//+------------------------------------------------------------------+ +//| BufferFree | +//+------------------------------------------------------------------+ +bool COpenCL::BufferFree(const int buffer_index) + { +//--- check buffer index + if(buffer_index<0 || buffer_index>=m_buffers_total) + return(false); + if(m_buffers[buffer_index]==INVALID_HANDLE) + return(false); +//--- free buffer handle + CLBufferFree(m_buffers[buffer_index]); + m_buffers[buffer_index]=INVALID_HANDLE; +//--- + return(true); + } +//+------------------------------------------------------------------+ +//| BufferFromArray | +//+------------------------------------------------------------------+ +template +bool COpenCL::BufferFromArray(const int buffer_index,T &data[],const uint data_array_offset,const uint data_array_count,const uint flags) + { +//--- check parameters + if(m_context==INVALID_HANDLE || m_program==INVALID_HANDLE) + return(false); + if(buffer_index<0 || buffer_index>=m_buffers_total || data_array_count<=0) + return(false); + +//--- buffer does not exists, create it + if(m_buffers[buffer_index]==INVALID_HANDLE) + { + uint size_in_bytes=data_array_count*sizeof(T); + int buffer_handle=CLBufferCreate(m_context,size_in_bytes,flags); + if(buffer_handle!=INVALID_HANDLE) + { + m_buffers[buffer_index]=buffer_handle; + } + else + return(false); + } +//--- write data to OpenCL buffer + uint data_written=CLBufferWrite(m_buffers[buffer_index],data,0,data_array_offset,data_array_count); + if(data_written!=data_array_count) + return(false); +//--- + return(true); + } +//+------------------------------------------------------------------+ +//| BufferRead | +//+------------------------------------------------------------------+ +template +bool COpenCL::BufferRead(const int buffer_index,T &data[],const uint cl_buffer_offset,const uint data_array_offset,const uint data_array_count) + { +//--- check parameters + if(buffer_index<0 || buffer_index>=m_buffers_total || data_array_count<=0) + return(false); + if(m_buffers[buffer_index]==INVALID_HANDLE) + return(false); + if(m_context==INVALID_HANDLE || m_program==INVALID_HANDLE) + return(false); +//--- read data from OpenCL buffer + uint data_read=CLBufferRead(m_buffers[buffer_index],data,cl_buffer_offset,data_array_offset,data_array_count); + if(data_read!=data_array_count) + return(false); +//--- + return(true); + } +//+------------------------------------------------------------------+ +//| BufferWrite | +//+------------------------------------------------------------------+ +template +bool COpenCL::BufferWrite(const int buffer_index,T &data[],const uint cl_buffer_offset,const uint data_array_offset,const uint data_array_count) + { +//--- check parameters + if(buffer_index<0 || buffer_index>=m_buffers_total || data_array_count<=0) + return(false); + if(m_buffers[buffer_index]==INVALID_HANDLE) + return(false); + if(m_context==INVALID_HANDLE || m_program==INVALID_HANDLE) + return(false); +//--- write data to OpenCL buffer + uint data_written=CLBufferWrite(m_buffers[buffer_index],data,cl_buffer_offset,data_array_offset,data_array_count); + if(data_written!=data_array_count) + return(false); +//--- + return(true); + } +//+------------------------------------------------------------------+ +//| SetArgument | +//+------------------------------------------------------------------+ +template +bool COpenCL::SetArgument(const int kernel_index,const int arg_index,T value) + { + if(kernel_index<0 || kernel_index>=m_kernels_total) + return(false); + + int kernel_handle=m_kernels[kernel_index]; + if(kernel_handle==INVALID_HANDLE) + return(false); +//--- + return CLSetKernelArg(kernel_handle,arg_index,value); + } +//+------------------------------------------------------------------+ +//| SetArgumentBuffer | +//+------------------------------------------------------------------+ +bool COpenCL::SetArgumentBuffer(const int kernel_index,const int arg_index,const int buffer_index) + { + if(m_context==INVALID_HANDLE || m_program==INVALID_HANDLE) + return(false); + if(kernel_index<0 || kernel_index>=m_kernels_total) + return(false); + if(buffer_index<0 || buffer_index>=m_buffers_total) + return(false); + if(m_buffers[buffer_index]==INVALID_HANDLE) + return(false); +//--- + return CLSetKernelArgMem(m_kernels[kernel_index],arg_index,m_buffers[buffer_index]); + } +//+------------------------------------------------------------------+ +//| SetArgumentLocalMemory | +//+------------------------------------------------------------------+ +bool COpenCL::SetArgumentLocalMemory(const int kernel_index,const int arg_index,const int local_memory_size) + { + if(m_context==INVALID_HANDLE || m_program==INVALID_HANDLE) + return(false); + if(kernel_index<0 || kernel_index>=m_kernels_total) + return(false); +//--- check device local memory size + long device_local_memory_size=CLGetInfoInteger(m_context,CL_DEVICE_LOCAL_MEM_SIZE); + if(local_memory_size>device_local_memory_size) + return(false); +//--- + return CLSetKernelArgMemLocal(m_kernels[kernel_index],arg_index,local_memory_size); + } +//+------------------------------------------------------------------+ +//| Execute | +//+------------------------------------------------------------------+ +bool COpenCL::Execute(const int kernel_index,const int work_dim,const uint &work_offset[],const uint &work_size[]) + { + if(kernel_index<0 || kernel_index>=m_kernels_total) + return(false); + int kernel_handle=m_kernels[kernel_index]; + if(kernel_handle==INVALID_HANDLE) + return(false); +//--- + return CLExecute(kernel_handle,work_dim,work_offset,work_size); + } +//+------------------------------------------------------------------+ +//| Execute | +//+------------------------------------------------------------------+ +bool COpenCL::Execute(const int kernel_index,const int work_dim,const uint &work_offset[],const uint &work_size[],const uint &local_work_size[]) + { + if(kernel_index<0 || kernel_index>=m_kernels_total) + return(false); +//--- + return CLExecute(m_kernels[kernel_index],work_dim,work_offset,work_size,local_work_size); + } +//+------------------------------------------------------------------+ diff --git a/Include/StdLibErr.mqh b/Include/StdLibErr.mqh new file mode 100644 index 0000000..355bead --- /dev/null +++ b/Include/StdLibErr.mqh @@ -0,0 +1,10 @@ +//+------------------------------------------------------------------+ +//| StdLibErr.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#define ERR_USER_INVALID_HANDLE 1 +#define ERR_USER_INVALID_BUFF_NUM 2 +#define ERR_USER_ITEM_NOT_FOUND 3 +#define ERR_USER_ARRAY_IS_EMPTY 1000 +//+------------------------------------------------------------------+ diff --git a/Include/Strings/String.mqh b/Include/Strings/String.mqh new file mode 100644 index 0000000..adcb3d0 --- /dev/null +++ b/Include/Strings/String.mqh @@ -0,0 +1,377 @@ +//+------------------------------------------------------------------+ +//| String.mqh | +//| Copyright 2009-2013, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include +//+------------------------------------------------------------------+ +//| Class CString. | +//| Appointment: Class-string. | +//| Derives from class CObject. | +//+------------------------------------------------------------------+ +class CString : public CObject + { +protected: + string m_string; + +public: + CString(void); + ~CString(void); + //--- methods access + string Str(void) const { return(m_string); }; + uint Len(void) const { return(StringLen(m_string)); }; + void Copy(string ©) const; + void Copy(CString *copy) const; + //--- methods fill + bool Fill(const short character) { return(StringFill(m_string,character)); }; + void Assign(const string str) { m_string=str; }; + void Assign(const CString *str) { m_string=str.Str(); }; + void Append(const string str); + void Append(const CString *str); + uint Insert(const uint pos,const string substring); + uint Insert(const uint pos,const CString *substring); + //--- methods compare + int Compare(const string str) const; + int Compare(const CString *str) const; + int CompareNoCase(const string str) const; + int CompareNoCase(const CString *str) const; + //--- methods prepare + string Left(const uint count) const; + string Right(const uint count) const; + string Mid(const uint pos,const uint count) const; + //--- methods truncation/deletion + int Trim(const string targets); + int TrimLeft(const string targets); + int TrimRight(const string targets); + bool Clear(void) { return(StringInit(m_string)); }; + //--- methods conversion + bool ToUpper(void) { return(StringToUpper(m_string)); }; + bool ToLower(void) { return(StringToLower(m_string)); }; + void Reverse(void); + //--- methods find + int Find(const uint start,const string substring) const; + int FindRev(const string substring) const; + uint Remove(const string substring); + uint Replace(const string substring,const string newstring); + +protected: + virtual int Compare(const CObject *node,const int mode=0) const; + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CString::CString(void) : m_string("") + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CString::~CString(void) + { + } +//+------------------------------------------------------------------+ +//| Copy the string value member to copy | +//+------------------------------------------------------------------+ +void CString::Copy(string ©) const + { + copy=m_string; + } +//+------------------------------------------------------------------+ +//| Copy the string value member to copy | +//+------------------------------------------------------------------+ +void CString::Copy(CString *copy) const + { + copy.Assign(m_string); + } +//+------------------------------------------------------------------+ +//| Add a string to the end | +//+------------------------------------------------------------------+ +void CString::Append(const string str) + { + m_string+=str; + } +//+------------------------------------------------------------------+ +//| Add a string to the end | +//+------------------------------------------------------------------+ +void CString::Append(const CString *str) + { +//--- check + if(!CheckPointer(str)) + return; +//--- + m_string+=str.Str(); + } +//+------------------------------------------------------------------+ +//| Insert a string in specified position | +//+------------------------------------------------------------------+ +uint CString::Insert(const uint pos,const string substring) + { + string tmp=StringSubstr(m_string,0,pos); +//--- + tmp+=substring; + m_string=tmp+StringSubstr(m_string,pos); +//--- result + return(StringLen(m_string)); + } +//+------------------------------------------------------------------+ +//| Insert a string in specified position | +//+------------------------------------------------------------------+ +uint CString::Insert(const uint pos,const CString *substring) + { +//--- check + if(!CheckPointer(substring)) + return(0); +//--- + string tmp=StringSubstr(m_string,0,pos); +//--- + tmp+=substring.Str(); + m_string=tmp+StringSubstr(m_string,pos); +//--- result + return(StringLen(m_string)); + } +//+------------------------------------------------------------------+ +//| Comparison with the string | +//+------------------------------------------------------------------+ +int CString::Compare(const string str) const + { + if(m_stringstr) + return(1); +//--- equal + return(0); + } +//+------------------------------------------------------------------+ +//| Comparison with the string | +//+------------------------------------------------------------------+ +int CString::Compare(const CString *str) const + { +//--- check + if(!CheckPointer(str)) + return(0); +//--- + if(m_stringstr.Str()) + return(1); +//--- equal + return(0); + } +//+------------------------------------------------------------------+ +//| Comparison with the string without case | +//+------------------------------------------------------------------+ +int CString::CompareNoCase(const string str) const + { + string tmp1,tmp2; +//--- + tmp1=m_string; + tmp2=str; + StringToLower(tmp1); + StringToLower(tmp2); +//--- + if(tmp1tmp2) + return(1); +//--- equal + return(0); + } +//+------------------------------------------------------------------+ +//| Comparison with the string without case | +//+------------------------------------------------------------------+ +int CString::CompareNoCase(const CString *str) const + { + string tmp1,tmp2; +//--- check + if(!CheckPointer(str)) + return(0); +//--- + tmp1=m_string; + tmp2=str.Str(); + StringToLower(tmp1); + StringToLower(tmp2); +//--- + if(tmp1tmp2) + return(1); +//--- equal + return(0); + } +//+------------------------------------------------------------------+ +//| Find occurrences of substring from the specified position | +//+------------------------------------------------------------------+ +int CString::Find(const uint start,const string substring) const + { + return(StringFind(m_string,substring,start)); + } +//+------------------------------------------------------------------+ +//| Find last occurrence of substring | +//+------------------------------------------------------------------+ +int CString::FindRev(const string substring) const + { + int result,pos=-1; +//--- + do + { + result=pos; + } + while((pos=StringFind(m_string,substring,pos+1))>=0); +//--- result + return(result); + } +//+------------------------------------------------------------------+ +//| Get a substring consisting of count elements of the left string | +//+------------------------------------------------------------------+ +string CString::Left(const uint count) const + { + return(StringSubstr(m_string,0,count)); + } +//+------------------------------------------------------------------+ +//| Get a substring consisting of count elements of the right string.| +//+------------------------------------------------------------------+ +string CString::Right(const uint count) const + { + return(StringSubstr(m_string,StringLen(m_string)-count,count)); + } +//+------------------------------------------------------------------+ +//| Get a substring consisting of count elements of the pos string | +//+------------------------------------------------------------------+ +string CString::Mid(const uint pos,const uint count) const + { + return(StringSubstr(m_string,pos,count)); + } +//+------------------------------------------------------------------+ +//| Remove from the string, all characters in the begin and | +//| in the end if they arein targets, or space, \t,\n or \r | +//+------------------------------------------------------------------+ +int CString::Trim(const string targets) + { + return(TrimLeft(targets)+TrimRight(targets)); + } +//+------------------------------------------------------------------+ +//| Remove from the string, all characters in the begin if they are | +//| in targets, or space, \t,\n or \r | +//+------------------------------------------------------------------+ +int CString::TrimLeft(const string targets) + { + ushort ch; +//--- + for(int i=0;i=0;i--) + { + ch=StringGetCharacter(m_string,i); + if(ch<=' ') + continue; + for(int j=0;jj;i--,j++) + { + ch=StringGetCharacter(m_string,i); + StringSetCharacter(m_string,i,StringGetCharacter(m_string,j)); + StringSetCharacter(m_string,j,ch); + } + } +//+------------------------------------------------------------------+ +//| Remove all occurrences of the substring | +//+------------------------------------------------------------------+ +uint CString::Remove(const string substring) + { + int result=0,len,pos=-1; + string tmp; +//--- + len=StringLen(substring); + while((pos=StringFind(m_string,substring,pos))>=0) + { + tmp=StringSubstr(m_string,0,pos); + m_string=tmp+StringSubstr(m_string,pos+len); + result++; + } +//--- result + return(result); + } +//+------------------------------------------------------------------+ +//| Replace all occurrences of a substring in the specified string | +//+------------------------------------------------------------------+ +uint CString::Replace(const string substring,const string newstring) + { + int result=0,len,pos=-1; + string tmp; +//--- + len=StringLen(substring); + while((pos=StringFind(m_string,substring,pos))>=0) + { + tmp=StringSubstr(m_string,0,pos)+newstring; + m_string=tmp+StringSubstr(m_string,pos+len); + // to eliminate possible loops + pos+=StringLen(newstring); + result++; + } +//--- result + return(result); + } +//+------------------------------------------------------------------+ +//| Comparison with the string by algorithm | +//+------------------------------------------------------------------+ +int CString::Compare(const CObject *node,const int mode=0) const + { + CString *str=(CString*)node; +//--- check + if(str==NULL) + return(0); +//--- + switch(mode) + { + case 0: return(Compare(str)); + case 1: return(CompareNoCase(str)); + } +//--- equal + return(0); + } +//+------------------------------------------------------------------+ diff --git a/Include/Tools/DateTime.mqh b/Include/Tools/DateTime.mqh new file mode 100644 index 0000000..94d405b --- /dev/null +++ b/Include/Tools/DateTime.mqh @@ -0,0 +1,581 @@ +//+------------------------------------------------------------------+ +//| DateTime.mqh | +//| Copyright 2009-2015, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ +//| Structure CDateTime. | +//| Purpose: Working with dates and time. | +//| Extends the MqlDateTime structure. | +//+------------------------------------------------------------------+ +struct CDateTime : public MqlDateTime + { + //--- additional information + string MonthName(const int num) const; + string ShortMonthName(const int num) const; + string DayName(const int num) const; + string ShortDayName(const int num) const; + string MonthName(void) const { return(MonthName(mon)); } + string ShortMonthName(void) const { return(ShortMonthName(mon)); } + string DayName(void) const { return(DayName(day_of_week)); } + string ShortDayName(void) const { return(ShortDayName(day_of_week)); } + int DaysInMonth(void) const; + //--- data access + datetime DateTime(void) { return(StructToTime(this)); } + void DateTime(const datetime value) { TimeToStruct(value,this); } + void DateTime(const MqlDateTime& value) { this=value; } + void Date(const datetime value); + void Date(const MqlDateTime &value); + void Time(const datetime value); + void Time(const MqlDateTime &value); + //--- settings + void Sec(const int value); + void Min(const int value); + void Hour(const int value); + void Day(const int value); + void Mon(const int value); + void Year(const int value); + //--- increments + void SecDec(int delta=1); + void SecInc(int delta=1); + void MinDec(int delta=1); + void MinInc(int delta=1); + void HourDec(int delta=1); + void HourInc(int delta=1); + void DayDec(int delta=1); + void DayInc(int delta=1); + void MonDec(int delta=1); + void MonInc(int delta=1); + void YearDec(int delta=1); + void YearInc(int delta=1); + //--- check + void DayCheck(void); + }; +//+------------------------------------------------------------------+ +//| Gets month name | +//+------------------------------------------------------------------+ +string CDateTime::MonthName(const int num) const + { + switch(num) + { + case 1: return("January"); + case 2: return("February"); + case 3: return("March"); + case 4: return("April"); + case 5: return("May"); + case 6: return("June"); + case 7: return("July"); + case 8: return("August"); + case 9: return("September"); + case 10: return("October"); + case 11: return("November"); + case 12: return("December"); + } +//--- + return("Bad month"); + } +//+------------------------------------------------------------------+ +//| Gets short name of month | +//+------------------------------------------------------------------+ +string CDateTime::ShortMonthName(const int num) const + { + switch(num) + { + case 1: return("jan"); + case 2: return("feb"); + case 3: return("mar"); + case 4: return("apr"); + case 5: return("may"); + case 6: return("jun"); + case 7: return("jul"); + case 8: return("aug"); + case 9: return("sep"); + case 10: return("oct"); + case 11: return("nov"); + case 12: return("dec"); + } +//--- + return("Bad month"); + } +//+------------------------------------------------------------------+ +//| Gets name of week day | +//+------------------------------------------------------------------+ +string CDateTime::DayName(const int num) const + { + switch(num) + { + case 0: return("Sunday"); + case 1: return("Monday"); + case 2: return("Tuesday"); + case 3: return("Wednesday"); + case 4: return("Thursday"); + case 5: return("Friday"); + case 6: return("Saturday"); + } +//--- + return("Bad day of week"); + } +//+------------------------------------------------------------------+ +//| Gets short name of week day | +//+------------------------------------------------------------------+ +string CDateTime::ShortDayName(const int num) const + { + switch(num) + { + case 0: return("Su"); + case 1: return("Mo"); + case 2: return("Tu"); + case 3: return("We"); + case 4: return("Th"); + case 5: return("Fr"); + case 6: return("Sa"); + } +//--- + return("Bad day of week"); + } +//+------------------------------------------------------------------+ +//| Gets number of days in month | +//+------------------------------------------------------------------+ +int CDateTime::DaysInMonth(void) const + { + int leap_year; +//--- + switch(mon) + { + case 1: + case 3: + case 5: + case 7: + case 8: + case 10: + case 12: + return(31); + case 2: + leap_year=year; + if(year%100==0) + leap_year/=100; + return((leap_year%4==0)? 29 : 28); + case 4: + case 6: + case 9: + case 11: + return(30); + } +//--- + return(0); + } +//+------------------------------------------------------------------+ +//| Sets date | +//+------------------------------------------------------------------+ +void CDateTime::Date(const datetime value) + { + MqlDateTime dt; +//--- convert to structure + TimeToStruct(value,dt); +//--- set + Date(dt); + } +//+------------------------------------------------------------------+ +//| Sets date | +//+------------------------------------------------------------------+ +void CDateTime::Date(const MqlDateTime &value) + { + day =value.day; + mon =value.mon; + year=value.year; +//--- check if day is correct + DayCheck(); + } +//+------------------------------------------------------------------+ +//| Sets time | +//+------------------------------------------------------------------+ +void CDateTime::Time(const datetime value) + { + MqlDateTime dt; +//--- convert to structure + TimeToStruct(value,dt); +//--- set + Time(dt); + } +//+------------------------------------------------------------------+ +//| Sets time | +//+------------------------------------------------------------------+ +void CDateTime::Time(const MqlDateTime &value) + { + hour=value.hour; + min =value.min; + sec =value.sec; + } +//+------------------------------------------------------------------+ +//| Sets seconds | +//+------------------------------------------------------------------+ +void CDateTime::Sec(const int value) + { +//--- check and set + if(value>=0 && value<60) + sec=value; + } +//+------------------------------------------------------------------+ +//| Sets minutes | +//+------------------------------------------------------------------+ +void CDateTime::Min(const int value) + { +//--- check and set + if(value>=0 && value<60) + min=value; + } +//+------------------------------------------------------------------+ +//| Sets hours | +//+------------------------------------------------------------------+ +void CDateTime::Hour(const int value) + { +//--- check and set + if(value>=0 && value<24) + hour=value; + } +//+------------------------------------------------------------------+ +//| Sets day of month | +//+------------------------------------------------------------------+ +void CDateTime::Day(const int value) + { +//--- check and set + if(value>0 && value<=DaysInMonth()) + { + day=value; + //--- check if day is correct + DayCheck(); + } + } +//+------------------------------------------------------------------+ +//| Sets month | +//+------------------------------------------------------------------+ +void CDateTime::Mon(const int value) + { +//--- check and set + if(value>0 && value<=12) + { + mon=value; + //--- check if day is correct + DayCheck(); + } + } +//+------------------------------------------------------------------+ +//| Sets year | +//+------------------------------------------------------------------+ +void CDateTime::Year(const int value) + { +//--- check and set + if(value>=1970) + { + year=value; + //--- check if day is correct + DayCheck(); + } + } +//+------------------------------------------------------------------+ +//| Subtracts specified number of seconds | +//+------------------------------------------------------------------+ +void CDateTime::SecDec(int delta) + { +//--- if increment is 0 - exit + if(delta==0) + return; +//--- if increment is negative - inverse the operation + if(delta<0) + { + SecInc(-delta); + return; + } +//--- check if subtract from upper number positions + if(delta>60) + { + MinDec(delta/60); + delta%=60; + } + sec-=delta; + if(sec<0) + { + sec+=60; + MinDec(); + } + } +//+------------------------------------------------------------------+ +//| Adds specified number of seconds | +//+------------------------------------------------------------------+ +void CDateTime::SecInc(int delta) + { +//--- if increment is 0 - exit + if(delta==0) + return; +//--- if increment is negative - inverse the operation + if(delta<0) + { + SecDec(-delta); + return; + } +//--- check if add to upper number positions + if(delta>60) + { + MinInc(delta/60); + delta%=60; + } + sec+=delta; + if(sec>=60) + { + sec-=60; + MinInc(); + } + } +//+------------------------------------------------------------------+ +//| Subtracts specified number of minutes | +//+------------------------------------------------------------------+ +void CDateTime::MinDec(int delta) + { +//--- if increment is 0 - exit + if(delta==0) + return; +//--- if increment is negative - inverse the operation + if(delta<0) + { + MinInc(-delta); + return; + } +//--- check if subtract from upper number positions + if(delta>60) + { + HourDec(delta/60); + delta%=60; + } + min-=delta; + if(min<0) + { + min+=60; + HourDec(); + } + } +//+------------------------------------------------------------------+ +//| Adds specified number of minutes | +//+------------------------------------------------------------------+ +void CDateTime::MinInc(int delta) + { +//--- if increment is 0 - exit + if(delta==0) + return; +//--- if increment is negative - inverse the operation + if(delta<0) + { + MinDec(-delta); + return; + } +//--- check if add to upper number positions + if(delta>60) + { + HourInc(delta/60); + delta%=60; + } + min+=delta; + if(min>=60) + { + min-=60; + HourInc(); + } + } +//+------------------------------------------------------------------+ +//| Subtracts specified number of hours | +//+------------------------------------------------------------------+ +void CDateTime::HourDec(int delta) + { +//--- if increment is 0 - exit + if(delta==0) + return; +//--- if increment is negative - inverse the operation + if(delta<0) + { + HourInc(-delta); + return; + } +//--- check if subtract from upper number positions + if(delta>24) + { + DayDec(delta/24); + delta%=24; + } + hour-=delta; + if(hour<0) + { + hour+=24; + DayDec(); + } + } +//+------------------------------------------------------------------+ +//| Adds specified number of hours | +//+------------------------------------------------------------------+ +void CDateTime::HourInc(int delta) + { +//--- if increment is 0 - exit + if(delta==0) + return; +//--- if increment is negative - inverse the operation + if(delta<0) + { + HourDec(-delta); + return; + } +//--- check if add to upper number positions + if(delta>24) + { + DayInc(delta/24); + delta%=24; + } + hour+=delta; + if(hour>=24) + { + hour-=24; + DayInc(); + } + } +//+------------------------------------------------------------------+ +//| Subtracts specified number of days | +//+------------------------------------------------------------------+ +void CDateTime::DayDec(int delta) + { +//--- if increment is 0 - exit + if(delta==0) + return; +//--- if increment is negative - inverse the operation + if(delta<0) + { + DayInc(-delta); + return; + } +//--- uncertain condition, as the number of days in month can differ + while(day<=delta) + { + delta-=day; + MonDec(); + day=DaysInMonth(); + } + day-=delta; +//--- check if day is correct + DayCheck(); + } +//+------------------------------------------------------------------+ +//| Adds specified number of days | +//+------------------------------------------------------------------+ +void CDateTime::DayInc(int delta) + { +//--- if increment is 0 - exit + if(delta==0) + return; +//--- if increment is negative - inverse the operation + if(delta<0) + { + DayDec(-delta); + return; + } +//--- uncertain condition, as the number of days in month can differ + while(DaysInMonth()-day12) + { + YearDec(delta/12); + delta%=12; + } + mon-=delta; + if(mon<=0) + { + mon+=12; + YearDec(); + } +//--- check if day is correct + DayCheck(); + } +//+------------------------------------------------------------------+ +//| Adds specified number of months | +//+------------------------------------------------------------------+ +void CDateTime::MonInc(int delta) + { +//--- if increment is 0 - exit + if(delta==0) + return; +//--- if increment is negative - inverse the operation + if(delta<0) + { + MonDec(-delta); + return; + } +//--- check if add to upper number positions + if(delta>12) + { + YearInc(delta/12); + delta%=12; + } + mon+=delta; + if(mon>12) + { + mon-=12; + YearInc(); + } +//--- check if day is correct + DayCheck(); + } +//+------------------------------------------------------------------+ +//| Subtracts specified number of years | +//+------------------------------------------------------------------+ +void CDateTime::YearDec(int delta) + { +//--- if increment is 0 - exit + if(delta!=0) + { + year-=delta; + //--- check if day is correct + DayCheck(); + } + } +//+------------------------------------------------------------------+ +//| Adds specified number of years | +//+------------------------------------------------------------------+ +void CDateTime::YearInc(int delta) + { +//--- if increment is 0 - exit + if(delta!=0) + { + year+=delta; + //--- check if day is correct + DayCheck(); + } + } +//+------------------------------------------------------------------+ +//| Checks if day number is correct | +//+------------------------------------------------------------------+ +void CDateTime::DayCheck(void) + { + if(day>DaysInMonth()) + day=DaysInMonth(); +//--- this is required to get day of week and day of year + TimeToStruct(StructToTime(this),this); + } +//+------------------------------------------------------------------+ diff --git a/Include/Trade/AccountInfo.mqh b/Include/Trade/AccountInfo.mqh new file mode 100644 index 0000000..30b5703 --- /dev/null +++ b/Include/Trade/AccountInfo.mqh @@ -0,0 +1,378 @@ +//+------------------------------------------------------------------+ +//| AccountInfo.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include +//+------------------------------------------------------------------+ +//| Class CAccountInfo. | +//| Appointment: Class for access to account info. | +//| Derives from class CObject. | +//+------------------------------------------------------------------+ +class CAccountInfo : public CObject + { +public: + CAccountInfo(void); + ~CAccountInfo(void); + //--- fast access methods to the integer account propertyes + long Login(void) const; + ENUM_ACCOUNT_TRADE_MODE TradeMode(void) const; + string TradeModeDescription(void) const; + long Leverage(void) const; + ENUM_ACCOUNT_STOPOUT_MODE StopoutMode(void) const; + string StopoutModeDescription(void) const; + ENUM_ACCOUNT_MARGIN_MODE MarginMode(void) const; + string MarginModeDescription(void) const; + bool TradeAllowed(void) const; + bool TradeExpert(void) const; + int LimitOrders(void) const; + //--- fast access methods to the double account propertyes + double Balance(void) const; + double Credit(void) const; + double Profit(void) const; + double Equity(void) const; + double Margin(void) const; + double FreeMargin(void) const; + double MarginLevel(void) const; + double MarginCall(void) const; + double MarginStopOut(void) const; + //--- fast access methods to the string account propertyes + string Name(void) const; + string Server(void) const; + string Currency(void) const; + string Company(void) const; + //--- access methods to the API MQL5 functions + long InfoInteger(const ENUM_ACCOUNT_INFO_INTEGER prop_id) const; + double InfoDouble(const ENUM_ACCOUNT_INFO_DOUBLE prop_id) const; + string InfoString(const ENUM_ACCOUNT_INFO_STRING prop_id) const; + //--- checks + double OrderProfitCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation, + const double volume,const double price_open,const double price_close) const; + double MarginCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation, + const double volume,const double price) const; + double FreeMarginCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation, + const double volume,const double price) const; + double MaxLotCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation, + const double price,const double percent=100) const; + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CAccountInfo::CAccountInfo(void) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CAccountInfo::~CAccountInfo(void) + { + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_LOGIN" | +//+------------------------------------------------------------------+ +long CAccountInfo::Login(void) const + { + return(AccountInfoInteger(ACCOUNT_LOGIN)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_TRADE_MODE" | +//+------------------------------------------------------------------+ +ENUM_ACCOUNT_TRADE_MODE CAccountInfo::TradeMode(void) const + { + return((ENUM_ACCOUNT_TRADE_MODE)AccountInfoInteger(ACCOUNT_TRADE_MODE)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_TRADE_MODE" as string | +//+------------------------------------------------------------------+ +string CAccountInfo::TradeModeDescription(void) const + { + string str; +//--- + switch(TradeMode()) + { + case ACCOUNT_TRADE_MODE_DEMO : str="Demo trading account"; break; + case ACCOUNT_TRADE_MODE_CONTEST: str="Contest trading account"; break; + case ACCOUNT_TRADE_MODE_REAL : str="Real trading account"; break; + default : str="Unknown trade account"; + } +//--- + return(str); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_LEVERAGE" | +//+------------------------------------------------------------------+ +long CAccountInfo::Leverage(void) const + { + return(AccountInfoInteger(ACCOUNT_LEVERAGE)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_MARGIN_SO_MODE" | +//+------------------------------------------------------------------+ +ENUM_ACCOUNT_STOPOUT_MODE CAccountInfo::StopoutMode(void) const + { + return((ENUM_ACCOUNT_STOPOUT_MODE)AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_MARGIN_SO_MODE" as string | +//+------------------------------------------------------------------+ +string CAccountInfo::StopoutModeDescription(void) const + { + string str; +//--- + switch(StopoutMode()) + { + case ACCOUNT_STOPOUT_MODE_PERCENT: str="Level is specified in percentage"; break; + case ACCOUNT_STOPOUT_MODE_MONEY : str="Level is specified in money"; break; + default : str="Unknown stopout mode"; + } +//--- + return(str); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_MARGIN_MODE" | +//+------------------------------------------------------------------+ +ENUM_ACCOUNT_MARGIN_MODE CAccountInfo::MarginMode(void) const + { + return((ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_MARGIN_MODE" as string | +//+------------------------------------------------------------------+ +string CAccountInfo::MarginModeDescription(void) const + { + string str; +//--- + switch(MarginMode()) + { + case ACCOUNT_MARGIN_MODE_RETAIL_NETTING: str="Netting"; break; + case ACCOUNT_MARGIN_MODE_EXCHANGE : str="Exchange"; break; + case ACCOUNT_MARGIN_MODE_RETAIL_HEDGING: str="Hedging"; break; + default : str="Unknown margin mode"; + } +//--- + return(str); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_TRADE_ALLOWED" | +//+------------------------------------------------------------------+ +bool CAccountInfo::TradeAllowed(void) const + { + return((bool)AccountInfoInteger(ACCOUNT_TRADE_ALLOWED)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_TRADE_EXPERT" | +//+------------------------------------------------------------------+ +bool CAccountInfo::TradeExpert(void) const + { + return((bool)AccountInfoInteger(ACCOUNT_TRADE_EXPERT)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_LIMIT_ORDERS" | +//+------------------------------------------------------------------+ +int CAccountInfo::LimitOrders(void) const + { + return((int)AccountInfoInteger(ACCOUNT_LIMIT_ORDERS)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_BALANCE" | +//+------------------------------------------------------------------+ +double CAccountInfo::Balance(void) const + { + return(AccountInfoDouble(ACCOUNT_BALANCE)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_CREDIT" | +//+------------------------------------------------------------------+ +double CAccountInfo::Credit(void) const + { + return(AccountInfoDouble(ACCOUNT_CREDIT)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_PROFIT" | +//+------------------------------------------------------------------+ +double CAccountInfo::Profit(void) const + { + return(AccountInfoDouble(ACCOUNT_PROFIT)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_EQUITY" | +//+------------------------------------------------------------------+ +double CAccountInfo::Equity(void) const + { + return(AccountInfoDouble(ACCOUNT_EQUITY)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_MARGIN" | +//+------------------------------------------------------------------+ +double CAccountInfo::Margin(void) const + { + return(AccountInfoDouble(ACCOUNT_MARGIN)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_FREEMARGIN" | +//+------------------------------------------------------------------+ +double CAccountInfo::FreeMargin(void) const + { + return(AccountInfoDouble(ACCOUNT_FREEMARGIN)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_MARGIN_LEVEL" | +//+------------------------------------------------------------------+ +double CAccountInfo::MarginLevel(void) const + { + return(AccountInfoDouble(ACCOUNT_MARGIN_LEVEL)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_MARGIN_SO_CALL" | +//+------------------------------------------------------------------+ +double CAccountInfo::MarginCall(void) const + { + return(AccountInfoDouble(ACCOUNT_MARGIN_SO_CALL)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_MARGIN_SO_SO" | +//+------------------------------------------------------------------+ +double CAccountInfo::MarginStopOut(void) const + { + return(AccountInfoDouble(ACCOUNT_MARGIN_SO_SO)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_NAME" | +//+------------------------------------------------------------------+ +string CAccountInfo::Name(void) const + { + return(AccountInfoString(ACCOUNT_NAME)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_SERVER" | +//+------------------------------------------------------------------+ +string CAccountInfo::Server(void) const + { + return(AccountInfoString(ACCOUNT_SERVER)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_CURRENCY" | +//+------------------------------------------------------------------+ +string CAccountInfo::Currency(void) const + { + return(AccountInfoString(ACCOUNT_CURRENCY)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ACCOUNT_COMPANY" | +//+------------------------------------------------------------------+ +string CAccountInfo::Company(void) const + { + return(AccountInfoString(ACCOUNT_COMPANY)); + } +//+------------------------------------------------------------------+ +//| Access functions AccountInfoInteger(...) | +//+------------------------------------------------------------------+ +long CAccountInfo::InfoInteger(const ENUM_ACCOUNT_INFO_INTEGER prop_id) const + { + return(AccountInfoInteger(prop_id)); + } +//+------------------------------------------------------------------+ +//| Access functions AccountInfoDouble(...) | +//+------------------------------------------------------------------+ +double CAccountInfo::InfoDouble(const ENUM_ACCOUNT_INFO_DOUBLE prop_id) const + { + return(AccountInfoDouble(prop_id)); + } +//+------------------------------------------------------------------+ +//| Access functions AccountInfoString(...) | +//+------------------------------------------------------------------+ +string CAccountInfo::InfoString(const ENUM_ACCOUNT_INFO_STRING prop_id) const + { + return(AccountInfoString(prop_id)); + } +//+------------------------------------------------------------------+ +//| Access functions OrderCalcProfit(...). | +//| INPUT: name - symbol name, | +//| trade_operation - trade operation, | +//| volume - volume of the opening position, | +//| price_open - price of the opening position, | +//| price_close - price of the closing position. | +//+------------------------------------------------------------------+ +double CAccountInfo::OrderProfitCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation, + const double volume,const double price_open,const double price_close) const + { + double profit=EMPTY_VALUE; +//--- + if(!OrderCalcProfit(trade_operation,symbol,volume,price_open,price_close,profit)) + return(EMPTY_VALUE); +//--- + return(profit); + } +//+------------------------------------------------------------------+ +//| Access functions OrderCalcMargin(...). | +//| INPUT: name - symbol name, | +//| trade_operation - trade operation, | +//| volume - volume of the opening position, | +//| price - price of the opening position. | +//+------------------------------------------------------------------+ +double CAccountInfo::MarginCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation, + const double volume,const double price) const + { + double margin=EMPTY_VALUE; +//--- + if(!OrderCalcMargin(trade_operation,symbol,volume,price,margin)) + return(EMPTY_VALUE); +//--- + return(margin); + } +//+------------------------------------------------------------------+ +//| Access functions OrderCalcMargin(...). | +//| INPUT: name - symbol name, | +//| trade_operation - trade operation, | +//| volume - volume of the opening position, | +//| price - price of the opening position. | +//+------------------------------------------------------------------+ +double CAccountInfo::FreeMarginCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation, + const double volume,const double price) const + { + return(FreeMargin()-MarginCheck(symbol,trade_operation,volume,price)); + } +//+------------------------------------------------------------------+ +//| Access functions OrderCalcMargin(...). | +//| INPUT: name - symbol name, | +//| trade_operation - trade operation, | +//| price - price of the opening position, | +//| percent - percent of available margin [1-100%]. | +//+------------------------------------------------------------------+ +double CAccountInfo::MaxLotCheck(const string symbol,const ENUM_ORDER_TYPE trade_operation, + const double price,const double percent) const + { + double margin=0.0; +//--- checks + if(symbol=="" || price<=0.0 || percent<1 || percent>100) + { + Print("CAccountInfo::MaxLotCheck invalid parameters"); + return(0.0); + } +//--- calculate margin requirements for 1 lot + if(!OrderCalcMargin(trade_operation,symbol,1.0,price,margin) || margin<0.0) + { + Print("CAccountInfo::MaxLotCheck margin calculation failed"); + return(0.0); + } +//--- + if(margin==0.0) // for pending orders + return(SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX)); +//--- calculate maximum volume + double volume=NormalizeDouble(FreeMargin()*percent/100.0/margin,2); +//--- normalize and check limits + double stepvol=SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP); + if(stepvol>0.0) + volume=stepvol*MathFloor(volume/stepvol); +//--- + double minvol=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN); + if(volumemaxvol) + volume=maxvol; +//--- return volume + return(volume); + } +//+------------------------------------------------------------------+ diff --git a/Include/Trade/DealInfo.mqh b/Include/Trade/DealInfo.mqh new file mode 100644 index 0000000..01882a5 --- /dev/null +++ b/Include/Trade/DealInfo.mqh @@ -0,0 +1,352 @@ +//+------------------------------------------------------------------+ +//| DealInfo.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include "SymbolInfo.mqh" +//+------------------------------------------------------------------+ +//| Class CDealInfo. | +//| Appointment: Class for access to history deal info. | +//| Derives from class CObject. | +//+------------------------------------------------------------------+ +class CDealInfo : public CObject + { +protected: + ulong m_ticket; // ticket of history order + +public: + CDealInfo(void); + ~CDealInfo(void); + //--- methods of access to protected data + void Ticket(const ulong ticket) { m_ticket=ticket; } + ulong Ticket(void) const { return(m_ticket); } + //--- fast access methods to the integer position propertyes + long Order(void) const; + datetime Time(void) const; + ulong TimeMsc(void) const; + ENUM_DEAL_TYPE DealType(void) const; + string TypeDescription(void) const; + ENUM_DEAL_ENTRY Entry(void) const; + string EntryDescription(void) const; + long Magic(void) const; + long PositionId(void) const; + //--- fast access methods to the double position propertyes + double Volume(void) const; + double Price(void) const; + double Commission(void) const; + double Swap(void) const; + double Profit(void) const; + //--- fast access methods to the string position propertyes + string Symbol(void) const; + string Comment(void) const; + string ExternalId(void) const; + //--- access methods to the API MQL5 functions + bool InfoInteger(ENUM_DEAL_PROPERTY_INTEGER prop_id,long &var) const; + bool InfoDouble(ENUM_DEAL_PROPERTY_DOUBLE prop_id,double &var) const; + bool InfoString(ENUM_DEAL_PROPERTY_STRING prop_id,string &var) const; + //--- info methods + string FormatAction(string &str,const uint action) const; + string FormatEntry(string &str,const uint entry) const; + string FormatDeal(string &str) const; + //--- method for select deal + bool SelectByIndex(const int index); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CDealInfo::CDealInfo(void) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CDealInfo::~CDealInfo(void) + { + } +//+------------------------------------------------------------------+ +//| Get the property value "DEAL_ORDER" | +//+------------------------------------------------------------------+ +long CDealInfo::Order(void) const + { + return(HistoryDealGetInteger(m_ticket,DEAL_ORDER)); + } +//+------------------------------------------------------------------+ +//| Get the property value "DEAL_TIME" | +//+------------------------------------------------------------------+ +datetime CDealInfo::Time(void) const + { + return((datetime)HistoryDealGetInteger(m_ticket,DEAL_TIME)); + } +//+------------------------------------------------------------------+ +//| Get the property value "DEAL_TIME_MSC" | +//+------------------------------------------------------------------+ +ulong CDealInfo::TimeMsc(void) const + { + return(HistoryDealGetInteger(m_ticket,DEAL_TIME_MSC)); + } +//+------------------------------------------------------------------+ +//| Get the property value "DEAL_TYPE" | +//+------------------------------------------------------------------+ +ENUM_DEAL_TYPE CDealInfo::DealType(void) const + { + return((ENUM_DEAL_TYPE)HistoryDealGetInteger(m_ticket,DEAL_TYPE)); + } +//+------------------------------------------------------------------+ +//| Get the property value "DEAL_TYPE" as string | +//+------------------------------------------------------------------+ +string CDealInfo::TypeDescription(void) const + { + string str; +//--- + switch(DealType()) + { + case DEAL_TYPE_BUY : str="Buy type"; break; + case DEAL_TYPE_SELL : str="Sell type"; break; + case DEAL_TYPE_BALANCE : str="Balance type"; break; + case DEAL_TYPE_CREDIT : str="Credit type"; break; + case DEAL_TYPE_CHARGE : str="Charge type"; break; + case DEAL_TYPE_CORRECTION : str="Correction type"; break; + case DEAL_TYPE_BONUS : str="Bonus type"; break; + case DEAL_TYPE_COMMISSION : str="Commission type"; break; + case DEAL_TYPE_COMMISSION_DAILY : str="Daily Commission type"; break; + case DEAL_TYPE_COMMISSION_MONTHLY : str="Monthly Commission type"; break; + case DEAL_TYPE_COMMISSION_AGENT_DAILY : str="Daily Agent Commission type"; break; + case DEAL_TYPE_COMMISSION_AGENT_MONTHLY: str="Monthly Agent Commission type"; break; + case DEAL_TYPE_INTEREST : str="Interest Rate type"; break; + case DEAL_TYPE_BUY_CANCELED : str="Canceled Buy type"; break; + case DEAL_TYPE_SELL_CANCELED : str="Canceled Sell type"; break; + default : str="Unknown type"; + } +//--- + return(str); + } +//+------------------------------------------------------------------+ +//| Get the property value "DEAL_ENTRY" | +//+------------------------------------------------------------------+ +ENUM_DEAL_ENTRY CDealInfo::Entry(void) const + { + return((ENUM_DEAL_ENTRY)HistoryDealGetInteger(m_ticket,DEAL_ENTRY)); + } +//+------------------------------------------------------------------+ +//| Get the property value "DEAL_ENTRY" as string | +//+------------------------------------------------------------------+ +string CDealInfo::EntryDescription(void) const + { + string str; +//--- + switch(Entry()) + { + case DEAL_ENTRY_IN : str="In entry"; break; + case DEAL_ENTRY_OUT : str="Out entry"; break; + case DEAL_ENTRY_INOUT : str="InOut entry"; break; + case DEAL_ENTRY_STATE : str="Status record"; break; + case DEAL_ENTRY_OUT_BY : str="Out By entry"; break; + default : str="Unknown entry"; + } +//--- + return(str); + } +//+------------------------------------------------------------------+ +//| Get the property value "DEAL_MAGIC" | +//+------------------------------------------------------------------+ +long CDealInfo::Magic(void) const + { + return(HistoryDealGetInteger(m_ticket,DEAL_MAGIC)); + } +//+------------------------------------------------------------------+ +//| Get the property value "DEAL_POSITION_ID" | +//+------------------------------------------------------------------+ +long CDealInfo::PositionId(void) const + { + return(HistoryDealGetInteger(m_ticket,DEAL_POSITION_ID)); + } +//+------------------------------------------------------------------+ +//| Get the property value "DEAL_VOLUME" | +//+------------------------------------------------------------------+ +double CDealInfo::Volume(void) const + { + return(HistoryDealGetDouble(m_ticket,DEAL_VOLUME)); + } +//+------------------------------------------------------------------+ +//| Get the property value "DEAL_PRICE_OPEN" | +//+------------------------------------------------------------------+ +double CDealInfo::Price(void) const + { + return(HistoryDealGetDouble(m_ticket,DEAL_PRICE)); + } +//+------------------------------------------------------------------+ +//| Get the property value "DEAL_COMMISSION" | +//+------------------------------------------------------------------+ +double CDealInfo::Commission(void) const + { + return(HistoryDealGetDouble(m_ticket,DEAL_COMMISSION)); + } +//+------------------------------------------------------------------+ +//| Get the property value "DEAL_SWAP" | +//+------------------------------------------------------------------+ +double CDealInfo::Swap(void) const + { + return(HistoryDealGetDouble(m_ticket,DEAL_SWAP)); + } +//+------------------------------------------------------------------+ +//| Get the property value "DEAL_PROFIT" | +//+------------------------------------------------------------------+ +double CDealInfo::Profit(void) const + { + return(HistoryDealGetDouble(m_ticket,DEAL_PROFIT)); + } +//+------------------------------------------------------------------+ +//| Get the property value "DEAL_SYMBOL" | +//+------------------------------------------------------------------+ +string CDealInfo::Symbol(void) const + { + return(HistoryDealGetString(m_ticket,DEAL_SYMBOL)); + } +//+------------------------------------------------------------------+ +//| Get the property value "DEAL_COMMENT" | +//+------------------------------------------------------------------+ +string CDealInfo::Comment(void) const + { + return(HistoryDealGetString(m_ticket,DEAL_COMMENT)); + } +//+------------------------------------------------------------------+ +//| Get the property value "DEAL_EXTERNAL_ID" | +//+------------------------------------------------------------------+ +string CDealInfo::ExternalId(void) const + { + return(HistoryDealGetString(m_ticket,DEAL_EXTERNAL_ID)); + } +//+------------------------------------------------------------------+ +//| Access functions HistoryDealGetInteger(...) | +//+------------------------------------------------------------------+ +bool CDealInfo::InfoInteger(ENUM_DEAL_PROPERTY_INTEGER prop_id,long &var) const + { + return(HistoryDealGetInteger(m_ticket,prop_id,var)); + } +//+------------------------------------------------------------------+ +//| Access functions HistoryDealGetDouble(...) | +//+------------------------------------------------------------------+ +bool CDealInfo::InfoDouble(ENUM_DEAL_PROPERTY_DOUBLE prop_id,double &var) const + { + return(HistoryDealGetDouble(m_ticket,prop_id,var)); + } +//+------------------------------------------------------------------+ +//| Access functions HistoryDealGetString(...) | +//+------------------------------------------------------------------+ +bool CDealInfo::InfoString(ENUM_DEAL_PROPERTY_STRING prop_id,string &var) const + { + return(HistoryDealGetString(m_ticket,prop_id,var)); + } +//+------------------------------------------------------------------+ +//| Converths the type of a deal to text | +//+------------------------------------------------------------------+ +string CDealInfo::FormatAction(string &str,const uint action) const + { +//--- clean + str=""; +//--- see the type + switch(action) + { + case DEAL_TYPE_BUY : str="buy"; break; + case DEAL_TYPE_SELL : str="sell"; break; + case DEAL_TYPE_BALANCE : str="balance"; break; + case DEAL_TYPE_CREDIT : str="credit"; break; + case DEAL_TYPE_CHARGE : str="charge"; break; + case DEAL_TYPE_CORRECTION : str="correction"; break; + case DEAL_TYPE_BONUS : str="bonus"; break; + case DEAL_TYPE_COMMISSION : str="commission"; break; + case DEAL_TYPE_COMMISSION_DAILY : str="daily commission"; break; + case DEAL_TYPE_COMMISSION_MONTHLY : str="monthly commission"; break; + case DEAL_TYPE_COMMISSION_AGENT_DAILY : str="daily agent commission"; break; + case DEAL_TYPE_COMMISSION_AGENT_MONTHLY: str="monthly agent commission"; break; + case DEAL_TYPE_INTEREST : str="interest rate"; break; + case DEAL_TYPE_BUY_CANCELED : str="canceled buy"; break; + case DEAL_TYPE_SELL_CANCELED : str="canceled sell"; break; + default : str="unknown deal type "+(string)action; + } +//--- return the result + return(str); + } +//+------------------------------------------------------------------+ +//| Converts the deal direction to text | +//+------------------------------------------------------------------+ +string CDealInfo::FormatEntry(string &str,const uint entry) const + { +//--- clean + str=""; +//--- see the type + switch(entry) + { + case DEAL_ENTRY_IN : str="in"; break; + case DEAL_ENTRY_OUT : str="out"; break; + case DEAL_ENTRY_INOUT : str="in/out"; break; + case DEAL_ENTRY_OUT_BY: str="out by"; break; + default : str="unknown deal entry "+(string)entry; + } +//--- return the result + return(str); + } +//+------------------------------------------------------------------+ +//| Converts the deal parameters to text | +//+------------------------------------------------------------------+ +string CDealInfo::FormatDeal(string &str) const + { + string type; + CSymbolInfo symbol; +//--- set up + symbol.Name(Symbol()); + int digits=symbol.Digits(); +//--- form the description of the deal + switch(DealType()) + { + //--- Buy-Sell + case DEAL_TYPE_BUY : + case DEAL_TYPE_SELL : + str=StringFormat("#%I64u %s %s %s at %s", + Ticket(), + FormatAction(type,DealType()), + DoubleToString(Volume(),2), + Symbol(), + DoubleToString(Price(),digits)); + break; + + //--- balance operations + case DEAL_TYPE_BALANCE : + case DEAL_TYPE_CREDIT : + case DEAL_TYPE_CHARGE : + case DEAL_TYPE_CORRECTION: + case DEAL_TYPE_BONUS : + case DEAL_TYPE_COMMISSION: + case DEAL_TYPE_COMMISSION_DAILY: + case DEAL_TYPE_COMMISSION_MONTHLY: + case DEAL_TYPE_COMMISSION_AGENT_DAILY: + case DEAL_TYPE_COMMISSION_AGENT_MONTHLY: + case DEAL_TYPE_INTEREST: + str=StringFormat("#%I64u %s %s [%s]", + Ticket(), + FormatAction(type,DealType()), + DoubleToString(Profit(),2), + Comment()); + break; + + default: + str="unknown deal type "+(string)DealType(); + break; + } +//--- return the result + return(str); + } +//+------------------------------------------------------------------+ +//| Select a deal on the index | +//+------------------------------------------------------------------+ +bool CDealInfo::SelectByIndex(const int index) + { + ulong ticket=HistoryDealGetTicket(index); + if(ticket==0) + return(false); + Ticket(ticket); +//--- + return(true); + } +//+------------------------------------------------------------------+ diff --git a/Include/Trade/HistoryOrderInfo.mqh b/Include/Trade/HistoryOrderInfo.mqh new file mode 100644 index 0000000..663ecd8 --- /dev/null +++ b/Include/Trade/HistoryOrderInfo.mqh @@ -0,0 +1,443 @@ +//+------------------------------------------------------------------+ +//| HistoryOrderInfo.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include "SymbolInfo.mqh" +//+------------------------------------------------------------------+ +//| Class CHistoryOrderInfo. | +//| Appointment: Class for access to history order info. | +//| Derives from class CObject. | +//+------------------------------------------------------------------+ +class CHistoryOrderInfo : public CObject + { +protected: + ulong m_ticket; // ticket of history order +public: + CHistoryOrderInfo(void); + ~CHistoryOrderInfo(void); + //--- methods of access to protected data + void Ticket(const ulong ticket) { m_ticket=ticket; } + ulong Ticket(void) const { return(m_ticket); } + //--- fast access methods to the integer order propertyes + datetime TimeSetup(void) const; + ulong TimeSetupMsc(void) const; + datetime TimeDone(void) const; + ulong TimeDoneMsc(void) const; + ENUM_ORDER_TYPE OrderType(void) const; + string TypeDescription(void) const; + ENUM_ORDER_STATE State(void) const; + string StateDescription(void) const; + datetime TimeExpiration(void) const; + ENUM_ORDER_TYPE_FILLING TypeFilling(void) const; + string TypeFillingDescription(void) const; + ENUM_ORDER_TYPE_TIME TypeTime(void) const; + string TypeTimeDescription(void) const; + long Magic(void) const; + long PositionId(void) const; + long PositionById(void) const; + //--- fast access methods to the double order propertyes + double VolumeInitial(void) const; + double VolumeCurrent(void) const; + double PriceOpen(void) const; + double StopLoss(void) const; + double TakeProfit(void) const; + double PriceCurrent(void) const; + double PriceStopLimit(void) const; + //--- fast access methods to the string order propertyes + string Symbol(void) const; + string Comment(void) const; + string ExternalId(void) const; + //--- access methods to the API MQL5 functions + bool InfoInteger(const ENUM_ORDER_PROPERTY_INTEGER prop_id,long &var) const; + bool InfoDouble(const ENUM_ORDER_PROPERTY_DOUBLE prop_id,double &var) const; + bool InfoString(const ENUM_ORDER_PROPERTY_STRING prop_id,string &var) const; + //--- info methods + string FormatType(string &str,const uint type) const; + string FormatStatus(string &str,const uint status) const; + string FormatTypeFilling(string &str,const uint type) const; + string FormatTypeTime(string &str,const uint type) const; + string FormatOrder(string &str) const; + string FormatPrice(string &str,const double price_order,const double price_trigger,const uint digits) const; + //--- method for select history order + bool SelectByIndex(const int index); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CHistoryOrderInfo::CHistoryOrderInfo(void) : m_ticket(0) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CHistoryOrderInfo::~CHistoryOrderInfo(void) + { + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TIME_SETUP" | +//+------------------------------------------------------------------+ +datetime CHistoryOrderInfo::TimeSetup(void) const + { + return((datetime)HistoryOrderGetInteger(m_ticket,ORDER_TIME_SETUP)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TIME_SETUP_MSC" | +//+------------------------------------------------------------------+ +ulong CHistoryOrderInfo::TimeSetupMsc(void) const + { + return(HistoryOrderGetInteger(m_ticket,ORDER_TIME_SETUP_MSC)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TIME_DONE" | +//+------------------------------------------------------------------+ +datetime CHistoryOrderInfo::TimeDone(void) const + { + return((datetime)HistoryOrderGetInteger(m_ticket,ORDER_TIME_DONE)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TIME_DONE_MSC" | +//+------------------------------------------------------------------+ +ulong CHistoryOrderInfo::TimeDoneMsc(void) const + { + return(HistoryOrderGetInteger(m_ticket,ORDER_TIME_DONE_MSC)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TYPE" | +//+------------------------------------------------------------------+ +ENUM_ORDER_TYPE CHistoryOrderInfo::OrderType(void) const + { + return((ENUM_ORDER_TYPE)HistoryOrderGetInteger(m_ticket,ORDER_TYPE)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TYPE" as string | +//+------------------------------------------------------------------+ +string CHistoryOrderInfo::TypeDescription(void) const + { + string str; +//--- + return(FormatType(str,OrderType())); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_STATE" | +//+------------------------------------------------------------------+ +ENUM_ORDER_STATE CHistoryOrderInfo::State(void) const + { + return((ENUM_ORDER_STATE)HistoryOrderGetInteger(m_ticket,ORDER_STATE)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_STATE" as string | +//+------------------------------------------------------------------+ +string CHistoryOrderInfo::StateDescription(void) const + { + string str; +//--- + return(FormatStatus(str,State())); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TIME_EXPIRATION" | +//+------------------------------------------------------------------+ +datetime CHistoryOrderInfo::TimeExpiration(void) const + { + return((datetime)HistoryOrderGetInteger(m_ticket,ORDER_TIME_EXPIRATION)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TYPE_FILLING" | +//+------------------------------------------------------------------+ +ENUM_ORDER_TYPE_FILLING CHistoryOrderInfo::TypeFilling(void) const + { + return((ENUM_ORDER_TYPE_FILLING)HistoryOrderGetInteger(m_ticket,ORDER_TYPE_FILLING)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TYPE_FILLING" as string | +//+------------------------------------------------------------------+ +string CHistoryOrderInfo::TypeFillingDescription(void) const + { + string str; +//--- + return(FormatTypeFilling(str,TypeFilling())); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TYPE_TIME" | +//+------------------------------------------------------------------+ +ENUM_ORDER_TYPE_TIME CHistoryOrderInfo::TypeTime(void) const + { + return((ENUM_ORDER_TYPE_TIME)HistoryOrderGetInteger(m_ticket,ORDER_TYPE_TIME)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TYPE_TIME" as string | +//+------------------------------------------------------------------+ +string CHistoryOrderInfo::TypeTimeDescription(void) const + { + string str; +//--- + return(FormatTypeTime(str,TypeTime())); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_EXPERT" | +//+------------------------------------------------------------------+ +long CHistoryOrderInfo::Magic(void) const + { + return(HistoryOrderGetInteger(m_ticket,ORDER_MAGIC)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_POSITION_ID" | +//+------------------------------------------------------------------+ +long CHistoryOrderInfo::PositionId(void) const + { + return(HistoryOrderGetInteger(m_ticket,ORDER_POSITION_ID)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_POSITION_BY_ID" | +//+------------------------------------------------------------------+ +long CHistoryOrderInfo::PositionById(void) const + { + return(HistoryOrderGetInteger(m_ticket,ORDER_POSITION_BY_ID)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_VOLUME_INITIAL" | +//+------------------------------------------------------------------+ +double CHistoryOrderInfo::VolumeInitial(void) const + { + return(HistoryOrderGetDouble(m_ticket,ORDER_VOLUME_INITIAL)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_VOLUME_CURRENT" | +//+------------------------------------------------------------------+ +double CHistoryOrderInfo::VolumeCurrent(void) const + { + return(HistoryOrderGetDouble(m_ticket,ORDER_VOLUME_CURRENT)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_PRICE_OPEN" | +//+------------------------------------------------------------------+ +double CHistoryOrderInfo::PriceOpen(void) const + { + return(HistoryOrderGetDouble(m_ticket,ORDER_PRICE_OPEN)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_SL" | +//+------------------------------------------------------------------+ +double CHistoryOrderInfo::StopLoss(void) const + { + return(HistoryOrderGetDouble(m_ticket,ORDER_SL)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TP" | +//+------------------------------------------------------------------+ +double CHistoryOrderInfo::TakeProfit(void) const + { + return(HistoryOrderGetDouble(m_ticket,ORDER_TP)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_PRICE_CURRENT" | +//+------------------------------------------------------------------+ +double CHistoryOrderInfo::PriceCurrent(void) const + { + return(HistoryOrderGetDouble(m_ticket,ORDER_PRICE_CURRENT)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_PRICE_STOPLIMIT" | +//+------------------------------------------------------------------+ +double CHistoryOrderInfo::PriceStopLimit(void) const + { + return(HistoryOrderGetDouble(m_ticket,ORDER_PRICE_STOPLIMIT)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_SYMBOL" | +//+------------------------------------------------------------------+ +string CHistoryOrderInfo::Symbol(void) const + { + return(HistoryOrderGetString(m_ticket,ORDER_SYMBOL)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_COMMENT" | +//+------------------------------------------------------------------+ +string CHistoryOrderInfo::Comment(void) const + { + return(HistoryOrderGetString(m_ticket,ORDER_COMMENT)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_EXTERNAL_ID" | +//+------------------------------------------------------------------+ +string CHistoryOrderInfo::ExternalId(void) const + { + return(HistoryOrderGetString(m_ticket,ORDER_EXTERNAL_ID)); + } +//+------------------------------------------------------------------+ +//| Access functions OrderGetInteger(...) | +//+------------------------------------------------------------------+ +bool CHistoryOrderInfo::InfoInteger(const ENUM_ORDER_PROPERTY_INTEGER prop_id,long &var) const + { + return(HistoryOrderGetInteger(m_ticket,prop_id,var)); + } +//+------------------------------------------------------------------+ +//| Access functions OrderGetDouble(...) | +//+------------------------------------------------------------------+ +bool CHistoryOrderInfo::InfoDouble(const ENUM_ORDER_PROPERTY_DOUBLE prop_id,double &var) const + { + return(HistoryOrderGetDouble(m_ticket,prop_id,var)); + } +//+------------------------------------------------------------------+ +//| Access functions OrderGetString(...) | +//+------------------------------------------------------------------+ +bool CHistoryOrderInfo::InfoString(const ENUM_ORDER_PROPERTY_STRING prop_id,string &var) const + { + return(HistoryOrderGetString(m_ticket,prop_id,var)); + } +//+------------------------------------------------------------------+ +//| Converts the order type to text | +//+------------------------------------------------------------------+ +string CHistoryOrderInfo::FormatType(string &str,const uint type) const + { +//--- clean + str=""; +//--- see the type + switch(type) + { + case ORDER_TYPE_BUY : str="buy"; break; + case ORDER_TYPE_SELL : str="sell"; break; + case ORDER_TYPE_BUY_LIMIT : str="buy limit"; break; + case ORDER_TYPE_SELL_LIMIT : str="sell limit"; break; + case ORDER_TYPE_BUY_STOP : str="buy stop"; break; + case ORDER_TYPE_SELL_STOP : str="sell stop"; break; + case ORDER_TYPE_BUY_STOP_LIMIT : str="buy stop limit"; break; + case ORDER_TYPE_SELL_STOP_LIMIT: str="sell stop limit"; break; + case ORDER_TYPE_CLOSE_BY : str="close by"; break; + + default: + str="unknown order type "+(string)type; + break; + } +//--- return the result + return(str); + } +//+------------------------------------------------------------------+ +//| Converts the order status to text | +//+------------------------------------------------------------------+ +string CHistoryOrderInfo::FormatStatus(string &str,const uint status) const + { +//--- clean + str=""; +//--- see the type + switch(status) + { + case ORDER_STATE_STARTED : str="started"; break; + case ORDER_STATE_PLACED : str="placed"; break; + case ORDER_STATE_CANCELED: str="canceled"; break; + case ORDER_STATE_PARTIAL : str="partial"; break; + case ORDER_STATE_FILLED : str="filled"; break; + case ORDER_STATE_REJECTED: str="rejected"; break; + case ORDER_STATE_EXPIRED : str="expired"; break; + + default: + str="unknown order status "+(string)status; + break; + } +//--- return the result + return(str); + } +//+------------------------------------------------------------------+ +//| Converts the order filling type to text | +//+------------------------------------------------------------------+ +string CHistoryOrderInfo::FormatTypeFilling(string &str,const uint type) const + { +//--- clean + str=""; +//--- see the type + switch(type) + { + case ORDER_FILLING_RETURN: str="return remainder"; break; + case ORDER_FILLING_IOC : str="cancel remainder"; break; + case ORDER_FILLING_FOK : str="fill or kill"; break; + + default: + str="unknown type filling "+(string)type; + break; + } +//--- return the result + return(str); + } +//+------------------------------------------------------------------+ +//| Converts the type of order by expiration to text | +//+------------------------------------------------------------------+ +string CHistoryOrderInfo::FormatTypeTime(string &str,const uint type) const + { +//--- clean + str=""; +//--- see the type + switch(type) + { + case ORDER_TIME_GTC : str="gtc"; break; + case ORDER_TIME_DAY : str="day"; break; + case ORDER_TIME_SPECIFIED : str="specified"; break; + case ORDER_TIME_SPECIFIED_DAY: str="specified day"; break; + + default: + str="unknown type time "+(string)type; + break; + } +//--- return the result + return(str); + } +//+------------------------------------------------------------------+ +//| Converts the order parameters to text | +//+------------------------------------------------------------------+ +string CHistoryOrderInfo::FormatOrder(string &str) const + { + string type,price; + CSymbolInfo symbol; +//--- set up + symbol.Name(Symbol()); + int digits=symbol.Digits(); +//--- form the order description + str=StringFormat("#%I64u %s %s %s", + Ticket(), + FormatType(type,OrderType()), + DoubleToString(VolumeInitial(),2), + Symbol()); +//--- receive the price of the order + FormatPrice(price,PriceOpen(),PriceStopLimit(),digits); +//--- if there is price, write it + if(price!="") + { + str+=" at "; + str+=price; + } +//--- return the result + return(str); + } +//+------------------------------------------------------------------+ +//| Converts the order prices to text | +//+------------------------------------------------------------------+ +string CHistoryOrderInfo::FormatPrice(string &str,const double price_order,const double price_trigger,const uint digits) const + { + string price,trigger; +//--- clean + str=""; +//--- Is there its trigger price? + if(price_trigger) + { + price =DoubleToString(price_order,digits); + trigger=DoubleToString(price_trigger,digits); + str =StringFormat("%s (%s)",price,trigger); + } + else + str=DoubleToString(price_order,digits); +//--- return the result + return(str); + } +//+------------------------------------------------------------------+ +//| Select a history order on the index | +//+------------------------------------------------------------------+ +bool CHistoryOrderInfo::SelectByIndex(const int index) + { + ulong ticket=HistoryOrderGetTicket(index); + if(ticket==0) + return(false); + Ticket(ticket); +//--- + return(true); + } +//+------------------------------------------------------------------+ diff --git a/Include/Trade/OrderInfo.mqh b/Include/Trade/OrderInfo.mqh new file mode 100644 index 0000000..af845b2 --- /dev/null +++ b/Include/Trade/OrderInfo.mqh @@ -0,0 +1,518 @@ +//+------------------------------------------------------------------+ +//| OrderInfo.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include "SymbolInfo.mqh" +//+------------------------------------------------------------------+ +//| Class COrderInfo. | +//| Appointment: Class for access to order info. | +//| Derives from class CObject. | +//+------------------------------------------------------------------+ +class COrderInfo : public CObject + { +protected: + ulong m_ticket; + ENUM_ORDER_TYPE m_type; + ENUM_ORDER_STATE m_state; + datetime m_expiration; + double m_volume_curr; + double m_price_open; + double m_stop_loss; + double m_take_profit; + +public: + COrderInfo(void); + ~COrderInfo(void); + //--- methods of access to protected data + ulong Ticket(void) const { return(m_ticket); } + //--- fast access methods to the integer order propertyes + datetime TimeSetup(void) const; + ulong TimeSetupMsc(void) const; + datetime TimeDone(void) const; + ulong TimeDoneMsc(void) const; + ENUM_ORDER_TYPE OrderType(void) const; + string TypeDescription(void) const; + ENUM_ORDER_STATE State(void) const; + string StateDescription(void) const; + datetime TimeExpiration(void) const; + ENUM_ORDER_TYPE_FILLING TypeFilling(void) const; + string TypeFillingDescription(void) const; + ENUM_ORDER_TYPE_TIME TypeTime(void) const; + string TypeTimeDescription(void) const; + long Magic(void) const; + long PositionId(void) const; + long PositionById(void) const; + //--- fast access methods to the double order propertyes + double VolumeInitial(void) const; + double VolumeCurrent(void) const; + double PriceOpen(void) const; + double StopLoss(void) const; + double TakeProfit(void) const; + double PriceCurrent(void) const; + double PriceStopLimit(void) const; + //--- fast access methods to the string order propertyes + string Symbol(void) const; + string Comment(void) const; + string ExternalId(void) const; + //--- access methods to the API MQL5 functions + bool InfoInteger(const ENUM_ORDER_PROPERTY_INTEGER prop_id,long &var) const; + bool InfoDouble(const ENUM_ORDER_PROPERTY_DOUBLE prop_id,double &var) const; + bool InfoString(const ENUM_ORDER_PROPERTY_STRING prop_id,string &var) const; + //--- info methods + string FormatType(string &str,const uint type) const; + string FormatStatus(string &str,const uint status) const; + string FormatTypeFilling(string &str,const uint type) const; + string FormatTypeTime(string &str,const uint type) const; + string FormatOrder(string &str) const; + string FormatPrice(string &str,const double price_order,const double price_trigger,const uint digits) const; + //--- method for select order + bool Select(void); + bool Select(const ulong ticket); + bool SelectByIndex(const int index); + //--- addition methods + void StoreState(void); + bool CheckState(void); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +COrderInfo::COrderInfo(void) : m_ticket(ULONG_MAX), + m_type(WRONG_VALUE), + m_state(WRONG_VALUE), + m_expiration(0), + m_volume_curr(0.0), + m_price_open(0.0), + m_stop_loss(0.0), + m_take_profit(0.0) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +COrderInfo::~COrderInfo(void) + { + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TIME_SETUP" | +//+------------------------------------------------------------------+ +datetime COrderInfo::TimeSetup(void) const + { + return((datetime)OrderGetInteger(ORDER_TIME_SETUP)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TIME_SETUP_MSC" | +//+------------------------------------------------------------------+ +ulong COrderInfo::TimeSetupMsc(void) const + { + return(OrderGetInteger(ORDER_TIME_SETUP_MSC)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TIME_DONE" | +//+------------------------------------------------------------------+ +datetime COrderInfo::TimeDone(void) const + { + return((datetime)OrderGetInteger(ORDER_TIME_DONE)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TIME_DONE_MSC" | +//+------------------------------------------------------------------+ +ulong COrderInfo::TimeDoneMsc(void) const + { + return(OrderGetInteger(ORDER_TIME_DONE_MSC)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TYPE" | +//+------------------------------------------------------------------+ +ENUM_ORDER_TYPE COrderInfo::OrderType(void) const + { + return((ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TYPE" as string | +//+------------------------------------------------------------------+ +string COrderInfo::TypeDescription(void) const + { + string str; +//--- + return(FormatType(str,OrderType())); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_STATE" | +//+------------------------------------------------------------------+ +ENUM_ORDER_STATE COrderInfo::State(void) const + { + return((ENUM_ORDER_STATE)OrderGetInteger(ORDER_STATE)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_STATE" as string | +//+------------------------------------------------------------------+ +string COrderInfo::StateDescription(void) const + { + string str; +//--- + return(FormatStatus(str,State())); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TIME_EXPIRATION" | +//+------------------------------------------------------------------+ +datetime COrderInfo::TimeExpiration(void) const + { + return((datetime)OrderGetInteger(ORDER_TIME_EXPIRATION)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TYPE_FILLING" | +//+------------------------------------------------------------------+ +ENUM_ORDER_TYPE_FILLING COrderInfo::TypeFilling(void) const + { + return((ENUM_ORDER_TYPE_FILLING)OrderGetInteger(ORDER_TYPE_FILLING)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TYPE_FILLING" as string | +//+------------------------------------------------------------------+ +string COrderInfo::TypeFillingDescription(void) const + { + string str; +//--- + return(FormatTypeFilling(str,TypeFilling())); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TYPE_TIME" | +//+------------------------------------------------------------------+ +ENUM_ORDER_TYPE_TIME COrderInfo::TypeTime(void) const + { + return((ENUM_ORDER_TYPE_TIME)OrderGetInteger(ORDER_TYPE_TIME)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TYPE_TIME" as string | +//+------------------------------------------------------------------+ +string COrderInfo::TypeTimeDescription(void) const + { + string str; +//--- + return(FormatTypeTime(str,TypeFilling())); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_MAGIC" | +//+------------------------------------------------------------------+ +long COrderInfo::Magic(void) const + { + return(OrderGetInteger(ORDER_MAGIC)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_POSITION_ID" | +//+------------------------------------------------------------------+ +long COrderInfo::PositionId(void) const + { + return(OrderGetInteger(ORDER_POSITION_ID)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_POSITION_BY_ID" | +//+------------------------------------------------------------------+ +long COrderInfo::PositionById(void) const + { + return(OrderGetInteger(ORDER_POSITION_BY_ID)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_VOLUME_INITIAL" | +//+------------------------------------------------------------------+ +double COrderInfo::VolumeInitial(void) const + { + return(OrderGetDouble(ORDER_VOLUME_INITIAL)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_VOLUME_CURRENT" | +//+------------------------------------------------------------------+ +double COrderInfo::VolumeCurrent(void) const + { + return(OrderGetDouble(ORDER_VOLUME_CURRENT)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_PRICE_OPEN" | +//+------------------------------------------------------------------+ +double COrderInfo::PriceOpen(void) const + { + return(OrderGetDouble(ORDER_PRICE_OPEN)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_SL" | +//+------------------------------------------------------------------+ +double COrderInfo::StopLoss(void) const + { + return(OrderGetDouble(ORDER_SL)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_TP" | +//+------------------------------------------------------------------+ +double COrderInfo::TakeProfit(void) const + { + return(OrderGetDouble(ORDER_TP)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_PRICE_CURRENT" | +//+------------------------------------------------------------------+ +double COrderInfo::PriceCurrent(void) const + { + return(OrderGetDouble(ORDER_PRICE_CURRENT)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_PRICE_STOPLIMIT" | +//+------------------------------------------------------------------+ +double COrderInfo::PriceStopLimit(void) const + { + return(OrderGetDouble(ORDER_PRICE_STOPLIMIT)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_SYMBOL" | +//+------------------------------------------------------------------+ +string COrderInfo::Symbol(void) const + { + return(OrderGetString(ORDER_SYMBOL)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_COMMENT" | +//+------------------------------------------------------------------+ +string COrderInfo::Comment(void) const + { + return(OrderGetString(ORDER_COMMENT)); + } +//+------------------------------------------------------------------+ +//| Get the property value "ORDER_EXTERNAL_ID" | +//+------------------------------------------------------------------+ +string COrderInfo::ExternalId(void) const + { + return(OrderGetString(ORDER_EXTERNAL_ID)); + } +//+------------------------------------------------------------------+ +//| Access functions OrderGetInteger(...) | +//+------------------------------------------------------------------+ +bool COrderInfo::InfoInteger(const ENUM_ORDER_PROPERTY_INTEGER prop_id,long &var) const + { + return(OrderGetInteger(prop_id,var)); + } +//+------------------------------------------------------------------+ +//| Access functions OrderGetDouble(...) | +//+------------------------------------------------------------------+ +bool COrderInfo::InfoDouble(const ENUM_ORDER_PROPERTY_DOUBLE prop_id,double &var) const + { + return(OrderGetDouble(prop_id,var)); + } +//+------------------------------------------------------------------+ +//| Access functions OrderGetString(...) | +//+------------------------------------------------------------------+ +bool COrderInfo::InfoString(const ENUM_ORDER_PROPERTY_STRING prop_id,string &var) const + { + return(OrderGetString(prop_id,var)); + } +//+------------------------------------------------------------------+ +//| Converts the order type to text | +//+------------------------------------------------------------------+ +string COrderInfo::FormatType(string &str,const uint type) const + { +//--- clean + str=""; +//--- see the type + switch(type) + { + case ORDER_TYPE_BUY : str="buy"; break; + case ORDER_TYPE_SELL : str="sell"; break; + case ORDER_TYPE_BUY_LIMIT : str="buy limit"; break; + case ORDER_TYPE_SELL_LIMIT : str="sell limit"; break; + case ORDER_TYPE_BUY_STOP : str="buy stop"; break; + case ORDER_TYPE_SELL_STOP : str="sell stop"; break; + case ORDER_TYPE_BUY_STOP_LIMIT : str="buy stop limit"; break; + case ORDER_TYPE_SELL_STOP_LIMIT: str="sell stop limit"; break; + case ORDER_TYPE_CLOSE_BY : str="close by"; break; + + default: + str="unknown order type "+(string)type; + break; + } +//--- return the result + return(str); + } +//+------------------------------------------------------------------+ +//| Converts the order status to text | +//+------------------------------------------------------------------+ +string COrderInfo::FormatStatus(string &str,const uint status) const + { +//--- clean + str=""; +//--- see the type + switch(status) + { + case ORDER_STATE_STARTED : str="started"; break; + case ORDER_STATE_PLACED : str="placed"; break; + case ORDER_STATE_CANCELED : str="canceled"; break; + case ORDER_STATE_PARTIAL : str="partial"; break; + case ORDER_STATE_FILLED : str="filled"; break; + case ORDER_STATE_REJECTED : str="rejected"; break; + case ORDER_STATE_EXPIRED : str="expired"; break; + case ORDER_STATE_REQUEST_ADD : str="request adding"; break; + case ORDER_STATE_REQUEST_MODIFY: str="request modifying"; break; + case ORDER_STATE_REQUEST_CANCEL: str="request cancelling"; break; + + default: + str="unknown order status "+(string)status; + break; + } +//--- return the result + return(str); + } +//+------------------------------------------------------------------+ +//| Converts the order filling type to text | +//+------------------------------------------------------------------+ +string COrderInfo::FormatTypeFilling(string &str,const uint type) const + { +//--- clean + str=""; +//--- see the type + switch(type) + { + case ORDER_FILLING_RETURN: str="return remainder"; break; + case ORDER_FILLING_IOC : str="cancel remainder"; break; + case ORDER_FILLING_FOK : str="fill or kill"; break; + + default: + str="unknown type filling "+(string)type; + break; + } +//--- return the result + return(str); + } +//+------------------------------------------------------------------+ +//| Converts the type of order by expiration to text | +//+------------------------------------------------------------------+ +string COrderInfo::FormatTypeTime(string &str,const uint type) const + { +//--- clean + str=""; +//--- see the type + switch(type) + { + case ORDER_TIME_GTC : str="gtc"; break; + case ORDER_TIME_DAY : str="day"; break; + case ORDER_TIME_SPECIFIED : str="specified"; break; + case ORDER_TIME_SPECIFIED_DAY: str="specified day"; break; + + default: + str="unknown type time "+(string)type; + break; + } +//--- return the result + return(str); + } +//+------------------------------------------------------------------+ +//| Converts the order parameters to text | +//+------------------------------------------------------------------+ +string COrderInfo::FormatOrder(string &str) const + { + string type,price; + CSymbolInfo symbol; +//--- set up + symbol.Name(Symbol()); + int digits=symbol.Digits(); +//--- form the order description + str=StringFormat("#%I64u %s %s %s", + Ticket(), + FormatType(type,OrderType()), + DoubleToString(VolumeInitial(),2), + Symbol()); +//--- receive the price of the order + FormatPrice(price,PriceOpen(),PriceStopLimit(),digits); +//--- if there is price, write it + if(price!="") + { + str+=" at "; + str+=price; + } +//--- return the result + return(str); + } +//+------------------------------------------------------------------+ +//| Converts the order prices to text | +//+------------------------------------------------------------------+ +string COrderInfo::FormatPrice(string &str,const double price_order,const double price_trigger,const uint digits) const + { + string price,trigger; +//--- clean + str=""; +//--- Is there its trigger price? + if(price_trigger) + { + price =DoubleToString(price_order,digits); + trigger=DoubleToString(price_trigger,digits); + str =StringFormat("%s (%s)",price,trigger); + } + else + str=DoubleToString(price_order,digits); +//--- return the result + return(str); + } +//+------------------------------------------------------------------+ +//| Selecting an order to access | +//+------------------------------------------------------------------+ +bool COrderInfo::Select(void) + { + return(OrderSelect(m_ticket)); + } +//+------------------------------------------------------------------+ +//| Selecting an order to access | +//+------------------------------------------------------------------+ +bool COrderInfo::Select(const ulong ticket) + { + if(OrderSelect(ticket)) + { + m_ticket=ticket; + return(true); + } + m_ticket=ULONG_MAX; +//--- + return(false); + } +//+------------------------------------------------------------------+ +//| Select an order on the index | +//+------------------------------------------------------------------+ +bool COrderInfo::SelectByIndex(const int index) + { + ulong ticket=OrderGetTicket(index); + if(ticket==0) + { + m_ticket=ULONG_MAX; + return(false); + } + m_ticket=ticket; +//--- + return(true); + } +//+------------------------------------------------------------------+ +//| Stored order's current state | +//+------------------------------------------------------------------+ +void COrderInfo::StoreState(void) + { + m_type =OrderType(); + m_state =State(); + m_expiration =TimeExpiration(); + m_volume_curr=VolumeCurrent(); + m_price_open =PriceOpen(); + m_stop_loss =StopLoss(); + m_take_profit=TakeProfit(); + } +//+------------------------------------------------------------------+ +//| Check order change | +//+------------------------------------------------------------------+ +bool COrderInfo::CheckState(void) + { + if(m_type==OrderType() && + m_state==State() && + m_expiration ==TimeExpiration() && + m_volume_curr==VolumeCurrent() && + m_price_open==PriceOpen() && + m_stop_loss==StopLoss() && + m_take_profit==TakeProfit()) + return(false); +//--- + return(true); + } +//+------------------------------------------------------------------+ diff --git a/Include/Trade/PositionInfo.mqh b/Include/Trade/PositionInfo.mqh new file mode 100644 index 0000000..52a40c1 --- /dev/null +++ b/Include/Trade/PositionInfo.mqh @@ -0,0 +1,374 @@ +//+------------------------------------------------------------------+ +//| PositionInfo.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include "SymbolInfo.mqh" +//+------------------------------------------------------------------+ +//| Class CPositionInfo. | +//| Appointment: Class for access to position info. | +//| Derives from class CObject. | +//+------------------------------------------------------------------+ +class CPositionInfo : public CObject + { +protected: + ENUM_POSITION_TYPE m_type; + double m_volume; + double m_price; + double m_stop_loss; + double m_take_profit; + +public: + CPositionInfo(void); + ~CPositionInfo(void); + //--- fast access methods to the integer position propertyes + ulong Ticket(void) const; + datetime Time(void) const; + ulong TimeMsc(void) const; + datetime TimeUpdate(void) const; + ulong TimeUpdateMsc(void) const; + ENUM_POSITION_TYPE PositionType(void) const; + string TypeDescription(void) const; + long Magic(void) const; + long Identifier(void) const; + //--- fast access methods to the double position propertyes + double Volume(void) const; + double PriceOpen(void) const; + double StopLoss(void) const; + double TakeProfit(void) const; + double PriceCurrent(void) const; + double Commission(void) const; + double Swap(void) const; + double Profit(void) const; + //--- fast access methods to the string position propertyes + string Symbol(void) const; + string Comment(void) const; + //--- access methods to the API MQL5 functions + bool InfoInteger(const ENUM_POSITION_PROPERTY_INTEGER prop_id,long &var) const; + bool InfoDouble(const ENUM_POSITION_PROPERTY_DOUBLE prop_id,double &var) const; + bool InfoString(const ENUM_POSITION_PROPERTY_STRING prop_id,string &var) const; + //--- info methods + string FormatType(string &str,const uint type) const; + string FormatPosition(string &str) const; + //--- methods for select position + bool Select(const string symbol); + bool SelectByMagic(const string symbol,const ulong magic); + bool SelectByTicket(const ulong ticket); + bool SelectByIndex(const int index); + //--- + void StoreState(void); + bool CheckState(void); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CPositionInfo::CPositionInfo(void) : m_type(WRONG_VALUE), + m_volume(0.0), + m_price(0.0), + m_stop_loss(0.0), + m_take_profit(0.0) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CPositionInfo::~CPositionInfo(void) + { + } +//+------------------------------------------------------------------+ +//| Get the property value "POSITION_TICKET" | +//+------------------------------------------------------------------+ +ulong CPositionInfo::Ticket(void) const + { + return((ulong)PositionGetInteger(POSITION_TICKET)); + } +//+------------------------------------------------------------------+ +//| Get the property value "POSITION_TIME" | +//+------------------------------------------------------------------+ +datetime CPositionInfo::Time(void) const + { + return((datetime)PositionGetInteger(POSITION_TIME)); + } +//+------------------------------------------------------------------+ +//| Get the property value "POSITION_TIME_MSC" | +//+------------------------------------------------------------------+ +ulong CPositionInfo::TimeMsc(void) const + { + return((ulong)PositionGetInteger(POSITION_TIME_MSC)); + } +//+------------------------------------------------------------------+ +//| Get the property value "POSITION_TIME_UPDATE" | +//+------------------------------------------------------------------+ +datetime CPositionInfo::TimeUpdate(void) const + { + return((datetime)PositionGetInteger(POSITION_TIME_UPDATE)); + } +//+------------------------------------------------------------------+ +//| Get the property value "POSITION_TIME_UPDATE_MSC" | +//+------------------------------------------------------------------+ +ulong CPositionInfo::TimeUpdateMsc(void) const + { + return((ulong)PositionGetInteger(POSITION_TIME_UPDATE_MSC)); + } +//+------------------------------------------------------------------+ +//| Get the property value "POSITION_TYPE" | +//+------------------------------------------------------------------+ +ENUM_POSITION_TYPE CPositionInfo::PositionType(void) const + { + return((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE)); + } +//+------------------------------------------------------------------+ +//| Get the property value "POSITION_TYPE" as string | +//+------------------------------------------------------------------+ +string CPositionInfo::TypeDescription(void) const + { + string str; +//--- + return(FormatType(str,PositionType())); + } +//+------------------------------------------------------------------+ +//| Get the property value "POSITION_MAGIC" | +//+------------------------------------------------------------------+ +long CPositionInfo::Magic(void) const + { + return(PositionGetInteger(POSITION_MAGIC)); + } +//+------------------------------------------------------------------+ +//| Get the property value "POSITION_IDENTIFIER" | +//+------------------------------------------------------------------+ +long CPositionInfo::Identifier(void) const + { + return(PositionGetInteger(POSITION_IDENTIFIER)); + } +//+------------------------------------------------------------------+ +//| Get the property value "POSITION_VOLUME" | +//+------------------------------------------------------------------+ +double CPositionInfo::Volume(void) const + { + return(PositionGetDouble(POSITION_VOLUME)); + } +//+------------------------------------------------------------------+ +//| Get the property value "POSITION_PRICE_OPEN" | +//+------------------------------------------------------------------+ +double CPositionInfo::PriceOpen(void) const + { + return(PositionGetDouble(POSITION_PRICE_OPEN)); + } +//+------------------------------------------------------------------+ +//| Get the property value "POSITION_SL" | +//+------------------------------------------------------------------+ +double CPositionInfo::StopLoss(void) const + { + return(PositionGetDouble(POSITION_SL)); + } +//+------------------------------------------------------------------+ +//| Get the property value "POSITION_TP" | +//+------------------------------------------------------------------+ +double CPositionInfo::TakeProfit(void) const + { + return(PositionGetDouble(POSITION_TP)); + } +//+------------------------------------------------------------------+ +//| Get the property value "POSITION_PRICE_CURRENT" | +//+------------------------------------------------------------------+ +double CPositionInfo::PriceCurrent(void) const + { + return(PositionGetDouble(POSITION_PRICE_CURRENT)); + } +//+------------------------------------------------------------------+ +//| Get the property value "POSITION_COMMISSION" | +//+------------------------------------------------------------------+ +double CPositionInfo::Commission(void) const + { + return(PositionGetDouble(POSITION_COMMISSION)); + } +//+------------------------------------------------------------------+ +//| Get the property value "POSITION_SWAP" | +//+------------------------------------------------------------------+ +double CPositionInfo::Swap(void) const + { + return(PositionGetDouble(POSITION_SWAP)); + } +//+------------------------------------------------------------------+ +//| Get the property value "POSITION_PROFIT" | +//+------------------------------------------------------------------+ +double CPositionInfo::Profit(void) const + { + return(PositionGetDouble(POSITION_PROFIT)); + } +//+------------------------------------------------------------------+ +//| Get the property value "POSITION_SYMBOL" | +//+------------------------------------------------------------------+ +string CPositionInfo::Symbol(void) const + { + return(PositionGetString(POSITION_SYMBOL)); + } +//+------------------------------------------------------------------+ +//| Get the property value "POSITION_COMMENT" | +//+------------------------------------------------------------------+ +string CPositionInfo::Comment(void) const + { + return(PositionGetString(POSITION_COMMENT)); + } +//+------------------------------------------------------------------+ +//| Access functions PositionGetInteger(...) | +//+------------------------------------------------------------------+ +bool CPositionInfo::InfoInteger(const ENUM_POSITION_PROPERTY_INTEGER prop_id,long &var) const + { + return(PositionGetInteger(prop_id,var)); + } +//+------------------------------------------------------------------+ +//| Access functions PositionGetDouble(...) | +//+------------------------------------------------------------------+ +bool CPositionInfo::InfoDouble(const ENUM_POSITION_PROPERTY_DOUBLE prop_id,double &var) const + { + return(PositionGetDouble(prop_id,var)); + } +//+------------------------------------------------------------------+ +//| Access functions PositionGetString(...) | +//+------------------------------------------------------------------+ +bool CPositionInfo::InfoString(const ENUM_POSITION_PROPERTY_STRING prop_id,string &var) const + { + return(PositionGetString(prop_id,var)); + } +//+------------------------------------------------------------------+ +//| Converts the position type to text | +//+------------------------------------------------------------------+ +string CPositionInfo::FormatType(string &str,const uint type) const + { +//--- clean + str=""; +//--- see the type + switch(type) + { + case POSITION_TYPE_BUY : str="buy"; break; + case POSITION_TYPE_SELL: str="sell"; break; + default : str="unknown position type "+(string)type; + } +//--- return the result + return(str); + } +//+------------------------------------------------------------------+ +//| Converts the position parameters to text | +//+------------------------------------------------------------------+ +string CPositionInfo::FormatPosition(string &str) const + { + string tmp,type; + CSymbolInfo symbol; + ENUM_ACCOUNT_MARGIN_MODE margin_mode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE); +//--- set up + symbol.Name(Symbol()); + int digits=symbol.Digits(); +//--- form the position description + if(margin_mode==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) + str=StringFormat("#%I64u %s %s %s %s", + Ticket(), + FormatType(type,PositionType()), + DoubleToString(Volume(),2), + Symbol(), + DoubleToString(PriceOpen(),digits+3)); + else + str=StringFormat("%s %s %s %s", + FormatType(type,PositionType()), + DoubleToString(Volume(),2), + Symbol(), + DoubleToString(PriceOpen(),digits+3)); +//--- add stops if there are any + double sl=StopLoss(); + double tp=TakeProfit(); + if(sl!=0.0) + { + tmp=StringFormat(" sl: %s",DoubleToString(sl,digits)); + str+=tmp; + } + if(tp!=0.0) + { + tmp=StringFormat(" tp: %s",DoubleToString(tp,digits)); + str+=tmp; + } +//--- return the result + return(str); + } +//+------------------------------------------------------------------+ +//| Access functions PositionSelect(...) | +//+------------------------------------------------------------------+ +bool CPositionInfo::Select(const string symbol) + { + return(PositionSelect(symbol)); + } +//+------------------------------------------------------------------+ +//| Access functions PositionSelect(...) | +//+------------------------------------------------------------------+ +bool CPositionInfo::SelectByMagic(const string symbol,const ulong magic) + { + bool res=false; + uint total=PositionsTotal(); +//--- + for(uint i=0; i +//+------------------------------------------------------------------+ +//| Class CSymbolInfo. | +//| Appointment: Class for access to symbol info. | +//| Derives from class CObject. | +//+------------------------------------------------------------------+ +class CSymbolInfo : public CObject + { +protected: + string m_name; // symbol name + MqlTick m_tick; // structure of tick; + double m_point; // symbol point + double m_tick_value; // symbol tick value + double m_tick_value_profit; // symbol tick value profit + double m_tick_value_loss; // symbol tick value loss + double m_tick_size; // symbol tick size + double m_contract_size; // symbol contract size + double m_lots_min; // symbol lots min + double m_lots_max; // symbol lots max + double m_lots_step; // symbol lots step + double m_lots_limit; // symbol lots limit + double m_swap_long; // symbol swap long + double m_swap_short; // symbol swap short + int m_digits; // symbol digits + int m_order_mode; // symbol valid orders + ENUM_SYMBOL_TRADE_EXECUTION m_trade_execution; // symbol trade execution + ENUM_SYMBOL_CALC_MODE m_trade_calcmode; // symbol trade calcmode + ENUM_SYMBOL_TRADE_MODE m_trade_mode; // symbol trade mode + ENUM_SYMBOL_SWAP_MODE m_swap_mode; // symbol swap mode + ENUM_DAY_OF_WEEK m_swap3; // symbol swap3 + double m_margin_initial; // symbol margin initial + double m_margin_maintenance; // symbol margin maintenance + double m_margin_long; // symbol margin long position + double m_margin_short; // symbol margin short position + double m_margin_limit; // symbol margin limit order + double m_margin_stop; // symbol margin stop order + double m_margin_stoplimit; // symbol margin stoplimit order + int m_trade_time_flags; // symbol trade time flags + int m_trade_fill_flags; // symbol trade fill flags + +public: + CSymbolInfo(void); + ~CSymbolInfo(void); + //--- methods of access to protected data + string Name(void) const { return(m_name); } + bool Name(const string name); + bool Refresh(void); + bool RefreshRates(void); + //--- fast access methods to the integer symbol propertyes + bool Select(void) const; + bool Select(const bool select); + bool IsSynchronized(void) const; + //--- volumes + ulong Volume(void) const { return(m_tick.volume); } + ulong VolumeHigh(void) const; + ulong VolumeLow(void) const; + //--- miscellaneous + datetime Time(void) const { return(m_tick.time); } + int Spread(void) const; + bool SpreadFloat(void) const; + int TicksBookDepth(void) const; + //--- trade levels + int StopsLevel(void) const; + int FreezeLevel(void) const; + //--- fast access methods to the double symbol propertyes + //--- bid parameters + double Bid(void) const { return(m_tick.bid); } + double BidHigh(void) const; + double BidLow(void) const; + //--- ask parameters + double Ask(void) const { return(m_tick.ask); } + double AskHigh(void) const; + double AskLow(void) const; + //--- last parameters + double Last(void) const { return(m_tick.last); } + double LastHigh(void) const; + double LastLow(void) const; + //--- fast access methods to the mix symbol propertyes + int OrderMode(void) const { return(m_order_mode); } + //--- terms of trade + ENUM_SYMBOL_CALC_MODE TradeCalcMode(void) const { return(m_trade_calcmode); } + string TradeCalcModeDescription(void) const; + ENUM_SYMBOL_TRADE_MODE TradeMode(void) const { return(m_trade_mode); } + string TradeModeDescription(void) const; + //--- execution terms of trade + ENUM_SYMBOL_TRADE_EXECUTION TradeExecution(void) const { return(m_trade_execution); } + string TradeExecutionDescription(void) const; + //--- swap terms of trade + ENUM_SYMBOL_SWAP_MODE SwapMode(void) const { return(m_swap_mode); } + string SwapModeDescription(void) const; + ENUM_DAY_OF_WEEK SwapRollover3days(void) const { return(m_swap3); } + string SwapRollover3daysDescription(void) const; + //--- dates for futures + datetime StartTime(void) const; + datetime ExpirationTime(void) const; + //--- margin parameters + double MarginInitial(void) const { return(m_margin_initial); } + double MarginMaintenance(void) const { return(m_margin_maintenance); } + double MarginLong(void) const { return(m_margin_long); } + double MarginShort(void) const { return(m_margin_short); } + double MarginLimit(void) const { return(m_margin_limit); } + double MarginStop(void) const { return(m_margin_stop); } + double MarginStopLimit(void) const { return(m_margin_stoplimit); } + //--- trade flags parameters + int TradeTimeFlags(void) const { return(m_trade_time_flags); } + int TradeFillFlags(void) const { return(m_trade_fill_flags); } + //--- tick parameters + int Digits(void) const { return(m_digits); } + double Point(void) const { return(m_point); } + double TickValue(void) const { return(m_tick_value); } + double TickValueProfit(void) const { return(m_tick_value_profit); } + double TickValueLoss(void) const { return(m_tick_value_loss); } + double TickSize(void) const { return(m_tick_size); } + //--- lots parameters + double ContractSize(void) const { return(m_contract_size); } + double LotsMin(void) const { return(m_lots_min); } + double LotsMax(void) const { return(m_lots_max); } + double LotsStep(void) const { return(m_lots_step); } + double LotsLimit(void) const { return(m_lots_limit); } + //--- swaps + double SwapLong(void) const { return(m_swap_long); } + double SwapShort(void) const { return(m_swap_short); } + //--- fast access methods to the string symbol propertyes + string CurrencyBase(void) const; + string CurrencyProfit(void) const; + string CurrencyMargin(void) const; + string Bank(void) const; + string Description(void) const; + string Path(void) const; + //--- session information + long SessionDeals(void) const; + long SessionBuyOrders(void) const; + long SessionSellOrders(void) const; + double SessionTurnover(void) const; + double SessionInterest(void) const; + double SessionBuyOrdersVolume(void) const; + double SessionSellOrdersVolume(void) const; + double SessionOpen(void) const; + double SessionClose(void) const; + double SessionAW(void) const; + double SessionPriceSettlement(void) const; + double SessionPriceLimitMin(void) const; + double SessionPriceLimitMax(void) const; + //--- access methods to the API MQL5 functions + bool InfoInteger(const ENUM_SYMBOL_INFO_INTEGER prop_id,long &var) const; + bool InfoDouble(const ENUM_SYMBOL_INFO_DOUBLE prop_id,double &var) const; + bool InfoString(const ENUM_SYMBOL_INFO_STRING prop_id,string &var) const; + //--- service methods + double NormalizePrice(const double price) const; + bool CheckMarketWatch(void); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CSymbolInfo::CSymbolInfo(void) : m_name(""), + m_point(0.0), + m_tick_value(0.0), + m_tick_value_profit(0.0), + m_tick_value_loss(0.0), + m_tick_size(0.0), + m_contract_size(0.0), + m_lots_min(0.0), + m_lots_max(0.0), + m_lots_step(0.0), + m_swap_long(0.0), + m_swap_short(0.0), + m_digits(0), + m_order_mode(0), + m_trade_execution(0), + m_trade_calcmode(0), + m_trade_mode(0), + m_swap_mode(0), + m_swap3(0), + m_margin_initial(0.0), + m_margin_maintenance(0.0), + m_margin_long(0.0), + m_margin_short(0.0), + m_margin_limit(0.0), + m_margin_stop(0.0), + m_margin_stoplimit(0.0), + m_trade_time_flags(0), + m_trade_fill_flags(0) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CSymbolInfo::~CSymbolInfo(void) + { + } +//+------------------------------------------------------------------+ +//| Set name | +//+------------------------------------------------------------------+ +bool CSymbolInfo::Name(const string name) + { + m_name=name; +//--- + if(!CheckMarketWatch()) + return(false); +//--- + if(!Refresh()) + { + m_name=""; + Print(__FUNCTION__+": invalid data of symbol '"+name+"'"); + return(false); + } +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Refresh cached data | +//+------------------------------------------------------------------+ +bool CSymbolInfo::Refresh(void) + { + long tmp=0; +//--- + if(!SymbolInfoDouble(m_name,SYMBOL_POINT,m_point)) + return(false); + if(!SymbolInfoDouble(m_name,SYMBOL_TRADE_TICK_VALUE,m_tick_value)) + return(false); + if(!SymbolInfoDouble(m_name,SYMBOL_TRADE_TICK_VALUE_PROFIT,m_tick_value_profit)) + return(false); + if(!SymbolInfoDouble(m_name,SYMBOL_TRADE_TICK_VALUE_LOSS,m_tick_value_loss)) + return(false); + if(!SymbolInfoDouble(m_name,SYMBOL_TRADE_TICK_SIZE,m_tick_size)) + return(false); + if(!SymbolInfoDouble(m_name,SYMBOL_TRADE_CONTRACT_SIZE,m_contract_size)) + return(false); + if(!SymbolInfoDouble(m_name,SYMBOL_VOLUME_MIN,m_lots_min)) + return(false); + if(!SymbolInfoDouble(m_name,SYMBOL_VOLUME_MAX,m_lots_max)) + return(false); + if(!SymbolInfoDouble(m_name,SYMBOL_VOLUME_STEP,m_lots_step)) + return(false); + if(!SymbolInfoDouble(m_name,SYMBOL_VOLUME_LIMIT,m_lots_limit)) + return(false); + if(!SymbolInfoDouble(m_name,SYMBOL_SWAP_LONG,m_swap_long)) + return(false); + if(!SymbolInfoDouble(m_name,SYMBOL_SWAP_SHORT,m_swap_short)) + return(false); + if(!SymbolInfoInteger(m_name,SYMBOL_DIGITS,tmp)) + return(false); + m_digits=(int)tmp; + if(!SymbolInfoInteger(m_name,SYMBOL_ORDER_MODE,tmp)) + return(false); + m_order_mode=(int)tmp; + if(!SymbolInfoInteger(m_name,SYMBOL_TRADE_EXEMODE,tmp)) + return(false); + m_trade_execution=(ENUM_SYMBOL_TRADE_EXECUTION)tmp; + if(!SymbolInfoInteger(m_name,SYMBOL_TRADE_CALC_MODE,tmp)) + return(false); + m_trade_calcmode=(ENUM_SYMBOL_CALC_MODE)tmp; + if(!SymbolInfoInteger(m_name,SYMBOL_TRADE_MODE,tmp)) + return(false); + m_trade_mode=(ENUM_SYMBOL_TRADE_MODE)tmp; + if(!SymbolInfoInteger(m_name,SYMBOL_SWAP_MODE,tmp)) + return(false); + m_swap_mode=(ENUM_SYMBOL_SWAP_MODE)tmp; + if(!SymbolInfoInteger(m_name,SYMBOL_SWAP_ROLLOVER3DAYS,tmp)) + return(false); + m_swap3=(ENUM_DAY_OF_WEEK)tmp; + if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_INITIAL,m_margin_initial)) + return(false); + if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_MAINTENANCE,m_margin_maintenance)) + return(false); + if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_LONG,m_margin_long)) + return(false); + if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_SHORT,m_margin_short)) + return(false); + if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_LIMIT,m_margin_limit)) + return(false); + if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_STOP,m_margin_stop)) + return(false); + if(!SymbolInfoDouble(m_name,SYMBOL_MARGIN_STOPLIMIT,m_margin_stoplimit)) + return(false); + if(!SymbolInfoInteger(m_name,SYMBOL_EXPIRATION_MODE,tmp)) + return(false); + m_trade_time_flags=(int)tmp; + if(!SymbolInfoInteger(m_name,SYMBOL_FILLING_MODE,tmp)) + return(false); + m_trade_fill_flags=(int)tmp; +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Refresh cached data | +//+------------------------------------------------------------------+ +bool CSymbolInfo::RefreshRates(void) + { + return(SymbolInfoTick(m_name,m_tick)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_SELECT" | +//+------------------------------------------------------------------+ +bool CSymbolInfo::Select(void) const + { + return((bool)SymbolInfoInteger(m_name,SYMBOL_SELECT)); + } +//+------------------------------------------------------------------+ +//| Set the property value "SYMBOL_SELECT" | +//+------------------------------------------------------------------+ +bool CSymbolInfo::Select(const bool select) + { + return(SymbolSelect(m_name,select)); + } +//+------------------------------------------------------------------+ +//| Check synchronize symbol | +//+------------------------------------------------------------------+ +bool CSymbolInfo::IsSynchronized(void) const + { + return(SymbolIsSynchronized(m_name)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_VOLUMEHIGH" | +//+------------------------------------------------------------------+ +ulong CSymbolInfo::VolumeHigh(void) const + { + return(SymbolInfoInteger(m_name,SYMBOL_VOLUMEHIGH)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_VOLUMELOW" | +//+------------------------------------------------------------------+ +ulong CSymbolInfo::VolumeLow(void) const + { + return(SymbolInfoInteger(m_name,SYMBOL_VOLUMELOW)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_SPREAD" | +//+------------------------------------------------------------------+ +int CSymbolInfo::Spread(void) const + { + return((int)SymbolInfoInteger(m_name,SYMBOL_SPREAD)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_SPREAD_FLOAT" | +//+------------------------------------------------------------------+ +bool CSymbolInfo::SpreadFloat(void) const + { + return((bool)SymbolInfoInteger(m_name,SYMBOL_SPREAD_FLOAT)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_TICKS_BOOKDEPTH" | +//+------------------------------------------------------------------+ +int CSymbolInfo::TicksBookDepth(void) const + { + return((int)SymbolInfoInteger(m_name,SYMBOL_TICKS_BOOKDEPTH)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_TRADE_STOPS_LEVEL" | +//+------------------------------------------------------------------+ +int CSymbolInfo::StopsLevel(void) const + { + return((int)SymbolInfoInteger(m_name,SYMBOL_TRADE_STOPS_LEVEL)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_TRADE_FREEZE_LEVEL" | +//+------------------------------------------------------------------+ +int CSymbolInfo::FreezeLevel(void) const + { + return((int)SymbolInfoInteger(m_name,SYMBOL_TRADE_FREEZE_LEVEL)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_BIDHIGH" | +//+------------------------------------------------------------------+ +double CSymbolInfo::BidHigh(void) const + { + return(SymbolInfoDouble(m_name,SYMBOL_BIDHIGH)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_BIDLOW" | +//+------------------------------------------------------------------+ +double CSymbolInfo::BidLow(void) const + { + return(SymbolInfoDouble(m_name,SYMBOL_BIDLOW)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_ASKHIGH" | +//+------------------------------------------------------------------+ +double CSymbolInfo::AskHigh(void) const + { + return(SymbolInfoDouble(m_name,SYMBOL_ASKHIGH)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_ASKLOW" | +//+------------------------------------------------------------------+ +double CSymbolInfo::AskLow(void) const + { + return(SymbolInfoDouble(m_name,SYMBOL_ASKLOW)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_LASTHIGH" | +//+------------------------------------------------------------------+ +double CSymbolInfo::LastHigh(void) const + { + return(SymbolInfoDouble(m_name,SYMBOL_LASTHIGH)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_LASTLOW" | +//+------------------------------------------------------------------+ +double CSymbolInfo::LastLow(void) const + { + return(SymbolInfoDouble(m_name,SYMBOL_LASTLOW)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_TRADE_CALC_MODE" as string | +//+------------------------------------------------------------------+ +string CSymbolInfo::TradeCalcModeDescription(void) const + { + string str; +//--- + switch(m_trade_calcmode) + { + case SYMBOL_CALC_MODE_FOREX: + str="Calculation of profit and margin for Forex"; + break; + case SYMBOL_CALC_MODE_CFD: + str="Calculation of collateral and earnings for CFD"; + break; + case SYMBOL_CALC_MODE_FUTURES: + str="Calculation of collateral and profits for futures"; + break; + case SYMBOL_CALC_MODE_CFDINDEX: + str="Calculation of collateral and earnings for CFD on indices"; + break; + case SYMBOL_CALC_MODE_CFDLEVERAGE: + str="Calculation of collateral and earnings for the CFD when trading with leverage"; + break; + case SYMBOL_CALC_MODE_EXCH_STOCKS: + str="Calculation for exchange stocks"; + break; + case SYMBOL_CALC_MODE_EXCH_FUTURES: + str="Calculation for exchange futures"; + break; + case SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS: + str="Calculation for FORTS futures"; + break; + default: + str="Unknown calculation mode"; + } +//--- result + return(str); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_TRADE_MODE" as string | +//+------------------------------------------------------------------+ +string CSymbolInfo::TradeModeDescription(void) const + { + string str; +//--- + switch(m_trade_mode) + { + case SYMBOL_TRADE_MODE_DISABLED : str="Disabled"; break; + case SYMBOL_TRADE_MODE_LONGONLY : str="Long only"; break; + case SYMBOL_TRADE_MODE_SHORTONLY: str="Short only"; break; + case SYMBOL_TRADE_MODE_CLOSEONLY: str="Close only"; break; + case SYMBOL_TRADE_MODE_FULL : str="Full access"; break; + default : str="Unknown trade mode"; + } +//--- result + return(str); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_TRADE_EXEMODE" as string | +//+------------------------------------------------------------------+ +string CSymbolInfo::TradeExecutionDescription(void) const + { + string str; +//--- + switch(m_trade_execution) + { + case SYMBOL_TRADE_EXECUTION_REQUEST : str="Trading on request"; break; + case SYMBOL_TRADE_EXECUTION_INSTANT : str="Trading on live streaming prices"; break; + case SYMBOL_TRADE_EXECUTION_MARKET : str="Execution of orders on the market"; break; + case SYMBOL_TRADE_EXECUTION_EXCHANGE: str="Exchange execution"; break; + default: str="Unknown trade execution"; + } +//--- result + return(str); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_SWAP_MODE" as string | +//+------------------------------------------------------------------+ +string CSymbolInfo::SwapModeDescription(void) const + { + string str; +//--- + switch(m_swap_mode) + { + case SYMBOL_SWAP_MODE_DISABLED: + str="No swaps"; + break; + case SYMBOL_SWAP_MODE_POINTS: + str="Swaps are calculated in points"; + break; + case SYMBOL_SWAP_MODE_CURRENCY_SYMBOL: + str="Swaps are calculated in base currency"; + break; + case SYMBOL_SWAP_MODE_CURRENCY_MARGIN: + str="Swaps are calculated in margin currency"; + break; + case SYMBOL_SWAP_MODE_CURRENCY_DEPOSIT: + str="Swaps are calculated in deposit currency"; + break; + case SYMBOL_SWAP_MODE_INTEREST_CURRENT: + str="Swaps are calculated as annual interest using the current price"; + break; + case SYMBOL_SWAP_MODE_INTEREST_OPEN: + str="Swaps are calculated as annual interest using the open price"; + break; + case SYMBOL_SWAP_MODE_REOPEN_CURRENT: + str="Swaps are charged by reopening positions at the close price"; + break; + case SYMBOL_SWAP_MODE_REOPEN_BID: + str="Swaps are charged by reopening positions at the Bid price"; + break; + default: + str="Unknown swap mode"; + } +//--- result + return(str); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_SWAP_ROLLOVER3DAYS" as string | +//+------------------------------------------------------------------+ +string CSymbolInfo::SwapRollover3daysDescription(void) const + { + string str; +//--- + switch(m_swap3) + { + case SUNDAY : str="Sunday"; break; + case MONDAY : str="Monday"; break; + case TUESDAY : str="Tuesday"; break; + case WEDNESDAY: str="Wednesday"; break; + case THURSDAY : str="Thursday"; break; + case FRIDAY : str="Friday"; break; + case SATURDAY : str="Saturday"; break; + default : str="Unknown"; + } +//--- result + return(str); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_START_TIME" | +//+------------------------------------------------------------------+ +datetime CSymbolInfo::StartTime(void) const + { + return((datetime)SymbolInfoInteger(m_name,SYMBOL_START_TIME)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_EXPIRATION_TIME" | +//+------------------------------------------------------------------+ +datetime CSymbolInfo::ExpirationTime(void) const + { + return((datetime)SymbolInfoInteger(m_name,SYMBOL_EXPIRATION_TIME)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_CURRENCY_BASE" | +//+------------------------------------------------------------------+ +string CSymbolInfo::CurrencyBase(void) const + { + return(SymbolInfoString(m_name,SYMBOL_CURRENCY_BASE)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_CURRENCY_PROFIT" | +//+------------------------------------------------------------------+ +string CSymbolInfo::CurrencyProfit(void) const + { + return(SymbolInfoString(m_name,SYMBOL_CURRENCY_PROFIT)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_CURRENCY_MARGIN" | +//+------------------------------------------------------------------+ +string CSymbolInfo::CurrencyMargin(void) const + { + return(SymbolInfoString(m_name,SYMBOL_CURRENCY_MARGIN)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_BANK" | +//+------------------------------------------------------------------+ +string CSymbolInfo::Bank(void) const + { + return(SymbolInfoString(m_name,SYMBOL_BANK)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_DESCRIPTION" | +//+------------------------------------------------------------------+ +string CSymbolInfo::Description(void) const + { + return(SymbolInfoString(m_name,SYMBOL_DESCRIPTION)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_PATH" | +//+------------------------------------------------------------------+ +string CSymbolInfo::Path(void) const + { + return(SymbolInfoString(m_name,SYMBOL_PATH)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_SESSION_DEALS" | +//+------------------------------------------------------------------+ +long CSymbolInfo::SessionDeals(void) const + { + return(SymbolInfoInteger(m_name,SYMBOL_SESSION_DEALS)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_SESSION_BUY_ORDERS" | +//+------------------------------------------------------------------+ +long CSymbolInfo::SessionBuyOrders(void) const + { + return(SymbolInfoInteger(m_name,SYMBOL_SESSION_BUY_ORDERS)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_SESSION_SELL_ORDERS" | +//+------------------------------------------------------------------+ +long CSymbolInfo::SessionSellOrders(void) const + { + return(SymbolInfoInteger(m_name,SYMBOL_SESSION_SELL_ORDERS)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_SESSION_TURNOVER" | +//+------------------------------------------------------------------+ +double CSymbolInfo::SessionTurnover(void) const + { + return(SymbolInfoDouble(m_name,SYMBOL_SESSION_TURNOVER)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_SESSION_INTEREST" | +//+------------------------------------------------------------------+ +double CSymbolInfo::SessionInterest(void) const + { + return(SymbolInfoDouble(m_name,SYMBOL_SESSION_INTEREST)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_SESSION_BUY_ORDERS_VOLUME" | +//+------------------------------------------------------------------+ +double CSymbolInfo::SessionBuyOrdersVolume(void) const + { + return(SymbolInfoDouble(m_name,SYMBOL_SESSION_BUY_ORDERS_VOLUME)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_SESSION_SELL_ORDERS_VOLUME" | +//+------------------------------------------------------------------+ +double CSymbolInfo::SessionSellOrdersVolume(void) const + { + return(SymbolInfoDouble(m_name,SYMBOL_SESSION_SELL_ORDERS_VOLUME)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_SESSION_OPEN" | +//+------------------------------------------------------------------+ +double CSymbolInfo::SessionOpen(void) const + { + return(SymbolInfoDouble(m_name,SYMBOL_SESSION_OPEN)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_SESSION_CLOSE" | +//+------------------------------------------------------------------+ +double CSymbolInfo::SessionClose(void) const + { + return(SymbolInfoDouble(m_name,SYMBOL_SESSION_CLOSE)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_SESSION_AW" | +//+------------------------------------------------------------------+ +double CSymbolInfo::SessionAW(void) const + { + return(SymbolInfoDouble(m_name,SYMBOL_SESSION_AW)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_SESSION_PRICE_SETTLEMENT" | +//+------------------------------------------------------------------+ +double CSymbolInfo::SessionPriceSettlement(void) const + { + return(SymbolInfoDouble(m_name,SYMBOL_SESSION_PRICE_SETTLEMENT)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_SESSION_PRICE_LIMIT_MIN" | +//+------------------------------------------------------------------+ +double CSymbolInfo::SessionPriceLimitMin(void) const + { + return(SymbolInfoDouble(m_name,SYMBOL_SESSION_PRICE_LIMIT_MIN)); + } +//+------------------------------------------------------------------+ +//| Get the property value "SYMBOL_SESSION_PRICE_LIMIT_MAX" | +//+------------------------------------------------------------------+ +double CSymbolInfo::SessionPriceLimitMax(void) const + { + return(SymbolInfoDouble(m_name,SYMBOL_SESSION_PRICE_LIMIT_MAX)); + } +//+------------------------------------------------------------------+ +//| Access functions SymbolInfoInteger(...) | +//+------------------------------------------------------------------+ +bool CSymbolInfo::InfoInteger(const ENUM_SYMBOL_INFO_INTEGER prop_id,long &var) const + { + return(SymbolInfoInteger(m_name,prop_id,var)); + } +//+------------------------------------------------------------------+ +//| Access functions SymbolInfoDouble(...) | +//+------------------------------------------------------------------+ +bool CSymbolInfo::InfoDouble(const ENUM_SYMBOL_INFO_DOUBLE prop_id,double &var) const + { + return(SymbolInfoDouble(m_name,prop_id,var)); + } +//+------------------------------------------------------------------+ +//| Access functions SymbolInfoString(...) | +//+------------------------------------------------------------------+ +bool CSymbolInfo::InfoString(const ENUM_SYMBOL_INFO_STRING prop_id,string &var) const + { + return(SymbolInfoString(m_name,prop_id,var)); + } +//+------------------------------------------------------------------+ +//| Normalize price | +//+------------------------------------------------------------------+ +double CSymbolInfo::NormalizePrice(const double price) const + { + if(m_tick_size!=0) + return(NormalizeDouble(MathRound(price/m_tick_size)*m_tick_size,m_digits)); +//--- + return(NormalizeDouble(price,m_digits)); + } +//+------------------------------------------------------------------+ +//| Checks if symbol is selected in the MarketWatch | +//| and adds symbol to the MarketWatch, if necessary | +//+------------------------------------------------------------------+ +bool CSymbolInfo::CheckMarketWatch(void) + { +//--- check if symbol is selected in the MarketWatch + if(!Select()) + { + if(GetLastError()==ERR_MARKET_UNKNOWN_SYMBOL) + { + printf(__FUNCTION__+": Unknown symbol '%s'",m_name); + return(false); + } + if(!Select(true)) + { + printf(__FUNCTION__+": Error adding symbol %d",GetLastError()); + return(false); + } + } +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ diff --git a/Include/Trade/TerminalInfo.mqh b/Include/Trade/TerminalInfo.mqh new file mode 100644 index 0000000..3c24618 --- /dev/null +++ b/Include/Trade/TerminalInfo.mqh @@ -0,0 +1,225 @@ +//+------------------------------------------------------------------+ +//| TerminalInfo.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include +//+------------------------------------------------------------------+ +//| Class CTerminalInfo. | +//| Appointment: Class for access to terminal info. | +//| Derives from class CObject. | +//+------------------------------------------------------------------+ +class CTerminalInfo : public CObject + { +public: + CTerminalInfo(void); + ~CTerminalInfo(void); + //--- fast access methods to the integer terminal propertyes + int Build(void) const; + bool IsConnected(void) const; + bool IsDLLsAllowed(void) const; + bool IsTradeAllowed(void) const; + bool IsEmailEnabled(void) const; + bool IsFtpEnabled(void) const; + int MaxBars(void) const; + int CodePage(void) const; + int CPUCores(void) const; + int MemoryPhysical(void) const; + int MemoryTotal(void) const; + int MemoryAvailable(void) const; + int MemoryUsed(void) const; + bool IsX64(void) const; + int OpenCLSupport(void) const; + int DiskSpace(void) const; + //--- fast access methods to the string terminal propertyes + string Language(void) const; + string Name(void) const; + string Company(void) const; + string Path(void) const; + string DataPath(void) const; + string CommonDataPath(void) const; + //--- access methods to the API MQL5 functions + long InfoInteger(const ENUM_TERMINAL_INFO_INTEGER prop_id) const; + string InfoString(const ENUM_TERMINAL_INFO_STRING prop_id) const; + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CTerminalInfo::CTerminalInfo(void) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTerminalInfo::~CTerminalInfo(void) + { + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_BUILD" | +//+------------------------------------------------------------------+ +int CTerminalInfo::Build(void) const + { + return((int)TerminalInfoInteger(TERMINAL_BUILD)); + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_CONNECTED" | +//+------------------------------------------------------------------+ +bool CTerminalInfo::IsConnected(void) const + { + return((bool)TerminalInfoInteger(TERMINAL_CONNECTED)); + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_DLLS_ALLOWED" | +//+------------------------------------------------------------------+ +bool CTerminalInfo::IsDLLsAllowed(void) const + { + return((bool)TerminalInfoInteger(TERMINAL_DLLS_ALLOWED)); + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_TRADE_ALLOWED" | +//+------------------------------------------------------------------+ +bool CTerminalInfo::IsTradeAllowed(void) const + { + return((bool)TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)); + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_EMAIL_ENABLED" | +//+------------------------------------------------------------------+ +bool CTerminalInfo::IsEmailEnabled(void) const + { + return((bool)TerminalInfoInteger(TERMINAL_EMAIL_ENABLED)); + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_FTP_ENABLED" | +//+------------------------------------------------------------------+ +bool CTerminalInfo::IsFtpEnabled(void) const + { + return((bool)TerminalInfoInteger(TERMINAL_FTP_ENABLED)); + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_MAXBARS" | +//+------------------------------------------------------------------+ +int CTerminalInfo::MaxBars(void) const + { + return((int)TerminalInfoInteger(TERMINAL_MAXBARS)); + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_CODEPAGE" | +//+------------------------------------------------------------------+ +int CTerminalInfo::CodePage(void) const + { + return((int)TerminalInfoInteger(TERMINAL_CODEPAGE)); + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_CPU_CORES" | +//+------------------------------------------------------------------+ +int CTerminalInfo::CPUCores(void) const + { + return((int)TerminalInfoInteger(TERMINAL_CPU_CORES)); + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_MEMORY_PHYSICAL" | +//+------------------------------------------------------------------+ +int CTerminalInfo::MemoryPhysical(void) const + { + return((int)TerminalInfoInteger(TERMINAL_MEMORY_PHYSICAL)); + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_MEMORY_TOTAL" | +//+------------------------------------------------------------------+ +int CTerminalInfo::MemoryTotal(void) const + { + return((int)TerminalInfoInteger(TERMINAL_MEMORY_TOTAL)); + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_MEMORY_AVAILABLE" | +//+------------------------------------------------------------------+ +int CTerminalInfo::MemoryAvailable(void) const + { + return((int)TerminalInfoInteger(TERMINAL_MEMORY_AVAILABLE)); + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_MEMORY_USED" | +//+------------------------------------------------------------------+ +int CTerminalInfo::MemoryUsed(void) const + { + return((int)TerminalInfoInteger(TERMINAL_MEMORY_USED)); + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_X64" | +//+------------------------------------------------------------------+ +bool CTerminalInfo::IsX64(void) const + { + return((bool)TerminalInfoInteger(TERMINAL_X64)); + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_OPENCL_SUPPORT" | +//+------------------------------------------------------------------+ +int CTerminalInfo::OpenCLSupport(void) const + { + return((int)TerminalInfoInteger(TERMINAL_OPENCL_SUPPORT)); + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_DISK_SPACE" | +//+------------------------------------------------------------------+ +int CTerminalInfo::DiskSpace(void) const + { + return((int)TerminalInfoInteger(TERMINAL_DISK_SPACE)); + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_LANGUAGE" | +//+------------------------------------------------------------------+ +string CTerminalInfo::Language(void) const + { + return(TerminalInfoString(TERMINAL_LANGUAGE)); + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_NAME" | +//+------------------------------------------------------------------+ +string CTerminalInfo::Name(void) const + { + return(TerminalInfoString(TERMINAL_NAME)); + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_COMPANY" | +//+------------------------------------------------------------------+ +string CTerminalInfo::Company(void) const + { + return(TerminalInfoString(TERMINAL_COMPANY)); + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_PATH" | +//+------------------------------------------------------------------+ +string CTerminalInfo::Path(void) const + { + return(TerminalInfoString(TERMINAL_PATH)); + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_DATA_PATH" | +//+------------------------------------------------------------------+ +string CTerminalInfo::DataPath(void) const + { + return(TerminalInfoString(TERMINAL_DATA_PATH)); + } +//+------------------------------------------------------------------+ +//| Get the property value "TERMINAL_COMMONDATA_PATH" | +//+------------------------------------------------------------------+ +string CTerminalInfo::CommonDataPath(void) const + { + return(TerminalInfoString(TERMINAL_COMMONDATA_PATH)); + } +//+------------------------------------------------------------------+ +//| Access functions AccountInfoInteger(...) | +//+------------------------------------------------------------------+ +long CTerminalInfo::InfoInteger(const ENUM_TERMINAL_INFO_INTEGER prop_id) const + { + return(TerminalInfoInteger(prop_id)); + } +//+------------------------------------------------------------------+ +//| Access functions AccountInfoString(...) | +//+------------------------------------------------------------------+ +string CTerminalInfo::InfoString(const ENUM_TERMINAL_INFO_STRING prop_id) const + { + return(TerminalInfoString(prop_id)); + } +//+------------------------------------------------------------------+ diff --git a/Include/Trade/Trade.mqh b/Include/Trade/Trade.mqh new file mode 100644 index 0000000..4a4cf6e --- /dev/null +++ b/Include/Trade/Trade.mqh @@ -0,0 +1,1661 @@ +//+------------------------------------------------------------------+ +//| Trade.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include "SymbolInfo.mqh" +#include "OrderInfo.mqh" +#include "HistoryOrderInfo.mqh" +#include "PositionInfo.mqh" +#include "DealInfo.mqh" +//+------------------------------------------------------------------+ +//| enumerations | +//+------------------------------------------------------------------+ +enum ENUM_LOG_LEVELS + { + LOG_LEVEL_NO =0, + LOG_LEVEL_ERRORS=1, + LOG_LEVEL_ALL =2 + }; +//+------------------------------------------------------------------+ +//| Class CTrade. | +//| Appointment: Class trade operations. | +//| Derives from class CObject. | +//+------------------------------------------------------------------+ +class CTrade : public CObject + { +protected: + MqlTradeRequest m_request; // request data + MqlTradeResult m_result; // result data + MqlTradeCheckResult m_check_result; // result check data + bool m_async_mode; // trade mode + ulong m_magic; // expert magic number + ulong m_deviation; // deviation default + ENUM_ORDER_TYPE_FILLING m_type_filling; + ENUM_ACCOUNT_MARGIN_MODE m_margin_mode; + //--- + ENUM_LOG_LEVELS m_log_level; + +public: + CTrade(void); + ~CTrade(void); + //--- methods of access to protected data + void LogLevel(const ENUM_LOG_LEVELS log_level) { m_log_level=log_level; } + void Request(MqlTradeRequest &request) const; + ENUM_TRADE_REQUEST_ACTIONS RequestAction(void) const { return(m_request.action); } + string RequestActionDescription(void) const; + ulong RequestMagic(void) const { return(m_request.magic); } + ulong RequestOrder(void) const { return(m_request.order); } + ulong RequestPosition(void) const { return(m_request.position); } + ulong RequestPositionBy(void) const { return(m_request.position_by); } + string RequestSymbol(void) const { return(m_request.symbol); } + double RequestVolume(void) const { return(m_request.volume); } + double RequestPrice(void) const { return(m_request.price); } + double RequestStopLimit(void) const { return(m_request.stoplimit); } + double RequestSL(void) const { return(m_request.sl); } + double RequestTP(void) const { return(m_request.tp); } + ulong RequestDeviation(void) const { return(m_request.deviation); } + ENUM_ORDER_TYPE RequestType(void) const { return(m_request.type); } + string RequestTypeDescription(void) const; + ENUM_ORDER_TYPE_FILLING RequestTypeFilling(void) const { return(m_request.type_filling); } + string RequestTypeFillingDescription(void) const; + ENUM_ORDER_TYPE_TIME RequestTypeTime(void) const { return(m_request.type_time); } + string RequestTypeTimeDescription(void) const; + datetime RequestExpiration(void) const { return(m_request.expiration); } + string RequestComment(void) const { return(m_request.comment); } + //--- + void Result(MqlTradeResult &result) const; + uint ResultRetcode(void) const { return(m_result.retcode); } + string ResultRetcodeDescription(void) const; + int ResultRetcodeExternal(void) const { return(m_result.retcode_external); } + ulong ResultDeal(void) const { return(m_result.deal); } + ulong ResultOrder(void) const { return(m_result.order); } + double ResultVolume(void) const { return(m_result.volume); } + double ResultPrice(void) const { return(m_result.price); } + double ResultBid(void) const { return(m_result.bid); } + double ResultAsk(void) const { return(m_result.ask); } + string ResultComment(void) const { return(m_result.comment); } + //--- + void CheckResult(MqlTradeCheckResult &check_result) const; + uint CheckResultRetcode(void) const { return(m_check_result.retcode); } + string CheckResultRetcodeDescription(void) const; + double CheckResultBalance(void) const { return(m_check_result.balance); } + double CheckResultEquity(void) const { return(m_check_result.equity); } + double CheckResultProfit(void) const { return(m_check_result.profit); } + double CheckResultMargin(void) const { return(m_check_result.margin); } + double CheckResultMarginFree(void) const { return(m_check_result.margin_free); } + double CheckResultMarginLevel(void) const { return(m_check_result.margin_level); } + string CheckResultComment(void) const { return(m_check_result.comment); } + //--- trade methods + void SetAsyncMode(const bool mode) { m_async_mode=mode; } + void SetExpertMagicNumber(const ulong magic) { m_magic=magic; } + void SetDeviationInPoints(const ulong deviation) { m_deviation=deviation; } + void SetTypeFilling(const ENUM_ORDER_TYPE_FILLING filling) { m_type_filling=filling; } + bool SetTypeFillingBySymbol(const string symbol); + void SetMarginMode(void) { m_margin_mode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE); } + //--- methods for working with positions + bool PositionOpen(const string symbol,const ENUM_ORDER_TYPE order_type,const double volume, + const double price,const double sl,const double tp,const string comment=""); + bool PositionModify(const string symbol,const double sl,const double tp); + bool PositionModify(const ulong ticket,const double sl,const double tp); + bool PositionClose(const string symbol,const ulong deviation=ULONG_MAX); + bool PositionClose(const ulong ticket,const ulong deviation=ULONG_MAX); + bool PositionCloseBy(const ulong ticket,const ulong ticket_by); + bool PositionClosePartial(const string symbol,const double volume,const ulong deviation=ULONG_MAX); + bool PositionClosePartial(const ulong ticket,const double volume,const ulong deviation=ULONG_MAX); + //--- methods for working with pending orders + bool OrderOpen(const string symbol,const ENUM_ORDER_TYPE order_type,const double volume, + const double limit_price,const double price,const double sl,const double tp, + ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC,const datetime expiration=0, + const string comment=""); + bool OrderModify(const ulong ticket,const double price,const double sl,const double tp, + const ENUM_ORDER_TYPE_TIME type_time,const datetime expiration,const double stoplimit=0.0); + bool OrderDelete(const ulong ticket); + //--- additions methods + bool Buy(const double volume,const string symbol=NULL,double price=0.0,const double sl=0.0,const double tp=0.0,const string comment=""); + bool Sell(const double volume,const string symbol=NULL,double price=0.0,const double sl=0.0,const double tp=0.0,const string comment=""); + bool BuyLimit(const double volume,const double price,const string symbol=NULL,const double sl=0.0,const double tp=0.0, + const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC,const datetime expiration=0,const string comment=""); + bool BuyStop(const double volume,const double price,const string symbol=NULL,const double sl=0.0,const double tp=0.0, + const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC,const datetime expiration=0,const string comment=""); + bool SellLimit(const double volume,const double price,const string symbol=NULL,const double sl=0.0,const double tp=0.0, + const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC,const datetime expiration=0,const string comment=""); + bool SellStop(const double volume,const double price,const string symbol=NULL,const double sl=0.0,const double tp=0.0, + const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC,const datetime expiration=0,const string comment=""); + //--- method check + virtual double CheckVolume(const string symbol,double volume,double price,ENUM_ORDER_TYPE order_type); + virtual bool OrderCheck(const MqlTradeRequest &request,MqlTradeCheckResult &check_result); + virtual bool OrderSend(const MqlTradeRequest &request,MqlTradeResult &result); + //--- info methods + void PrintRequest(void) const; + void PrintResult(void) const; + //--- positions + string FormatPositionType(string &str,const uint type) const; + //--- orders + string FormatOrderType(string &str,const uint type) const; + string FormatOrderStatus(string &str,const uint status) const; + string FormatOrderTypeFilling(string &str,const uint type) const; + string FormatOrderTypeTime(string &str,const uint type) const; + string FormatOrderPrice(string &str,const double price_order,const double price_trigger,const uint digits) const; + //--- trade request + string FormatRequest(string &str,const MqlTradeRequest &request) const; + string FormatRequestResult(string &str,const MqlTradeRequest &request,const MqlTradeResult &result) const; + +protected: + bool FillingCheck(const string symbol); + bool ExpirationCheck(const string symbol); + bool OrderTypeCheck(const string symbol); + void ClearStructures(void); + bool IsStopped(const string function); + bool IsHedging(void) const { return(m_margin_mode==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING); } + //--- position select depending on netting or hedging + bool SelectPosition(const string symbol); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CTrade::CTrade(void) : m_async_mode(false), + m_magic(0), + m_deviation(10), + m_type_filling(ORDER_FILLING_FOK), + m_log_level(LOG_LEVEL_ERRORS) + + { + SetMarginMode(); +//--- initialize protected data + ClearStructures(); +//--- check programm mode + if(MQL5InfoInteger(MQL5_OPTIMIZATION)) + m_log_level=LOG_LEVEL_NO; + if(MQL5InfoInteger(MQL5_TESTING)) + m_log_level=LOG_LEVEL_ALL; + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTrade::~CTrade(void) + { + } +//+------------------------------------------------------------------+ +//| Get the request structure | +//+------------------------------------------------------------------+ +void CTrade::Request(MqlTradeRequest &request) const + { + request.action =m_request.action; + request.magic =m_request.magic; + request.order =m_request.order; + request.symbol =m_request.symbol; + request.volume =m_request.volume; + request.price =m_request.price; + request.stoplimit =m_request.stoplimit; + request.sl =m_request.sl; + request.tp =m_request.tp; + request.deviation =m_request.deviation; + request.type =m_request.type; + request.type_filling=m_request.type_filling; + request.type_time =m_request.type_time; + request.expiration =m_request.expiration; + request.comment =m_request.comment; + request.position =m_request.position; + request.position_by =m_request.position_by; + } +//+------------------------------------------------------------------+ +//| Get the trade action as string | +//+------------------------------------------------------------------+ +string CTrade::RequestActionDescription(void) const + { + string str; +//--- + FormatRequest(str,m_request); +//--- + return(str); + } +//+------------------------------------------------------------------+ +//| Get the order type as string | +//+------------------------------------------------------------------+ +string CTrade::RequestTypeDescription(void) const + { + string str; +//--- + FormatOrderType(str,(uint)m_request.order); +//--- + return(str); + } +//+------------------------------------------------------------------+ +//| Get the order type filling as string | +//+------------------------------------------------------------------+ +string CTrade::RequestTypeFillingDescription(void) const + { + string str; +//--- + FormatOrderTypeFilling(str,m_request.type_filling); +//--- + return(str); + } +//+------------------------------------------------------------------+ +//| Get the order type time as string | +//+------------------------------------------------------------------+ +string CTrade::RequestTypeTimeDescription(void) const + { + string str; +//--- + FormatOrderTypeTime(str,m_request.type_time); +//--- + return(str); + } +//+------------------------------------------------------------------+ +//| Get the result structure | +//+------------------------------------------------------------------+ +void CTrade::Result(MqlTradeResult &result) const + { + result.retcode =m_result.retcode; + result.deal =m_result.deal; + result.order =m_result.order; + result.volume =m_result.volume; + result.price =m_result.price; + result.bid =m_result.bid; + result.ask =m_result.ask; + result.comment =m_result.comment; + result.request_id=m_result.request_id; + result.retcode_external=m_result.retcode_external; + } +//+------------------------------------------------------------------+ +//| Get the retcode value as string | +//+------------------------------------------------------------------+ +string CTrade::ResultRetcodeDescription(void) const + { + string str; +//--- + FormatRequestResult(str,m_request,m_result); +//--- + return(str); + } +//+------------------------------------------------------------------+ +//| Get the check result structure | +//+------------------------------------------------------------------+ +void CTrade::CheckResult(MqlTradeCheckResult &check_result) const + { +//--- copy structure + check_result.retcode =m_check_result.retcode; + check_result.balance =m_check_result.balance; + check_result.equity =m_check_result.equity; + check_result.profit =m_check_result.profit; + check_result.margin =m_check_result.margin; + check_result.margin_free =m_check_result.margin_free; + check_result.margin_level=m_check_result.margin_level; + check_result.comment =m_check_result.comment; + } +//+------------------------------------------------------------------+ +//| Get the check retcode value as string | +//+------------------------------------------------------------------+ +string CTrade::CheckResultRetcodeDescription(void) const + { + string str; + MqlTradeResult result; +//--- + result.retcode=m_check_result.retcode; + FormatRequestResult(str,m_request,result); +//--- + return(str); + } +//+------------------------------------------------------------------+ +//| Open position | +//+------------------------------------------------------------------+ +bool CTrade::PositionOpen(const string symbol,const ENUM_ORDER_TYPE order_type,const double volume, + const double price,const double sl,const double tp,const string comment) + { +//--- check stopped + if(IsStopped(__FUNCTION__)) + return(false); +//--- clean + ClearStructures(); +//--- check + if(order_type!=ORDER_TYPE_BUY && order_type!=ORDER_TYPE_SELL) + { + m_result.retcode=TRADE_RETCODE_INVALID; + m_result.comment="Invalid order type"; + return(false); + } +//--- setting request + m_request.action =TRADE_ACTION_DEAL; + m_request.symbol =symbol; + m_request.magic =m_magic; + m_request.volume =volume; + m_request.type =order_type; + m_request.price =price; + m_request.sl =sl; + m_request.tp =tp; + m_request.deviation=m_deviation; +//--- check order type + if(!OrderTypeCheck(symbol)) + return(false); +//--- check filling + if(!FillingCheck(symbol)) + return(false); + m_request.comment=comment; +//--- action and return the result + return(OrderSend(m_request,m_result)); + } +//+------------------------------------------------------------------+ +//| Modify specified opened position | +//+------------------------------------------------------------------+ +bool CTrade::PositionModify(const string symbol,const double sl,const double tp) + { +//--- check stopped + if(IsStopped(__FUNCTION__)) + return(false); +//--- check position existence + if(!SelectPosition(symbol)) + return(false); +//--- clean + ClearStructures(); +//--- setting request + m_request.action =TRADE_ACTION_SLTP; + m_request.symbol =symbol; + m_request.magic =m_magic; + m_request.sl =sl; + m_request.tp =tp; + m_request.position=PositionGetInteger(POSITION_TICKET); +//--- action and return the result + return(OrderSend(m_request,m_result)); + } +//+------------------------------------------------------------------+ +//| Modify specified opened position | +//+------------------------------------------------------------------+ +bool CTrade::PositionModify(const ulong ticket,const double sl,const double tp) + { +//--- check stopped + if(IsStopped(__FUNCTION__)) + return(false); +//--- check position existence + if(!PositionSelectByTicket(ticket)) + return(false); +//--- clean + ClearStructures(); +//--- setting request + m_request.action =TRADE_ACTION_SLTP; + m_request.position=ticket; + m_request.symbol =PositionGetString(POSITION_SYMBOL); + m_request.magic =m_magic; + m_request.sl =sl; + m_request.tp =tp; +//--- action and return the result + return(OrderSend(m_request,m_result)); + } +//+------------------------------------------------------------------+ +//| Close specified opened position | +//+------------------------------------------------------------------+ +bool CTrade::PositionClose(const string symbol,const ulong deviation) + { + bool partial_close=false; + int retry_count =10; + uint retcode =TRADE_RETCODE_REJECT; +//--- check stopped + if(IsStopped(__FUNCTION__)) + return(false); +//--- clean + ClearStructures(); +//--- check filling + if(!FillingCheck(symbol)) + return(false); + do + { + //--- check + if(SelectPosition(symbol)) + { + if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY) + { + //--- prepare request for close BUY position + m_request.type =ORDER_TYPE_SELL; + m_request.price=SymbolInfoDouble(symbol,SYMBOL_BID); + } + else + { + //--- prepare request for close SELL position + m_request.type =ORDER_TYPE_BUY; + m_request.price=SymbolInfoDouble(symbol,SYMBOL_ASK); + } + } + else + { + //--- position not found + m_result.retcode=retcode; + return(false); + } + //--- setting request + m_request.action =TRADE_ACTION_DEAL; + m_request.symbol =symbol; + m_request.volume =PositionGetDouble(POSITION_VOLUME); + m_request.magic =m_magic; + m_request.deviation=(deviation==ULONG_MAX) ? m_deviation : deviation; + //--- check volume + double max_volume=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX); + if(m_request.volume>max_volume) + { + m_request.volume=max_volume; + partial_close=true; + } + else + partial_close=false; + //--- hedging? just send order + if(IsHedging()) + { + m_request.position=PositionGetInteger(POSITION_TICKET); + return(OrderSend(m_request,m_result)); + } + //--- order send + if(!OrderSend(m_request,m_result)) + { + if(--retry_count!=0) continue; + if(retcode==TRADE_RETCODE_DONE_PARTIAL) + m_result.retcode=retcode; + return(false); + } + //--- WARNING. If position volume exceeds the maximum volume allowed for deal, + //--- and when the asynchronous trade mode is on, for safety reasons, position is closed not completely, + //--- but partially. It is decreased by the maximum volume allowed for deal. + if(m_async_mode) + break; + retcode=TRADE_RETCODE_DONE_PARTIAL; + if(partial_close) + Sleep(1000); + } + while(partial_close); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Close specified opened position | +//+------------------------------------------------------------------+ +bool CTrade::PositionClose(const ulong ticket,const ulong deviation) + { +//--- check stopped + if(IsStopped(__FUNCTION__)) + return(false); +//--- check position existence + if(!PositionSelectByTicket(ticket)) + return(false); + string symbol=PositionGetString(POSITION_SYMBOL); +//--- clean + ClearStructures(); +//--- check filling + if(!FillingCheck(symbol)) + return(false); +//--- check + if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY) + { + //--- prepare request for close BUY position + m_request.type =ORDER_TYPE_SELL; + m_request.price=SymbolInfoDouble(symbol,SYMBOL_BID); + } + else + { + //--- prepare request for close SELL position + m_request.type =ORDER_TYPE_BUY; + m_request.price=SymbolInfoDouble(symbol,SYMBOL_ASK); + } +//--- setting request + m_request.action =TRADE_ACTION_DEAL; + m_request.position =ticket; + m_request.symbol =symbol; + m_request.volume =PositionGetDouble(POSITION_VOLUME); + m_request.magic =m_magic; + m_request.deviation=(deviation==ULONG_MAX) ? m_deviation : deviation; +//--- close position + return(OrderSend(m_request,m_result)); + } +//+------------------------------------------------------------------+ +//| Close one position by other | +//+------------------------------------------------------------------+ +bool CTrade::PositionCloseBy(const ulong ticket,const ulong ticket_by) + { +//--- check stopped + if(IsStopped(__FUNCTION__)) + return(false); +//--- check hedging mode + if(!IsHedging()) + return(false); +//--- check position existence + if(!PositionSelectByTicket(ticket)) + return(false); + string symbol=PositionGetString(POSITION_SYMBOL); + ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); + if(!PositionSelectByTicket(ticket_by)) + return(false); + string symbol_by=PositionGetString(POSITION_SYMBOL); + ENUM_POSITION_TYPE type_by=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); +//--- check positions + if(type==type_by) + return(false); + if(symbol!=symbol_by) + return(false); +//--- clean + ClearStructures(); +//--- check filling + if(!FillingCheck(symbol)) + return(false); +//--- setting request + m_request.action =TRADE_ACTION_CLOSE_BY; + m_request.position =ticket; + m_request.position_by=ticket_by; + m_request.magic =m_magic; +//--- close position + return(OrderSend(m_request,m_result)); + } +//+------------------------------------------------------------------+ +//| Partial close specified opened position (for hedging mode only) | +//+------------------------------------------------------------------+ +bool CTrade::PositionClosePartial(const string symbol,const double volume,const ulong deviation) + { + uint retcode=TRADE_RETCODE_REJECT; +//--- check stopped + if(IsStopped(__FUNCTION__)) + return(false); +//--- for hedging mode only + if(!IsHedging()) + return(false); +//--- clean + ClearStructures(); +//--- check filling + if(!FillingCheck(symbol)) + return(false); +//--- check + if(SelectPosition(symbol)) + { + if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY) + { + //--- prepare request for close BUY position + m_request.type =ORDER_TYPE_SELL; + m_request.price=SymbolInfoDouble(symbol,SYMBOL_BID); + } + else + { + //--- prepare request for close SELL position + m_request.type =ORDER_TYPE_BUY; + m_request.price=SymbolInfoDouble(symbol,SYMBOL_ASK); + } + } + else + { + //--- position not found + m_result.retcode=retcode; + return(false); + } +//--- check volume + double position_volume=PositionGetDouble(POSITION_VOLUME); + if(position_volume>volume) + position_volume=volume; +//--- setting request + m_request.action =TRADE_ACTION_DEAL; + m_request.symbol =symbol; + m_request.volume =position_volume; + m_request.magic =m_magic; + m_request.deviation=(deviation==ULONG_MAX) ? m_deviation : deviation; + m_request.position =PositionGetInteger(POSITION_TICKET); +//--- hedging? just send order + return(OrderSend(m_request,m_result)); + } +//+------------------------------------------------------------------+ +//| Partial close specified opened position (for hedging mode only) | +//+------------------------------------------------------------------+ +bool CTrade::PositionClosePartial(const ulong ticket,const double volume,const ulong deviation) + { +//--- check stopped + if(IsStopped(__FUNCTION__)) + return(false); +//--- for hedging mode only + if(!IsHedging()) + return(false); +//--- check position existence + if(!PositionSelectByTicket(ticket)) + return(false); + string symbol=PositionGetString(POSITION_SYMBOL); +//--- clean + ClearStructures(); +//--- check filling + if(!FillingCheck(symbol)) + return(false); +//--- check + if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY) + { + //--- prepare request for close BUY position + m_request.type =ORDER_TYPE_SELL; + m_request.price=SymbolInfoDouble(symbol,SYMBOL_BID); + } + else + { + //--- prepare request for close SELL position + m_request.type =ORDER_TYPE_BUY; + m_request.price=SymbolInfoDouble(symbol,SYMBOL_ASK); + } +//--- check volume + double position_volume=PositionGetDouble(POSITION_VOLUME); + if(position_volume>volume) + position_volume=volume; +//--- setting request + m_request.action =TRADE_ACTION_DEAL; + m_request.position =ticket; + m_request.symbol =symbol; + m_request.volume =position_volume; + m_request.magic =m_magic; + m_request.deviation=(deviation==ULONG_MAX) ? m_deviation : deviation; +//--- close position + return(OrderSend(m_request,m_result)); + } +//+------------------------------------------------------------------+ +//| Installation pending order | +//+------------------------------------------------------------------+ +bool CTrade::OrderOpen(const string symbol,const ENUM_ORDER_TYPE order_type,const double volume,const double limit_price, + const double price,const double sl,const double tp, + ENUM_ORDER_TYPE_TIME type_time,const datetime expiration,const string comment) + { +//--- check stopped + if(IsStopped(__FUNCTION__)) + return(false); +//--- clean + ClearStructures(); +//--- check filling + if(!FillingCheck(symbol)) + return(false); +//--- check order type + if(order_type==ORDER_TYPE_BUY || order_type==ORDER_TYPE_SELL) + { + m_result.retcode=TRADE_RETCODE_INVALID; + m_result.comment="Invalid order type"; + return(false); + } +//--- check order expiration + if(type_time==ORDER_TIME_GTC && expiration==0) + { + int exp=(int)SymbolInfoInteger(symbol,SYMBOL_EXPIRATION_MODE); + if((exp&SYMBOL_EXPIRATION_GTC)!=SYMBOL_EXPIRATION_GTC) + { + //--- if you place order for an unlimited time and if placing of such orders is prohibited + //--- try to place order with expiration at the end of the day + if((exp&SYMBOL_EXPIRATION_DAY)!=SYMBOL_EXPIRATION_DAY) + { + //--- if even this is not possible - error + Print(__FUNCTION__,": Error: Unable to place order without explicitly specified expiration time"); + m_result.retcode=TRADE_RETCODE_INVALID_EXPIRATION; + m_result.comment="Invalid expiration type"; + return(false); + } + type_time=ORDER_TIME_DAY; + } + } +//--- setting request + m_request.action =TRADE_ACTION_PENDING; + m_request.symbol =symbol; + m_request.magic =m_magic; + m_request.volume =volume; + m_request.type =order_type; + m_request.stoplimit =limit_price; + m_request.price =price; + m_request.sl =sl; + m_request.tp =tp; + m_request.type_time =type_time; + m_request.expiration =expiration; +//--- check order type + if(!OrderTypeCheck(symbol)) + return(false); +//--- check filling + if(!FillingCheck(symbol)) + { + m_result.retcode=TRADE_RETCODE_INVALID_FILL; + Print(__FUNCTION__+": Invalid filling type"); + return(false); + } +//--- check expiration + if(!ExpirationCheck(symbol)) + { + m_result.retcode=TRADE_RETCODE_INVALID_EXPIRATION; + Print(__FUNCTION__+": Invalid expiration type"); + return(false); + } + m_request.comment=comment; +//--- action and return the result + return(OrderSend(m_request,m_result)); + } +//+------------------------------------------------------------------+ +//| Modify specified pending order | +//+------------------------------------------------------------------+ +bool CTrade::OrderModify(const ulong ticket,const double price,const double sl,const double tp, + const ENUM_ORDER_TYPE_TIME type_time,const datetime expiration,const double stoplimit) + { +//--- check stopped + if(IsStopped(__FUNCTION__)) + return(false); +//--- clean + ClearStructures(); +//--- setting request + m_request.action =TRADE_ACTION_MODIFY; + m_request.magic =m_magic; + m_request.order =ticket; + m_request.price =price; + m_request.stoplimit =stoplimit; + m_request.sl =sl; + m_request.tp =tp; + m_request.type_time =type_time; + m_request.expiration =expiration; +//--- action and return the result + return(OrderSend(m_request,m_result)); + } +//+------------------------------------------------------------------+ +//| Delete specified pending order | +//+------------------------------------------------------------------+ +bool CTrade::OrderDelete(const ulong ticket) + { +//--- check stopped + if(IsStopped(__FUNCTION__)) + return(false); +//--- clean + ClearStructures(); +//--- setting request + m_request.action =TRADE_ACTION_REMOVE; + m_request.magic =m_magic; + m_request.order =ticket; +//--- action and return the result + return(OrderSend(m_request,m_result)); + } +//+------------------------------------------------------------------+ +//| Output full information of request to log | +//+------------------------------------------------------------------+ +void CTrade::PrintRequest(void) const + { + if(m_log_level0.0) + volume=stepvol*(MathFloor(lots/stepvol)-1); + //--- + double minvol=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN); + if(volumeLOG_LEVEL_ERRORS) + PrintFormat(__FUNCTION__+": %s [%s]",FormatRequest(action,request),FormatRequestResult(fmt,request,result)); + } + else + { + if(m_log_level>LOG_LEVEL_NO) + PrintFormat(__FUNCTION__+": %s [%s]",FormatRequest(action,request),FormatRequestResult(fmt,request,result)); + } +//--- return the result + return(res); + } +//+------------------------------------------------------------------+ +//| Position select depending on netting or hedging | +//+------------------------------------------------------------------+ +bool CTrade::SelectPosition(const string symbol) + { + bool res=false; +//--- + if(IsHedging()) + { + uint total=PositionsTotal(); + for(uint i=0; i0) sum+=ExtADbuffer[i-1]; + ExtADbuffer[i]=sum; + } +//---- + } +//+------------------------------------------------------------------+ diff --git a/Indicators/Examples/ADX.mq5 b/Indicators/Examples/ADX.mq5 new file mode 100644 index 0000000..9190215 --- /dev/null +++ b/Indicators/Examples/ADX.mq5 @@ -0,0 +1,152 @@ +//+------------------------------------------------------------------+ +//| ADX.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +#property description "Average Directional Movement Index" +#include + +#property indicator_separate_window +#property indicator_buffers 6 +#property indicator_plots 3 +#property indicator_type1 DRAW_LINE +#property indicator_color1 LightSeaGreen +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 +#property indicator_type2 DRAW_LINE +#property indicator_color2 YellowGreen +#property indicator_style2 STYLE_DOT +#property indicator_width2 1 +#property indicator_type3 DRAW_LINE +#property indicator_color3 Wheat +#property indicator_style3 STYLE_DOT +#property indicator_width3 1 +#property indicator_label1 "ADX" +#property indicator_label2 "+DI" +#property indicator_label3 "-DI" +//--- input parameters +input int InpPeriodADX=14; // Period +//---- buffers +double ExtADXBuffer[]; +double ExtPDIBuffer[]; +double ExtNDIBuffer[]; +double ExtPDBuffer[]; +double ExtNDBuffer[]; +double ExtTmpBuffer[]; +//--- global variables +int ExtADXPeriod; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- check for input parameters + if(InpPeriodADX>=100 || InpPeriodADX<=0) + { + ExtADXPeriod=14; + printf("Incorrect value for input variable Period_ADX=%d. Indicator will use value=%d for calculations.",InpPeriodADX,ExtADXPeriod); + } + else ExtADXPeriod=InpPeriodADX; +//---- indicator buffers + SetIndexBuffer(0,ExtADXBuffer); + SetIndexBuffer(1,ExtPDIBuffer); + SetIndexBuffer(2,ExtNDIBuffer); + SetIndexBuffer(3,ExtPDBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(4,ExtNDBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(5,ExtTmpBuffer,INDICATOR_CALCULATIONS); +//--- indicator digits + IndicatorSetInteger(INDICATOR_DIGITS,2); +//--- set draw begin + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,ExtADXPeriod<<1); + PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,ExtADXPeriod); + PlotIndexSetInteger(2,PLOT_DRAW_BEGIN,ExtADXPeriod); +//--- indicator short name + string short_name="ADX("+string(ExtADXPeriod)+")"; + IndicatorSetString(INDICATOR_SHORTNAME,short_name); +//--- change 1-st index label + PlotIndexSetString(0,PLOT_LABEL,short_name); +//---- end of initialization function + } +//+------------------------------------------------------------------+ +//| Custom indicator iteration function | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { +//--- checking for bars count + if(rates_total1) start=prev_calculated-1; + else + { + start=1; + ExtPDIBuffer[0]=0.0; + ExtNDIBuffer[0]=0.0; + ExtADXBuffer[0]=0.0; + } +//--- main cycle + for(int i=start;idTmpN) dTmpN=0.0; + else + { + if(dTmpP +//--- +#property indicator_separate_window +#property indicator_buffers 10 +#property indicator_plots 3 +#property indicator_type1 DRAW_LINE +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 +#property indicator_color1 LightSeaGreen +#property indicator_type2 DRAW_LINE +#property indicator_style2 STYLE_DOT +#property indicator_width2 1 +#property indicator_color2 YellowGreen +#property indicator_type3 DRAW_LINE +#property indicator_style3 STYLE_DOT +#property indicator_width3 1 +#property indicator_color3 Wheat +#property indicator_label1 "ADX Wilder" +#property indicator_label2 "+DI" +#property indicator_label3 "-DI" +//--- input parameters +input int InpPeriodADXW=14; // Period +//---- buffers +double ExtADXWBuffer[]; +double ExtPDIBuffer[]; +double ExtNDIBuffer[]; +double ExtPDSBuffer[]; +double ExtNDSBuffer[]; +double ExtPDBuffer[]; +double ExtNDBuffer[]; +double ExtTRBuffer[]; +double ExtATRBuffer[]; +double ExtDXBuffer[]; +//--- global variable +int ExtADXWPeriod; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- check for input parameters + if(InpPeriodADXW>=100 || InpPeriodADXW<=0) + { + ExtADXWPeriod=14; + printf("Incorrect value for input variable InpPeriodADXW=%d. Indicator will use value=%d for calculations.",InpPeriodADXW,ExtADXWPeriod); + } + else ExtADXWPeriod=InpPeriodADXW; +//---- indicator buffers + SetIndexBuffer(0,ExtADXWBuffer); + SetIndexBuffer(1,ExtPDIBuffer); + SetIndexBuffer(2,ExtNDIBuffer); +//--- calculation buffers + SetIndexBuffer(3,ExtPDBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(4,ExtNDBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(5,ExtDXBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(6,ExtTRBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(7,ExtATRBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(8,ExtPDSBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(9,ExtNDSBuffer,INDICATOR_CALCULATIONS); +//--- set draw begin + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,ExtADXWPeriod<<1); + PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,ExtADXWPeriod+1); + PlotIndexSetInteger(2,PLOT_DRAW_BEGIN,ExtADXWPeriod+1); +//--- indicator short name + string short_name="ADX Wilder("+string(ExtADXWPeriod)+")"; + IndicatorSetString(INDICATOR_SHORTNAME,short_name); +//--- change 1-st index label + PlotIndexSetString(0,PLOT_LABEL,short_name); +//--- indicator digits + IndicatorSetInteger(INDICATOR_DIGITS,2); +//---- end of initialization function + } +//+------------------------------------------------------------------+ +//| Custom indicator iteration function | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { +//--- checking for bars count + if(rates_total1) start=prev_calculated-1; + else + { + start=1; + for(int i=0;i1e-7) + ExtT=InpT; + else + { + ExtT=300.0; + printf("Input parameter T has wrong value. Indicator will use T = %f.",ExtT); + } +//--- define buffers + SetIndexBuffer(0,ExtASIBuffer); + SetIndexBuffer(1,ExtSIBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(2,ExtTRBuffer,INDICATOR_CALCULATIONS); +//--- draw begin settings + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,1); +//--- number of digits of indicator value + IndicatorSetInteger(INDICATOR_DIGITS,2); +//--- calculate ExtTpoints value + if(fabs(_Point)>1e-7) + ExtTpoints=ExtT*_Point; + else + ExtTpoints=ExtT*pow(10,-_Digits); +//---- OnInit done + } +//+------------------------------------------------------------------+ +//| Custom indicator iteration function | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { +//--- check for bars count + if(rates_total<2) return(0); +//--- + int pos; +//--- start calculation + pos=prev_calculated-1; +//--- correct position, when it's first iteration + if(pos<=0) + { + pos=1; + ExtASIBuffer[0]=0.0; + ExtSIBuffer[0]=0.0; + ExtTRBuffer[0]=high[0]-low[0]; + } +//--- main cycle + for(int i=pos;i=dLow && dPrevClose<=dHigh)) + { + if(dPrevClose>dHigh) ER=MathAbs(dHigh-dPrevClose); + if(dPrevCloserates_total || prev_calculated<0) to_copy=rates_total; + else + { + to_copy=rates_total-prev_calculated; + if(prev_calculated>0) to_copy++; + } +//--- get FastSMA buffer + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtFastSMAHandle,0,0,to_copy,ExtFastBuffer)<=0) + { + Print("Getting fast SMA is failed! Error",GetLastError()); + return(0); + } +//--- get SlowSMA buffer + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtSlowSMAHandle,0,0,to_copy,ExtSlowBuffer)<=0) + { + Print("Getting slow SMA is failed! Error",GetLastError()); + return(0); + } +//--- calculations + int i,limit; +//--- first calculation or number of bars was changed + if(prev_calculated<=33) + { + for(i=0;i<33;i++) + { + ExtACBuffer[i]=0.0; + ExtAOBuffer[i]=0.0; + } + limit=33; + } + else limit=prev_calculated-1; +//--- main loop of calculations + for(i=limit;i=ExtACBuffer[i-1]) + ExtColorBuffer[i]=0.0; // set color Green + else + ExtColorBuffer[i]=1.0; // set color Red + } +//--- return value of prev_calculated for next call + return(rates_total); + } + +//+------------------------------------------------------------------+ diff --git a/Indicators/Examples/Alligator.mq5 b/Indicators/Examples/Alligator.mq5 new file mode 100644 index 0000000..3663dfd --- /dev/null +++ b/Indicators/Examples/Alligator.mq5 @@ -0,0 +1,145 @@ +//+------------------------------------------------------------------+ +//| Alligator.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" + +//---- indicator settings +#property indicator_chart_window +#property indicator_buffers 3 +#property indicator_plots 3 +#property indicator_type1 DRAW_LINE +#property indicator_type2 DRAW_LINE +#property indicator_type3 DRAW_LINE +#property indicator_color1 Blue +#property indicator_color2 Red +#property indicator_color3 Lime +#property indicator_width1 1 +#property indicator_width2 1 +#property indicator_width3 1 +#property indicator_label1 "Jaws" +#property indicator_label2 "Teeth" +#property indicator_label3 "Lips" +//---- input parameters +input int InpJawsPeriod=13; // Jaws period +input int InpJawsShift=8; // Jaws shift +input int InpTeethPeriod=8; // Teeth period +input int InpTeethShift=5; // Teeth shift +input int InpLipsPeriod=5; // Lips period +input int InpLipsShift=3; // Lips shift +input ENUM_MA_METHOD InpMAMethod=MODE_SMMA; // Moving average method +input ENUM_APPLIED_PRICE InpAppliedPrice=PRICE_MEDIAN; // Applied price +//---- indicator buffers +double ExtJaws[]; +double ExtTeeth[]; +double ExtLips[]; +//---- handles for moving averages +int ExtJawsHandle; +int ExtTeethHandle; +int ExtLipsHandle; +//--- bars minimum for calculation +int ExtBarsMinimum; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//---- indicator buffers mapping + SetIndexBuffer(0,ExtJaws,INDICATOR_DATA); + SetIndexBuffer(1,ExtTeeth,INDICATOR_DATA); + SetIndexBuffer(2,ExtLips,INDICATOR_DATA); +//--- set accuracy + IndicatorSetInteger(INDICATOR_DIGITS,_Digits); +//---- sets first bar from what index will be drawn + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,InpJawsPeriod-1); + PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,InpTeethPeriod-1); + PlotIndexSetInteger(2,PLOT_DRAW_BEGIN,InpLipsPeriod-1); +//---- line shifts when drawing + PlotIndexSetInteger(0,PLOT_SHIFT,InpJawsShift); + PlotIndexSetInteger(1,PLOT_SHIFT,InpTeethShift); + PlotIndexSetInteger(2,PLOT_SHIFT,InpLipsShift); +//---- name for DataWindow + PlotIndexSetString(0,PLOT_LABEL,"Jaws("+string(InpJawsPeriod)+")"); + PlotIndexSetString(1,PLOT_LABEL,"Teeth("+string(InpTeethPeriod)+")"); + PlotIndexSetString(2,PLOT_LABEL,"Lips("+string(InpLipsPeriod)+")"); +//--- get MA's handles + ExtJawsHandle=iMA(NULL,0,InpJawsPeriod,0,InpMAMethod,InpAppliedPrice); + ExtTeethHandle=iMA(NULL,0,InpTeethPeriod,0,InpMAMethod,InpAppliedPrice); + ExtLipsHandle=iMA(NULL,0,InpLipsPeriod,0,InpMAMethod,InpAppliedPrice); +//--- bars minimum for calculation + ExtBarsMinimum=InpJawsPeriod+InpJawsShift; + if(ExtBarsMinimum<(InpTeethPeriod+InpTeethShift)) + ExtBarsMinimum=InpTeethPeriod+InpTeethShift; + if(ExtBarsMinimum<(InpLipsPeriod+InpLipsPeriod)) + ExtBarsMinimum=InpLipsPeriod+InpLipsPeriod; +//--- initialization done + } +//+------------------------------------------------------------------+ +//| Alligator OnCalculate function | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { +//--- check for rates total + if(rates_totalrates_total || prev_calculated<0) to_copy=rates_total; + else + { + to_copy=rates_total-prev_calculated; + if(prev_calculated>0) to_copy++; + } +//---- get ma buffers + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtJawsHandle,0,0,to_copy,ExtJaws)<=0) + { + Print("getting ExtJawsHandle is failed! Error",GetLastError()); + return(0); + } + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtTeethHandle,0,0,to_copy,ExtTeeth)<=0) + { + Print("getting ExtTeethHandle is failed! Error",GetLastError()); + return(0); + } + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtLipsHandle,0,0,to_copy,ExtLips)<=0) + { + Print("getting ExtLipsHandle is failed! Error",GetLastError()); + return(0); + } +//--- return value of prev_calculated for next call + return(rates_total); + } +//+------------------------------------------------------------------+ diff --git a/Indicators/Examples/Awesome_Oscillator.mq5 b/Indicators/Examples/Awesome_Oscillator.mq5 new file mode 100644 index 0000000..34584f4 --- /dev/null +++ b/Indicators/Examples/Awesome_Oscillator.mq5 @@ -0,0 +1,120 @@ +//+------------------------------------------------------------------+ +//| Awesome_Oscillator.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" + +//---- indicator settings +#property indicator_separate_window +#property indicator_buffers 4 +#property indicator_plots 1 +#property indicator_type1 DRAW_COLOR_HISTOGRAM +#property indicator_color1 Green,Red +#property indicator_width1 1 +#property indicator_label1 "AO" +//--- indicator buffers +double ExtAOBuffer[]; +double ExtColorBuffer[]; +double ExtFastBuffer[]; +double ExtSlowBuffer[]; +//--- handles for MAs +int ExtFastSMAHandle; +int ExtSlowSMAHandle; +//--- bars minimum for calculation +#define DATA_LIMIT 33 +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//---- indicator buffers mapping + SetIndexBuffer(0,ExtAOBuffer,INDICATOR_DATA); + SetIndexBuffer(1,ExtColorBuffer,INDICATOR_COLOR_INDEX); + SetIndexBuffer(2,ExtFastBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(3,ExtSlowBuffer,INDICATOR_CALCULATIONS); +//--- set accuracy + IndicatorSetInteger(INDICATOR_DIGITS,_Digits+1); +//--- sets first bar from what index will be drawn + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,33); +//--- name for DataWindow + IndicatorSetString(INDICATOR_SHORTNAME,"AO"); +//--- get handles + ExtFastSMAHandle=iMA(NULL,0,5,0,MODE_SMA,PRICE_MEDIAN); + ExtSlowSMAHandle=iMA(NULL,0,34,0,MODE_SMA,PRICE_MEDIAN); +//---- initialization done + } +//+------------------------------------------------------------------+ +//| Awesome Oscillator | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { +//--- check for rates total + if(rates_total<=DATA_LIMIT) + return(0);// not enough bars for calculation +//--- not all data may be calculated + int calculated=BarsCalculated(ExtFastSMAHandle); + if(calculatedrates_total || prev_calculated<0) to_copy=rates_total; + else + { + to_copy=rates_total-prev_calculated; + if(prev_calculated>0) to_copy++; + } +//--- get FastSMA buffer + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtFastSMAHandle,0,0,to_copy,ExtFastBuffer)<=0) + { + Print("Getting fast SMA is failed! Error",GetLastError()); + return(0); + } +//--- get SlowSMA buffer + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtSlowSMAHandle,0,0,to_copy,ExtSlowBuffer)<=0) + { + Print("Getting slow SMA is failed! Error",GetLastError()); + return(0); + } +//--- first calculation or number of bars was changed + int i,limit; + if(prev_calculated<=DATA_LIMIT) + { + for(i=0;iExtAOBuffer[i-1])ExtColorBuffer[i]=0.0; // set color Green + else ExtColorBuffer[i]=1.0; // set color Red + } +//--- return value of prev_calculated for next call + return(rates_total); + } + +//+------------------------------------------------------------------+ diff --git a/Indicators/Examples/BB.mq5 b/Indicators/Examples/BB.mq5 new file mode 100644 index 0000000..344c1f9 --- /dev/null +++ b/Indicators/Examples/BB.mq5 @@ -0,0 +1,140 @@ +//+------------------------------------------------------------------+ +//| BB.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +#property description "Bollinger Bands" +#include +//--- +#property indicator_chart_window +#property indicator_buffers 4 +#property indicator_plots 3 +#property indicator_type1 DRAW_LINE +#property indicator_color1 LightSeaGreen +#property indicator_type2 DRAW_LINE +#property indicator_color2 LightSeaGreen +#property indicator_type3 DRAW_LINE +#property indicator_color3 LightSeaGreen +#property indicator_label1 "Bands middle" +#property indicator_label2 "Bands upper" +#property indicator_label3 "Bands lower" +//--- input parametrs +input int InpBandsPeriod=20; // Period +input int InpBandsShift=0; // Shift +input double InpBandsDeviations=2.0; // Deviation +//--- global variables +int ExtBandsPeriod,ExtBandsShift; +double ExtBandsDeviations; +int ExtPlotBegin=0; +//---- indicator buffer +double ExtMLBuffer[]; +double ExtTLBuffer[]; +double ExtBLBuffer[]; +double ExtStdDevBuffer[]; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- check for input values + if(InpBandsPeriod<2) + { + ExtBandsPeriod=20; + printf("Incorrect value for input variable InpBandsPeriod=%d. Indicator will use value=%d for calculations.",InpBandsPeriod,ExtBandsPeriod); + } + else ExtBandsPeriod=InpBandsPeriod; + if(InpBandsShift<0) + { + ExtBandsShift=0; + printf("Incorrect value for input variable InpBandsShift=%d. Indicator will use value=%d for calculations.",InpBandsShift,ExtBandsShift); + } + else + ExtBandsShift=InpBandsShift; + if(InpBandsDeviations==0.0) + { + ExtBandsDeviations=2.0; + printf("Incorrect value for input variable InpBandsDeviations=%f. Indicator will use value=%f for calculations.",InpBandsDeviations,ExtBandsDeviations); + } + else ExtBandsDeviations=InpBandsDeviations; +//--- define buffers + SetIndexBuffer(0,ExtMLBuffer); + SetIndexBuffer(1,ExtTLBuffer); + SetIndexBuffer(2,ExtBLBuffer); + SetIndexBuffer(3,ExtStdDevBuffer,INDICATOR_CALCULATIONS); +//--- set index labels + PlotIndexSetString(0,PLOT_LABEL,"Bands("+string(ExtBandsPeriod)+") Middle"); + PlotIndexSetString(1,PLOT_LABEL,"Bands("+string(ExtBandsPeriod)+") Upper"); + PlotIndexSetString(2,PLOT_LABEL,"Bands("+string(ExtBandsPeriod)+") Lower"); +//--- indicator name + IndicatorSetString(INDICATOR_SHORTNAME,"Bollinger Bands"); +//--- indexes draw begin settings + ExtPlotBegin=ExtBandsPeriod-1; + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,ExtBandsPeriod); + PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,ExtBandsPeriod); + PlotIndexSetInteger(2,PLOT_DRAW_BEGIN,ExtBandsPeriod); +//--- indexes shift settings + PlotIndexSetInteger(0,PLOT_SHIFT,ExtBandsShift); + PlotIndexSetInteger(1,PLOT_SHIFT,ExtBandsShift); + PlotIndexSetInteger(2,PLOT_SHIFT,ExtBandsShift); +//--- number of digits of indicator value + IndicatorSetInteger(INDICATOR_DIGITS,_Digits+1); +//---- OnInit done + } +//+------------------------------------------------------------------+ +//| Custom indicator iteration function | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const int begin, + const double &price[]) + { +//--- variables + int pos; +//--- indexes draw begin settings, when we've recieved previous begin + if(ExtPlotBegin!=ExtBandsPeriod+begin) + { + ExtPlotBegin=ExtBandsPeriod+begin; + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,ExtPlotBegin); + PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,ExtPlotBegin); + PlotIndexSetInteger(2,PLOT_DRAW_BEGIN,ExtPlotBegin); + } +//--- check for bars count + if(rates_total1) pos=prev_calculated-1; + else pos=0; +//--- main cycle + for(int i=pos;irates_total || prev_calculated<0) to_copy=rates_total; + else + { + to_copy=rates_total-prev_calculated; + if(prev_calculated>0) to_copy++; + } +//--- get AC buffer + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtACHandle,0,0,to_copy,ExtACBuffer)<=0) + { + Print("Getting iAC is failed! Error",GetLastError()); + return(0); + } +//--- get AO buffer + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtAOHandle,0,0,to_copy,ExtAOBuffer)<=0) + { + Print("Getting iAO is failed! Error",GetLastError()); + return(0); + } +//--- set first bar from what calculation will start + if(prev_calculatedExtACBuffer[i-1] && ExtAOBuffer[i]>ExtAOBuffer[i-1]) + ExtColorBuffer[i]=0.0; + //--- check for Red Zone and set Color Red + if(ExtACBuffer[i]rates_total || prev_calculated<0) to_copy=rates_total; + else + { + to_copy=rates_total-prev_calculated; + if(prev_calculated>0) to_copy++; + } +//---- get ma buffers + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtEmaHandle,0,0,to_copy,ExtTempBuffer)<=0) + { + Print("getting ExtEmaHandle is failed! Error",GetLastError()); + return(0); + } +//--- first calculation or number of bars was changed + if(prev_calculatedrates_total || prev_calculated<0) to_copy=rates_total; + else + { + to_copy=rates_total-prev_calculated; + if(prev_calculated>0) to_copy++; + } +//---- get ma buffers + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtEmaHandle,0,0,to_copy,ExtTempBuffer)<=0) + { + Print("getting ExtEmaHandle is failed! Error",GetLastError()); + return(0); + } +//--- first calculation or number of bars was changed + if(prev_calculated +//--- +#property indicator_separate_window +#property indicator_buffers 4 +#property indicator_plots 1 +#property indicator_type1 DRAW_LINE +#property indicator_color1 LightSeaGreen +#property indicator_level1 -100.0 +#property indicator_level2 100.0 +#property indicator_applied_price PRICE_TYPICAL +//--- input parametrs +input int InpCCIPeriod=14; // Period +//--- global variable +int ExtCCIPeriod; +//---- indicator buffer +double ExtSPBuffer[]; +double ExtDBuffer[]; +double ExtMBuffer[]; +double ExtCCIBuffer[]; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- check for input value of period + if(InpCCIPeriod<=0) + { + ExtCCIPeriod=14; + printf("Incorrect value for input variable InpCCIPeriod=%d. Indicator will use value=%d for calculations.",InpCCIPeriod,ExtCCIPeriod); + } + else ExtCCIPeriod=InpCCIPeriod; +//--- define buffers + SetIndexBuffer(0,ExtCCIBuffer); + SetIndexBuffer(1,ExtDBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(2,ExtMBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(3,ExtSPBuffer,INDICATOR_CALCULATIONS); +//--- indicator name + IndicatorSetString(INDICATOR_SHORTNAME,"CCI("+string(ExtCCIPeriod)+")"); +//--- indexes draw begin settings + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,ExtCCIPeriod-1); +//--- number of digits of indicator value + IndicatorSetInteger(INDICATOR_DIGITS,2); +//---- OnInit done + } +//+------------------------------------------------------------------+ +//| Custom indicator iteration function | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const int begin, + const double &price[]) + { +//--- variables + int i,j; + double dTmp,dMul=0.015/ExtCCIPeriod; +//--- start calculation + int StartCalcPosition=(ExtCCIPeriod-1)+begin; +//--- check for bars count + if(rates_total0) PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,StartCalcPosition+(ExtCCIPeriod-1)); +//--- calculate position + int pos=prev_calculated-1; + if(pos +//--- indicator settings +#property indicator_separate_window +#property indicator_buffers 4 +#property indicator_plots 1 +#property indicator_type1 DRAW_LINE +#property indicator_color1 LightSeaGreen +//--- input parameters +input int InpFastMA=3; // Fast MA period +input int InpSlowMA=10; // Slow MA period +input ENUM_MA_METHOD InpSmoothMethod=MODE_EMA; // MA method +input ENUM_APPLIED_VOLUME InpVolumeType=VOLUME_TICK; // Volumes +//--- indicator buffers +double ExtCHOBuffer[]; +double ExtFastEMABuffer[]; +double ExtSlowEMABuffer[]; +double ExtADBuffer[]; +static int weightfast,weightslow; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- indicator buffers mapping + SetIndexBuffer(0,ExtCHOBuffer,INDICATOR_DATA); + SetIndexBuffer(1,ExtFastEMABuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(2,ExtSlowEMABuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(3,ExtADBuffer,INDICATOR_CALCULATIONS); +//--- set accuracy + IndicatorSetInteger(INDICATOR_DIGITS,0); +//--- sets first bar from what index will be drawn + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,InpSlowMA); +//--- name for DataWindow and indicator subwindow label + IndicatorSetString(INDICATOR_SHORTNAME,"CHO("+string(InpSlowMA)+","+string(InpFastMA)+")"); +//--- initialization done + } +//+------------------------------------------------------------------+ +//| calculate AD | +//+------------------------------------------------------------------+ +double AD(double high,double low,double close,long volume) + { + double res=0; +//--- + if(high!=low) + res=(2*close-high-low)/(high-low)*volume; +//--- + return(res); + } +//+------------------------------------------------------------------+ +//| calculate average on array | +//+------------------------------------------------------------------+ +void AverageOnArray(const int mode,const int rates_total,const int prev_calculated,const int begin, + const int period,const double& source[],double& destination[],int &weightsum) + { + switch(mode) + { + case MODE_EMA: + ExponentialMAOnBuffer(rates_total,prev_calculated,begin,period,source,destination); + break; + case MODE_SMMA: + SmoothedMAOnBuffer(rates_total,prev_calculated,begin,period,source,destination); + break; + case MODE_LWMA: + LinearWeightedMAOnBuffer(rates_total,prev_calculated,begin,period,source,destination,weightsum); + break; + default: + SimpleMAOnBuffer(rates_total,prev_calculated,begin,period,source,destination); + } + } +//+------------------------------------------------------------------+ +//| Chaikin Oscillator | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { + int i,limit; +//--- check for rates total + if(rates_total +//--- indicator settings +#property indicator_separate_window +#property indicator_buffers 3 +#property indicator_plots 1 +#property indicator_type1 DRAW_LINE +#property indicator_color1 DodgerBlue +//--- enum +enum SmoothMethod + { + SMA=0,// Simple MA + EMA=1 // Exponential MA + }; +//--- input parameters +input int InpSmoothPeriod=10; // Smoothing period +input int InpCHVPeriod=10; // CHV period +input SmoothMethod InpSmoothType=EMA; // Smoothing method +//---- buffers +double ExtCHVBuffer[]; +double ExtHLBuffer[]; +double ExtSHLBuffer[]; +//--- global variables +int ExtSmoothPeriod,ExtCHVPeriod; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- check for input variables + string MAName; +//--- set MA name + if(InpSmoothType==SMA) + MAName="SMA"; + else + MAName="EMA"; +//--- check inputs + if(InpSmoothPeriod<=0) + { + ExtSmoothPeriod=10; + printf("Incorrect value for input variable InpSmoothPeriod=%d. Indicator will use value=%d for calculations.",InpSmoothPeriod,ExtSmoothPeriod); + } + else ExtSmoothPeriod=InpSmoothPeriod; + if(InpCHVPeriod<=0) + { + ExtCHVPeriod=10; + printf("Incorrect value for input variable InpCHVPeriod=%d. Indicator will use value=%d for calculations.",InpCHVPeriod,ExtCHVPeriod); + } + else ExtCHVPeriod=InpCHVPeriod; +//---- define buffers + SetIndexBuffer(0,ExtCHVBuffer); + SetIndexBuffer(1,ExtHLBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(2,ExtSHLBuffer,INDICATOR_CALCULATIONS); +//--- set draw begin + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,ExtSmoothPeriod+ExtCHVPeriod-1); +//--- set index label + PlotIndexSetString(0,PLOT_LABEL,"CHV("+string(ExtSmoothPeriod)+","+MAName+")"); +//--- indicator name + IndicatorSetString(INDICATOR_SHORTNAME,"Chaikin Volatility("+string(ExtSmoothPeriod)+","+MAName+")"); +//--- round settings + IndicatorSetInteger(INDICATOR_DIGITS,1); +//---- OnInit done + } +//+------------------------------------------------------------------+ +//| Custom indicator iteration function | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { +//--- variables of indicator + int i,pos,posCHV; +//--- check for rates total + posCHV=ExtCHVPeriod+ExtSmoothPeriod-2; + if(rates_total +//+------------------------------------------------------------------+ +//| Indicator properties | +//+------------------------------------------------------------------+ +#property indicator_chart_window +#property indicator_buffers 0 +#property indicator_plots 0 +//+------------------------------------------------------------------+ +//| Input parameters | +//+------------------------------------------------------------------+ +input int InpFuturefBars =50; +//+------------------------------------------------------------------+ +//| global variables | +//+------------------------------------------------------------------+ +CFlameCanvas ExtCanvas; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + if(!ExtCanvas.FlameCreate("FlameChart",TimeCurrent(),InpFuturefBars,0)) + return(INIT_FAILED); +//--- succeed + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Custom indicator deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { + } +//+------------------------------------------------------------------+ +//| Custom indicator iteration function | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { + datetime xb1=time[rates_total-1]; + double yb1=high[rates_total-1]; + datetime xe1=xb1+InpFuturefBars*PeriodSeconds(); + double ye1=ChartGetDouble(0,CHART_PRICE_MAX); + datetime xb2=xb1; + double yb2=low[rates_total-1]; + datetime xe2=xe1; + double ye2=ChartGetDouble(0,CHART_PRICE_MIN); +//--- "nozzle" is defined using two lines: ((xb1,yb1),(xe1,ye1)) and ((xb2,yb2),(xe2,ye2)) + ExtCanvas.FlameSet(xb1,yb1,xe1,ye1,xb2,yb2,xe2,ye2); +//--- result + return(rates_total); + } +//+------------------------------------------------------------------+ +//| Custom indicator chart's event handler | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id,const long& lparam,const double& dparam,const string& sparam) + { + ExtCanvas.ChartEventHandler(id,lparam,dparam,sparam); + } +//+------------------------------------------------------------------+ diff --git a/Indicators/Examples/ColorBars.mq5 b/Indicators/Examples/ColorBars.mq5 new file mode 100644 index 0000000..df08370 --- /dev/null +++ b/Indicators/Examples/ColorBars.mq5 @@ -0,0 +1,80 @@ +//+------------------------------------------------------------------+ +//| ColorBars.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" + +#property indicator_chart_window +#property indicator_buffers 5 +#property indicator_plots 1 +//---- plot ColorBars +#property indicator_label1 "ColorBars" +#property indicator_type1 DRAW_COLOR_BARS +#property indicator_color1 Green,Red +#property indicator_label1 "Open;High;Low;Close" +//--- indicator buffers +double ExtOpenBuffer[]; +double ExtHighBuffer[]; +double ExtLowBuffer[]; +double ExtCloseBuffer[]; +double ExtColorsBuffer[]; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- indicators + SetIndexBuffer(0,ExtOpenBuffer,INDICATOR_DATA); + SetIndexBuffer(1,ExtHighBuffer,INDICATOR_DATA); + SetIndexBuffer(2,ExtLowBuffer,INDICATOR_DATA); + SetIndexBuffer(3,ExtCloseBuffer,INDICATOR_DATA); + SetIndexBuffer(4,ExtColorsBuffer,INDICATOR_COLOR_INDEX); +//--- don't show indicator data in DataWindow + PlotIndexSetInteger(0,PLOT_SHOW_DATA,false); +//--- set accuracy + IndicatorSetInteger(INDICATOR_DIGITS,_Digits); + } +//+------------------------------------------------------------------+ +//| Custom indicator iteration function | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { +//--- auxiliary variables + int i=0; + bool vol_up=true; +//--- set position for beginning + if(i0) + { + if(tick_volume[i]>tick_volume[i-1]) vol_up=true; + if(tick_volume[i]rates_total || prev_calculated<0) to_copy=rates_total; + else + { + to_copy=rates_total-prev_calculated; + if(prev_calculated>0) to_copy++; + } + //--- copy values of MA into indicator buffer ExtColorLineBuffer + if(IsStopped()) return(0); //Checking for stop flag + int copied=CopyBuffer(ExtMAHandle,0,0,rates_total,ExtColorLineBuffer); + if(copied<=0) return(0); + + ticks++;// ticks counting + if(ticks>=5)//it's time to change color scheme + { + ticks=0; // reset counter + modified++; // counter of color changes + if(modified>=3)modified=0;// reset counter + ResetLastError(); + switch(modified) + { + case 0:// first color scheme + PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,Red); + PlotIndexSetInteger(0,PLOT_LINE_COLOR,1,Blue); + PlotIndexSetInteger(0,PLOT_LINE_COLOR,2,Green); + break; + case 1:// second color scheme + PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,Yellow); + PlotIndexSetInteger(0,PLOT_LINE_COLOR,1,Pink); + PlotIndexSetInteger(0,PLOT_LINE_COLOR,2,LightSlateGray); + break; + default:// third color scheme + PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,LightGoldenrod); + PlotIndexSetInteger(0,PLOT_LINE_COLOR,1,Orchid); + PlotIndexSetInteger(0,PLOT_LINE_COLOR,2,LimeGreen); + } + } + else + { + //--- set start position + limit=prev_calculated-1; + //--- now we set line color for every bar + for(int i=limit;i +//--- indicator settings +#property indicator_chart_window +#property indicator_buffers 3 +#property indicator_plots 1 +#property indicator_type1 DRAW_LINE +#property indicator_color1 DarkBlue +#property indicator_width1 1 +#property indicator_label1 "DEMA" +#property indicator_applied_price PRICE_CLOSE +//--- input parameters +input int InpPeriodEMA=14; // EMA period +input int InpShift=0; // Indicator's shift +//--- indicator buffers +double DemaBuffer[]; +double Ema[]; +double EmaOfEma[]; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- indicator buffers mapping + SetIndexBuffer(0,DemaBuffer,INDICATOR_DATA); + SetIndexBuffer(1,Ema,INDICATOR_CALCULATIONS); + SetIndexBuffer(2,EmaOfEma,INDICATOR_CALCULATIONS); +//--- sets first bar from what index will be drawn + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,2*InpPeriodEMA-2); +//--- sets indicator shift + PlotIndexSetInteger(0,PLOT_SHIFT,InpShift); +//--- name for indicator label + IndicatorSetString(INDICATOR_SHORTNAME,"DEMA("+string(InpPeriodEMA)+")"); +//--- name for index label + PlotIndexSetString(0,PLOT_LABEL,"DEMA("+string(InpPeriodEMA)+")"); +//--- initialization done + } +//+------------------------------------------------------------------+ +//| Double Exponential Moving Average | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const int begin, + const double &price[]) + { +//--- check for data + if(rates_total<2*InpPeriodEMA-2) + return(0); +//--- + int limit; + if(prev_calculated==0) + limit=0; + else limit=prev_calculated-1; +//--- calculate EMA + ExponentialMAOnBuffer(rates_total,prev_calculated,0,InpPeriodEMA,price,Ema); +//--- calculate EMA on EMA array + ExponentialMAOnBuffer(rates_total,prev_calculated,InpPeriodEMA-1,InpPeriodEMA,Ema,EmaOfEma); +//--- calculate DEMA + for(int i=limit;i +//--- indicator settings +#property indicator_separate_window +#property indicator_buffers 2 +#property indicator_plots 1 +#property indicator_type1 DRAW_LINE +#property indicator_color1 DodgerBlue +//--- input parameters +input int InpDetrendPeriod=12; // Period +//--- indicator buffers +double ExtDPOBuffer[]; +double ExtMABuffer[]; +//--- global variable +int ExtMAPeriod; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- get length of cycle for smoothing + ExtMAPeriod=InpDetrendPeriod/2+1; +//--- indicator buffers mapping + SetIndexBuffer(0,ExtDPOBuffer,INDICATOR_DATA); + SetIndexBuffer(1,ExtMABuffer,INDICATOR_CALCULATIONS); +//--- set accuracy + IndicatorSetInteger(INDICATOR_DIGITS,_Digits+1); +//--- set first bar from what index will be drawn + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,ExtMAPeriod-1); +//--- name for DataWindow and indicator subwindow label + IndicatorSetString(INDICATOR_SHORTNAME,"DPO("+string(InpDetrendPeriod)+")"); +//--- initialization done + } +//+------------------------------------------------------------------+ +//| Detrended Price Oscillator | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const int begin, + const double &price[]) + { + int limit; + int firstInd=begin+ExtMAPeriod-1; +//--- correct draw begin + if(begin>0) PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,firstInd); +//--- preliminary calculations + if(prev_calculated +//--- indicator settings +#property indicator_separate_window +#property indicator_buffers 5 +#property indicator_plots 1 +#property indicator_type1 DRAW_LINE +#property indicator_color1 DodgerBlue +#property indicator_level1 0.3 +#property indicator_level2 0.7 +//--- input parameters +input int InpDeMarkerPeriod=14; // Period +//--- indicator buffers +double ExtDeMarkerBuffer[]; +double ExtDeMaxBuffer[]; +double ExtDeMinBuffer[]; +double ExtAvgDeMaxBuffer[]; +double ExtAvgDeMinBuffer[]; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- indicator buffers mapping + SetIndexBuffer(0,ExtDeMarkerBuffer,INDICATOR_DATA); + SetIndexBuffer(1,ExtDeMaxBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(2,ExtDeMinBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(3,ExtAvgDeMaxBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(4,ExtAvgDeMinBuffer,INDICATOR_CALCULATIONS); +//--- set accuracy + IndicatorSetInteger(INDICATOR_DIGITS,3); +//--- sets first bar from what index will be drawn + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,InpDeMarkerPeriod); +//--- name for DataWindow and indicator subwindow label + IndicatorSetString(INDICATOR_SHORTNAME,"DeM("+string(InpDeMarkerPeriod)+")"); +//--- initialization done + } +//+------------------------------------------------------------------+ +//| DeMarker | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { + int i,limit; + double dNum; +//--- check for bars count + if(rates_totalhigh[i-1]) ExtDeMaxBuffer[i]=high[i]-high[i-1]; + else ExtDeMaxBuffer[i]=0.0; + + if(low[i-1]>low[i]) ExtDeMinBuffer[i]=low[i-1]-low[i]; + else ExtDeMinBuffer[i]=0.0; + } + for(i=0;ihigh[i-1]) ExtDeMaxBuffer[i]=high[i]-high[i-1]; + else ExtDeMaxBuffer[i]=0.0; + + if(low[i-1]>low[i]) ExtDeMinBuffer[i]=low[i-1]-low[i]; + else ExtDeMinBuffer[i]=0.0; + + ExtAvgDeMaxBuffer[i]=SimpleMA(i,InpDeMarkerPeriod,ExtDeMaxBuffer); + ExtAvgDeMinBuffer[i]=SimpleMA(i,InpDeMarkerPeriod,ExtDeMinBuffer); + + dNum=ExtAvgDeMaxBuffer[i]+ExtAvgDeMinBuffer[i]; + if(dNum!=0) ExtDeMarkerBuffer[i]=ExtAvgDeMaxBuffer[i]/dNum; + else ExtDeMarkerBuffer[i]=0.0; + } +//--- OnCalculate done. Return new prev_calculated. + return(rates_total); + } +//+------------------------------------------------------------------+ diff --git a/Indicators/Examples/Envelopes.mq5 b/Indicators/Examples/Envelopes.mq5 new file mode 100644 index 0000000..bcddbef --- /dev/null +++ b/Indicators/Examples/Envelopes.mq5 @@ -0,0 +1,106 @@ +//+------------------------------------------------------------------+ +//| Envelopes.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +//--- indicator settings +#property indicator_chart_window +#property indicator_buffers 3 +#property indicator_plots 2 +#property indicator_type1 DRAW_LINE +#property indicator_type2 DRAW_LINE +#property indicator_color1 Blue +#property indicator_color2 Red +#property indicator_label1 "Upper band" +#property indicator_label2 "Lower band" +//--- input parameters +input int InpMAPeriod=14; // Period +input int InpMAShift=0; // Shift +input ENUM_MA_METHOD InpMAMethod=MODE_SMA; // Method +input ENUM_APPLIED_PRICE InpAppliedPrice=PRICE_CLOSE; // Applied price +input double InpDeviation=0.1; // Deviation +//--- indicator buffers +double ExtUpBuffer[]; +double ExtDownBuffer[]; +double ExtMABuffer[]; +//--- MA handle +int ExtMAHandle; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- indicator buffers mapping + SetIndexBuffer(0,ExtUpBuffer,INDICATOR_DATA); + SetIndexBuffer(1,ExtDownBuffer,INDICATOR_DATA); + SetIndexBuffer(2,ExtMABuffer,INDICATOR_CALCULATIONS); +//--- + IndicatorSetInteger(INDICATOR_DIGITS,_Digits+1); +//--- sets first bar from what index will be drawn + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,InpMAPeriod-1); +//--- name for DataWindow + IndicatorSetString(INDICATOR_SHORTNAME,"Env("+string(InpMAPeriod)+")"); + PlotIndexSetString(0,PLOT_LABEL,"Env("+string(InpMAPeriod)+")Upper"); + PlotIndexSetString(1,PLOT_LABEL,"Env("+string(InpMAPeriod)+")Lower"); +//---- line shifts when drawing + PlotIndexSetInteger(0,PLOT_SHIFT,InpMAShift); + PlotIndexSetInteger(1,PLOT_SHIFT,InpMAShift); +//--- + ExtMAHandle=iMA(NULL,0,InpMAPeriod,0,InpMAMethod,InpAppliedPrice); +//--- initialization done + } +//+------------------------------------------------------------------+ +//| Envelopes | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { + int i,limit; +//--- check for bars count + if(rates_totalrates_total || prev_calculated<0) to_copy=rates_total; + else + { + to_copy=rates_total-prev_calculated; + if(prev_calculated>0) to_copy++; + } +//---- get ma buffer + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtMAHandle,0,0,to_copy,ExtMABuffer)<=0) + { + Print("Getting MA data is failed! Error",GetLastError()); + return(0); + } +//--- preliminary calculations + limit=prev_calculated-1; + if(limitrates_total || prev_calculated<0) to_copy=rates_total; + else + { + to_copy=rates_total-prev_calculated; + if(prev_calculated>0) to_copy++; + } +//---- get ma buffer + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtMAHandle,0,0,to_copy,ExtMABuffer)<=0) + { + Print("Getting MA data is failed! Error",GetLastError()); + return(0); + } +//--- preliminary calculations + if(prev_calculatedhigh[i+1] && high[i]>high[i+2] && high[i]>=high[i-1] && high[i]>=high[i-2]) + ExtUpperBuffer[i]=high[i]; + else ExtUpperBuffer[i]=EMPTY_VALUE; + + //---- Lower Fractal + if(low[i]InpTeethPeriod>InpLipsPeriod; +// 2.InpJawsShift>InpTeethShift>InpLipsShift; +// 3.InpJawsPeriod>InpJawsShift; +// 4.InpTeethPeriod>InpTeethShift; +// 5.InpLipsPeriod>InpLipsShift. +//******************************************************************** +//--- indicator settings +#property indicator_separate_window +#property indicator_buffers 7 +#property indicator_plots 2 +#property indicator_type1 DRAW_COLOR_HISTOGRAM +#property indicator_type2 DRAW_COLOR_HISTOGRAM +#property indicator_color1 Green,Red +#property indicator_color2 Green,Red +#property indicator_width1 2 +#property indicator_width2 2 +#property indicator_label1 "Gator Upper" +#property indicator_label2 "Gator Lower" +//--- input parameters +input int InpJawsPeriod=13; // Jaws period +input int InpJawsShift=8; // Jaws shift +input int InpTeethPeriod=8; // Teeth period +input int InpTeethShift=5; // Teeth shift +input int InpLipsPeriod=5; // Lips period +input int InpLipsShift=3; // Lips shift +input ENUM_MA_METHOD InpMAMethod=MODE_SMMA; // Moving average method +input ENUM_APPLIED_PRICE InpAppliedPrice=PRICE_MEDIAN; // Applied price +//--- indicator buffers +double ExtUpperBuffer[]; +double ExtUpColorsBuffer[]; +double ExtLowerBuffer[]; +double ExtLoColorsBuffer[]; +double ExtJawsBuffer[]; +double ExtTeethBuffer[]; +double ExtLipsBuffer[]; +//--- handles +int ExtJawsHandle; +int ExtTeethHandle; +int ExtLipsHandle; +//--- global variables +int ExtUpperShift; +int ExtLowerShift; +bool ExtFlag; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- indicator buffers mapping + SetIndexBuffer(0,ExtUpperBuffer,INDICATOR_DATA); + SetIndexBuffer(1,ExtUpColorsBuffer,INDICATOR_COLOR_INDEX); + SetIndexBuffer(2,ExtLowerBuffer,INDICATOR_DATA); + SetIndexBuffer(3,ExtLoColorsBuffer,INDICATOR_COLOR_INDEX); +//--- MAs + SetIndexBuffer(4,ExtJawsBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(5,ExtTeethBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(6,ExtLipsBuffer,INDICATOR_CALCULATIONS); +//--- get handles + ExtJawsHandle=iMA(NULL,0,InpJawsPeriod,0,InpMAMethod,InpAppliedPrice); + ExtTeethHandle=iMA(NULL,0,InpTeethPeriod,0,InpMAMethod,InpAppliedPrice); + ExtLipsHandle=iMA(NULL,0,InpLipsPeriod,0,InpMAMethod,InpAppliedPrice); +//--- set indicator digits + IndicatorSetInteger(INDICATOR_DIGITS,_Digits+1); +//--- sets first bar from what index will be drawn + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,InpTeethShift+InpTeethPeriod); + PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,InpLipsShift+InpLipsPeriod); +//--- line shifts when drawing + PlotIndexSetInteger(0,PLOT_SHIFT,InpTeethShift); + PlotIndexSetInteger(1,PLOT_SHIFT,InpLipsShift); +//--- name for indicator subwindow label + IndicatorSetString(INDICATOR_SHORTNAME,"Gator("+ + string(InpJawsPeriod)+","+ + string(InpTeethPeriod)+","+ + string(InpLipsPeriod)+")"); +//--- sets drawing line empty value + PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); + PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0); +//--- calculate global variables values + ExtUpperShift=InpJawsShift-InpTeethShift; + ExtLowerShift=InpTeethShift-InpLipsShift; +//--- check for input parameters + ExtFlag=CheckForInput(); + if(!ExtFlag) Print("Wrong input parameters. Indicator won't work."); +//--- initialization done. 0 returned if ExtFlag is true + return(!ExtFlag); + } +//+------------------------------------------------------------------+ +//| Gator Oscillator | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { + int pos,shift; + double dCurr,dPrev; +//--- check for rules and bars count + if(ExtUpperShift>ExtLowerShift) + shift=ExtUpperShift; + else shift=ExtLowerShift; + if(!ExtFlag || shift>rates_total) + return(0); +//--- not all data may be calculated + int calculated=BarsCalculated(ExtJawsHandle); + if(calculatedrates_total || prev_calculated<0) to_copy=rates_total; + else + { + to_copy=rates_total-prev_calculated; + if(prev_calculated>0) to_copy++; + } +//---- get ma buffers + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtJawsHandle,0,0,to_copy,ExtJawsBuffer)<=0) + { + Print("getting ExtJawsHandle is failed! Error",GetLastError()); + return(0); + } + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtTeethHandle,0,0,to_copy,ExtTeethBuffer)<=0) + { + Print("getting ExtTeethHandle is failed! Error",GetLastError()); + return(0); + } + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtLipsHandle,0,0,to_copy,ExtLipsBuffer)<=0) + { + Print("getting ExtLipsHandle is failed! Error",GetLastError()); + return(0); + } +//--- last 2 counted bars will be recounted + pos=prev_calculated-2; + if(pos=lower_limit) + { + //--- calculate down buffer value + dCurr=-fabs(ExtTeethBuffer[i-ExtLowerShift]-ExtLipsBuffer[i]); + dPrev=ExtLowerBuffer[i-1]; + ExtLowerBuffer[i]=dCurr; + //--- set down buffer color + if(dPrev==dCurr) + ExtLoColorsBuffer[i]=ExtLoColorsBuffer[i-1]; + else + { + if(dPrev=upper_limit) + { + //--- calculate up buffer value + dCurr=fabs(ExtJawsBuffer[i-ExtUpperShift]-ExtTeethBuffer[i]); + ExtUpperBuffer[i]=dCurr; + dPrev=ExtUpperBuffer[i-1]; + //--- set up buffer color + if(dPrev==dCurr) + ExtUpColorsBuffer[i]=ExtUpColorsBuffer[i-1]; + else + { + if(dPrevInpTeethPeriod>InpLipsPeriod; | +//| 2.InpJawsShift>InpTeethShift>InpLipsShift; | +//| 3.InpJawsPeriod>InpJawsShift; | +//| 4.InpTeethPeriod>InpTeethShift; | +//| 5.InpLipsPeriod>InpLipsShift. | +//+------------------------------------------------------------------+ +bool CheckForInput() + { +//--- 1 + if(InpJawsPeriod<=InpTeethPeriod || InpTeethPeriod<=InpLipsPeriod) + return(false); +//--- 2 + if(InpJawsShift<=InpTeethShift || InpTeethShift<=InpLipsShift) + return(false); +//--- 3 + if(InpJawsPeriod<=InpJawsShift) + return(false); +//--- 4 + if(InpTeethPeriod<=InpTeethShift) + return(false); +//--- 5 + if(InpLipsPeriod<=InpLipsShift) + return(false); +//--- all right + return(true); + } +//+------------------------------------------------------------------+ diff --git a/Indicators/Examples/Gator_2.mq5 b/Indicators/Examples/Gator_2.mq5 new file mode 100644 index 0000000..04059bf --- /dev/null +++ b/Indicators/Examples/Gator_2.mq5 @@ -0,0 +1,248 @@ +//+------------------------------------------------------------------+ +//| Gator.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +#property description "Gator Oscillator" +#property description "based on shifted Alligator buffers" +//******************************************************************** +// Attention! Following correlations must be obeyed: +// 1.InpJawsPeriod>InpTeethPeriod>InpLipsPeriod; +// 2.InpJawsShift>InpTeethShift>InpLipsShift; +// 3.InpJawsPeriod>InpJawsShift; +// 4.InpTeethPeriod>InpTeethShift; +// 5.InpLipsPeriod>InpLipsShift. +//******************************************************************** +//--- indicator settings +#property indicator_separate_window +#property indicator_buffers 7 +#property indicator_plots 2 +#property indicator_type1 DRAW_COLOR_HISTOGRAM +#property indicator_type2 DRAW_COLOR_HISTOGRAM +#property indicator_color1 Green,Red +#property indicator_color2 Green,Red +#property indicator_width1 2 +#property indicator_width2 2 +#property indicator_label1 "Gator Upper" +#property indicator_label2 "Gator Lower" +//--- input parameters +input int InpJawsPeriod=13; // Jaws period +input int InpJawsShift=8; // Jaws shift +input int InpTeethPeriod=8; // Teeth period +input int InpTeethShift=5; // Teeth shift +input int InpLipsPeriod=5; // Lips period +input int InpLipsShift=3; // Lips shift +input ENUM_MA_METHOD InpMAMethod=MODE_SMMA; // Moving average method +input ENUM_APPLIED_PRICE InpAppliedPrice=PRICE_MEDIAN; // Applied price +//--- indicator buffers +double ExtUpperBuffer[]; +double ExtUpColorsBuffer[]; +double ExtLowerBuffer[]; +double ExtLoColorsBuffer[]; +double ExtJawsBuffer[]; +double ExtTeethBuffer[]; +double ExtLipsBuffer[]; +//--- handle +int ExtAlligatorHandle; +//--- global variables +int ExtUpperShift; +int ExtLowerShift; +bool ExtFlag; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- indicator buffers mapping + SetIndexBuffer(0,ExtUpperBuffer,INDICATOR_DATA); + SetIndexBuffer(1,ExtUpColorsBuffer,INDICATOR_COLOR_INDEX); + SetIndexBuffer(2,ExtLowerBuffer,INDICATOR_DATA); + SetIndexBuffer(3,ExtLoColorsBuffer,INDICATOR_COLOR_INDEX); +//--- MAs + SetIndexBuffer(4,ExtJawsBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(5,ExtTeethBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(6,ExtLipsBuffer,INDICATOR_CALCULATIONS); +//--- get handles + ExtAlligatorHandle=iAlligator(NULL,0, + InpJawsPeriod,0, + InpTeethPeriod,0, + InpLipsPeriod,0, + InpMAMethod,InpAppliedPrice); +//--- set indicator digits + IndicatorSetInteger(INDICATOR_DIGITS,_Digits+1); +//--- sets first bar from what index will be drawn + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,InpTeethShift+InpTeethPeriod); + PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,InpLipsShift+InpLipsPeriod); +//--- line shifts when drawing + PlotIndexSetInteger(0,PLOT_SHIFT,InpTeethShift); + PlotIndexSetInteger(1,PLOT_SHIFT,InpLipsShift); +//--- name for indicator subwindow label + IndicatorSetString(INDICATOR_SHORTNAME,"Gator("+ + string(InpJawsPeriod)+","+ + string(InpTeethPeriod)+","+ + string(InpLipsPeriod)+")"); +//--- sets drawing line empty value + PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); + PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0); +//--- calculate global variables values + ExtUpperShift=InpJawsShift-InpTeethShift; + ExtLowerShift=InpTeethShift-InpLipsShift; +//--- check for input parameters + ExtFlag=CheckForInput(); + if(!ExtFlag) Print("Wrong input parameters. Indicator won't work."); +//--- initialization done. 0 returned if ExtFlag is true + return(ExtFlag?0:1); + } +//+------------------------------------------------------------------+ +//| Gator Oscillator | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { + int pos,shift; + double dCurr,dPrev; +//--- check for rules and bars count + if(ExtUpperShift>ExtLowerShift) + shift=ExtUpperShift; + else shift=ExtLowerShift; + if(!ExtFlag || shift>rates_total) + return(0); +//--- not all data may be calculated + int calculated=BarsCalculated(ExtAlligatorHandle); + if(calculatedrates_total || prev_calculated<0) to_copy=rates_total; + else + { + to_copy=rates_total-prev_calculated; + if(prev_calculated>0) to_copy++; + } +//---- get ma buffers + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtAlligatorHandle,0,0,to_copy,ExtJawsBuffer)<=0) + { + Print("getting ExtAlligatorHandle buffer 0 is failed! Error",GetLastError()); + return(0); + } + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtAlligatorHandle,1,0,to_copy,ExtTeethBuffer)<=0) + { + Print("getting ExtAlligatorHandle buffer 1 is failed! Error",GetLastError()); + return(0); + } + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtAlligatorHandle,2,0,to_copy,ExtLipsBuffer)<=0) + { + Print("getting ExtAlligatorHandle buffer 2 is failed! Error",GetLastError()); + return(0); + } +//--- last counted bar will be recounted + pos=prev_calculated-1; + if(pos=lower_limit) + { + //--- calculate down buffer value + dCurr=-fabs(ExtTeethBuffer[i-ExtLowerShift]-ExtLipsBuffer[i]); + dPrev=ExtLowerBuffer[i-1]; + ExtLowerBuffer[i]=dCurr; + //--- set down buffer color + if(dPrev==dCurr) + ExtLoColorsBuffer[i]=ExtLoColorsBuffer[i-1]; + else + { + if(dPrev=upper_limit) + { + //--- calculate up buffer value + dCurr=fabs(ExtJawsBuffer[i-ExtUpperShift]-ExtTeethBuffer[i]); + ExtUpperBuffer[i]=dCurr; + dPrev=ExtUpperBuffer[i-1]; + //--- set up buffer color + if(dPrev==dCurr) + ExtUpColorsBuffer[i]=ExtUpColorsBuffer[i-1]; + else + { + if(dPrevInpTeethPeriod>InpLipsPeriod; | +//| 2.InpJawsShift>InpTeethShift>InpLipsShift; | +//| 3.InpJawsPeriod>InpJawsShift; | +//| 4.InpTeethPeriod>InpTeethShift; | +//| 5.InpLipsPeriod>InpLipsShift. | +//+------------------------------------------------------------------+ +bool CheckForInput() + { +//--- 1 + if(InpJawsPeriod<=InpTeethPeriod || InpTeethPeriod<=InpLipsPeriod) + return(false); +//--- 2 + if(InpJawsShift<=InpTeethShift || InpTeethShift<=InpLipsShift) + return(false); +//--- 3 + if(InpJawsPeriod<=InpJawsShift) + return(false); +//--- 4 + if(InpTeethPeriod<=InpTeethShift) + return(false); +//--- 5 + if(InpLipsPeriod<=InpLipsShift) + return(false); +//--- all right + return(true); + } +//+------------------------------------------------------------------+ diff --git a/Indicators/Examples/Heiken_Ashi.mq5 b/Indicators/Examples/Heiken_Ashi.mq5 new file mode 100644 index 0000000..955a81f --- /dev/null +++ b/Indicators/Examples/Heiken_Ashi.mq5 @@ -0,0 +1,88 @@ + +//+------------------------------------------------------------------+ +//| Heiken_Ashi.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +//--- indicator settings +#property indicator_chart_window +#property indicator_buffers 5 +#property indicator_plots 1 +#property indicator_type1 DRAW_COLOR_CANDLES +#property indicator_color1 DodgerBlue, Red +#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close" +//--- indicator buffers +double ExtOBuffer[]; +double ExtHBuffer[]; +double ExtLBuffer[]; +double ExtCBuffer[]; +double ExtColorBuffer[]; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- indicator buffers mapping + SetIndexBuffer(0,ExtOBuffer,INDICATOR_DATA); + SetIndexBuffer(1,ExtHBuffer,INDICATOR_DATA); + SetIndexBuffer(2,ExtLBuffer,INDICATOR_DATA); + SetIndexBuffer(3,ExtCBuffer,INDICATOR_DATA); + SetIndexBuffer(4,ExtColorBuffer,INDICATOR_COLOR_INDEX); +//--- + IndicatorSetInteger(INDICATOR_DIGITS,_Digits); +//--- sets first bar from what index will be drawn + IndicatorSetString(INDICATOR_SHORTNAME,"Heiken Ashi"); +//--- sets drawing line empty value + PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); +//--- initialization done + } +//+------------------------------------------------------------------+ +//| Heiken Ashi | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { + int i,limit; +//--- preliminary calculations + if(prev_calculated==0) + { + //--- set first candle + ExtLBuffer[0]=low[0]; + ExtHBuffer[0]=high[0]; + ExtOBuffer[0]=open[0]; + ExtCBuffer[0]=close[0]; + limit=1; + } + else limit=prev_calculated-1; + +//--- the main loop of calculations + for(i=limit;ifromIndex-range && i>=0;i--) + { + if(resfromIndex-range && i>=0;i--) + { + if(res>array[i]) res=array[i]; + } +//--- + return(res); + } +//+------------------------------------------------------------------+ +//| Ichimoku Kinko Hyo | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { + int limit; +//--- + if(prev_calculated==0) limit=0; + else limit=prev_calculated-1; +//--- + for(int i=limit;i +//--- indicator settings +#property indicator_separate_window +#property indicator_buffers 4 +#property indicator_plots 2 +#property indicator_type1 DRAW_HISTOGRAM +#property indicator_type2 DRAW_LINE +#property indicator_color1 Silver +#property indicator_color2 Red +#property indicator_width1 2 +#property indicator_width2 1 +#property indicator_label1 "MACD" +#property indicator_label2 "Signal" +//--- input parameters +input int InpFastEMA=12; // Fast EMA period +input int InpSlowEMA=26; // Slow EMA period +input int InpSignalSMA=9; // Signal SMA period +input ENUM_APPLIED_PRICE InpAppliedPrice=PRICE_CLOSE; // Applied price +//--- indicator buffers +double ExtMacdBuffer[]; +double ExtSignalBuffer[]; +double ExtFastMaBuffer[]; +double ExtSlowMaBuffer[]; +//--- MA handles +int ExtFastMaHandle; +int ExtSlowMaHandle; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- indicator buffers mapping + SetIndexBuffer(0,ExtMacdBuffer,INDICATOR_DATA); + SetIndexBuffer(1,ExtSignalBuffer,INDICATOR_DATA); + SetIndexBuffer(2,ExtFastMaBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(3,ExtSlowMaBuffer,INDICATOR_CALCULATIONS); +//--- sets first bar from what index will be drawn + PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,InpSignalSMA-1); +//--- name for Dindicator subwindow label + IndicatorSetString(INDICATOR_SHORTNAME,"MACD("+string(InpFastEMA)+","+string(InpSlowEMA)+","+string(InpSignalSMA)+")"); +//--- get MA handles + ExtFastMaHandle=iMA(NULL,0,InpFastEMA,0,MODE_EMA,InpAppliedPrice); + ExtSlowMaHandle=iMA(NULL,0,InpSlowEMA,0,MODE_EMA,InpAppliedPrice); +//--- initialization done + } +//+------------------------------------------------------------------+ +//| Moving Averages Convergence/Divergence | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { +//--- check for data + if(rates_totalrates_total || prev_calculated<0) to_copy=rates_total; + else + { + to_copy=rates_total-prev_calculated; + if(prev_calculated>0) to_copy++; + } +//--- get Fast EMA buffer + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtFastMaHandle,0,0,to_copy,ExtFastMaBuffer)<=0) + { + Print("Getting fast EMA is failed! Error",GetLastError()); + return(0); + } +//--- get SlowSMA buffer + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtSlowMaHandle,0,0,to_copy,ExtSlowMaBuffer)<=0) + { + Print("Getting slow SMA is failed! Error",GetLastError()); + return(0); + } +//--- + int limit; + if(prev_calculated==0) + limit=0; + else limit=prev_calculated-1; +//--- calculate MACD + for(int i=limit;idPreviousTP) dPositiveMF+=VolBuffer[index+1]*dCurrentTP; + if(dCurrentTP +//--- indicator settings +#property indicator_separate_window +#property indicator_buffers 4 +#property indicator_plots 1 +#property indicator_type1 DRAW_LINE +#property indicator_color1 DodgerBlue +#property indicator_level1 27 +#property indicator_level2 26.5 +#property indicator_levelcolor DarkGray +//--- input parametrs +input int InpPeriodEMA=9; // First EMA period +input int InpSecondPeriodEMA=9; // Second EMA period +input int InpSumPeriod=25; // Mass period +//--- global variables +int ExtPeriodEMA; +int ExtSecondPeriodEMA; +int ExtSumPeriod; +//---- indicator buffers +double ExtHLBuffer[]; +double ExtEHLBuffer[]; +double ExtEEHLBuffer[]; +double ExtMIBuffer[]; +//+------------------------------------------------------------------+ +//| MI initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- check input variables + if(InpPeriodEMA<=0) + { + ExtPeriodEMA=9; + printf("Incorrect value for input variable InpPeriodEMA=%d. Indicator will use value=%d for calculations.", + InpPeriodEMA,ExtPeriodEMA); + } + else ExtPeriodEMA=InpPeriodEMA; + if(InpSecondPeriodEMA<=0) + { + ExtSecondPeriodEMA=9; + printf("Incorrect value for input variable InpSecondPeriodEMA=%d. Indicator will use value=%d for calculations.", + InpSecondPeriodEMA,ExtSecondPeriodEMA); + } + else ExtSecondPeriodEMA=InpSecondPeriodEMA; + if(InpSumPeriod<=0) + { + ExtSumPeriod=25; + printf("Incorrect value for input variable PeriodSum=%d. Indicator will use value=%d for calculations.", + InpSumPeriod,ExtSumPeriod); + } + else ExtSumPeriod=InpSumPeriod; +//--- define buffers + SetIndexBuffer(0,ExtMIBuffer); + SetIndexBuffer(1,ExtEHLBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(2,ExtEEHLBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(3,ExtHLBuffer,INDICATOR_CALCULATIONS); +//--- number of digits of indicator value + IndicatorSetInteger(INDICATOR_DIGITS,2); +//--- name for DataWindow and indicator subwindow label + IndicatorSetString(INDICATOR_SHORTNAME,"Mass Index("+string(ExtPeriodEMA)+","+string(ExtSecondPeriodEMA)+","+string(ExtSumPeriod)+")"); + PlotIndexSetString(0,PLOT_LABEL,"MI("+string(ExtPeriodEMA)+","+string(ExtSecondPeriodEMA)+","+string(ExtSumPeriod)+")"); +//--- indexes draw begin settings + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,ExtPeriodEMA+ExtSecondPeriodEMA+ExtSumPeriod-3); +//---- OnInit done + } +//+------------------------------------------------------------------+ +//| Mass Index | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { +//--- check for bars count + int posMI=ExtSumPeriod+ExtPeriodEMA+ExtSecondPeriodEMA-3; + if(rates_total=posMI;j++) + if(ExtEEHLBuffer[i-j]!=0.0) + dTmp+=ExtEHLBuffer[i-j]/ExtEEHLBuffer[i-j]; + ExtMIBuffer[i]=dTmp; + } +//---- OnCalculate done. Return new prev_calculated. + return(rates_total); + } +//+------------------------------------------------------------------+ diff --git a/Indicators/Examples/MarketFacilitationIndex.mq5 b/Indicators/Examples/MarketFacilitationIndex.mq5 new file mode 100644 index 0000000..8dd0b07 --- /dev/null +++ b/Indicators/Examples/MarketFacilitationIndex.mq5 @@ -0,0 +1,125 @@ +//+------------------------------------------------------------------+ +//| MarketFacilitationIndex.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +//--- indicator settings +#property indicator_separate_window +#property indicator_buffers 2 +#property indicator_plots 1 +#property indicator_type1 DRAW_COLOR_HISTOGRAM +#property indicator_color1 Lime,SaddleBrown,Blue,Pink +#property indicator_width1 2 +//--- input parameter +input ENUM_APPLIED_VOLUME InpVolumeType=VOLUME_TICK; // Volumes +//---- buffers +double ExtMFIBuffer[]; +double ExtColorBuffer[]; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//---- indicators + SetIndexBuffer(0,ExtMFIBuffer,INDICATOR_DATA); + SetIndexBuffer(1,ExtColorBuffer,INDICATOR_COLOR_INDEX); +//--- name for DataWindow + IndicatorSetString(INDICATOR_SHORTNAME,"BWMFI"); +//--- set accuracy + IndicatorSetInteger(INDICATOR_DIGITS,_Digits); +//---- + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void CalculateMFI(const int start,const int rates_total, + const double &high[], + const double &low[], + const long &volume[]) + { + int i=start; + bool mfi_up=true,vol_up=true; +//--- calculate first values of mfi_up and vol_up + if(i>0) + { + int n=i; + while(n>0) + { + if(ExtMFIBuffer[n]>ExtMFIBuffer[n-1]) { mfi_up=true; break; } + if(ExtMFIBuffer[n]0) + { + if(volume[n]>volume[n-1]) { vol_up=true; break; } + if(volume[n]0) ExtMFIBuffer[i]=ExtMFIBuffer[i-1]; + else ExtMFIBuffer[i]=0; + } + else ExtMFIBuffer[i]=(high[i]-low[i])/_Point/volume[i]; + //--- calculate changes + if(i>0) + { + if(ExtMFIBuffer[i]>ExtMFIBuffer[i-1]) mfi_up=true; + if(ExtMFIBuffer[i]volume[i-1]) vol_up=true; + if(volume[i]1) + { + datetime ctm=TimeTradeServer(),lasttm=time[rates_total-1],nexttm=lasttm+datetime(PeriodSeconds()); + if(ctm=lasttm && nexttm!=lasttm) + { + double correction_koef=double(1+ctm-lasttm)/double(nexttm-lasttm); + ExtMFIBuffer[rates_total-1]*=correction_koef; + } + } +//--- + return(rates_total); + } +//+------------------------------------------------------------------+ \ No newline at end of file diff --git a/Indicators/Examples/Momentum.mq5 b/Indicators/Examples/Momentum.mq5 new file mode 100644 index 0000000..1e8122c --- /dev/null +++ b/Indicators/Examples/Momentum.mq5 @@ -0,0 +1,70 @@ +//+------------------------------------------------------------------+ +//| Momentum.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +//---- indicator settings +#property indicator_separate_window +#property indicator_buffers 1 +#property indicator_plots 1 +#property indicator_type1 DRAW_LINE +#property indicator_color1 DodgerBlue +//---- input parameters +input int InpMomentumPeriod=14; // Period +//---- indicator buffers +double ExtMomentumBuffer[]; +//--- global variable +int ExtMomentumPeriod; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- check for input value + if(InpMomentumPeriod<0) + { + ExtMomentumPeriod=14; + Print("Input parameter InpMomentumPeriod has wrong value. Indicator will use value ",ExtMomentumPeriod); + } + else ExtMomentumPeriod=InpMomentumPeriod; +//---- buffers + SetIndexBuffer(0,ExtMomentumBuffer,INDICATOR_DATA); +//---- name for DataWindow and indicator subwindow label + IndicatorSetString(INDICATOR_SHORTNAME,"Momentum"+"("+string(ExtMomentumPeriod)+")"); +//--- sets first bar from what index will be drawn + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,ExtMomentumPeriod-1); +//--- sets drawing line empty value + PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); +//--- digits + IndicatorSetInteger(INDICATOR_DIGITS,2); + } +//+------------------------------------------------------------------+ +//| Momentum | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const int begin, + const double &price[]) + { +//--- start calculation + int StartCalcPosition=(ExtMomentumPeriod-1)+begin; +//---- insufficient data + if(rates_total0) PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,StartCalcPosition+(ExtMomentumPeriod-1)); +//--- start working, detect position + int pos=prev_calculated-1; + if(posPrevClose) ExtOBVBuffer[i]=ExtOBVBuffer[i-1]+Volume; + else ExtOBVBuffer[i]=ExtOBVBuffer[i-1]; + } + } + } +//+------------------------------------------------------------------+ diff --git a/Indicators/Examples/OsMA.mq5 b/Indicators/Examples/OsMA.mq5 new file mode 100644 index 0000000..614a611 --- /dev/null +++ b/Indicators/Examples/OsMA.mq5 @@ -0,0 +1,126 @@ +//+------------------------------------------------------------------+ +//| OsMA.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +#property description "Moving Average of Oscillator" +#property description "aka MACD histogram" +#include +//--- indicator settings +#property indicator_separate_window +#property indicator_buffers 5 +#property indicator_plots 1 +#property indicator_type1 DRAW_HISTOGRAM +#property indicator_color1 Silver +#property indicator_width1 2 +//--- input parameters +input int InpFastEMAPeriod=12; // Fast EMA period +input int InpSlowEMAPeriod=26; // Slow EMA period +input int InpSignalSMAPeriod=9; // Signal SMA period +input ENUM_APPLIED_PRICE InpAppliedPrice=PRICE_CLOSE; // Applied price +//--- indicator buffers +double ExtOsMABuffer[]; +double ExtMacdBuffer[]; +double ExtSignalBuffer[]; +double ExtFastMaBuffer[]; +double ExtSlowMaBuffer[]; +//--- MA handles +int ExtFastMaHandle; +int ExtSlowMaHandle; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- indicator buffers mapping + SetIndexBuffer(0,ExtOsMABuffer,INDICATOR_DATA); + SetIndexBuffer(1,ExtMacdBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(2,ExtSignalBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(3,ExtFastMaBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(4,ExtSlowMaBuffer,INDICATOR_CALCULATIONS); + IndicatorSetInteger(INDICATOR_DIGITS,_Digits+2); +//--- sets first bar from what index will be drawn + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,InpSlowEMAPeriod+InpSignalSMAPeriod-2); +//--- name for DataWindow and indicator subwindow label + IndicatorSetString(INDICATOR_SHORTNAME,"OsMA("+string(InpFastEMAPeriod)+","+string(InpSlowEMAPeriod)+","+string(InpSignalSMAPeriod)+")"); + PlotIndexSetString(0,PLOT_LABEL,"OsMA"); +//--- get MAs handles + ExtFastMaHandle=iMA(NULL,0,InpFastEMAPeriod,0,MODE_EMA,InpAppliedPrice); + ExtSlowMaHandle=iMA(NULL,0,InpSlowEMAPeriod,0,MODE_EMA,InpAppliedPrice); +//--- initialization done + } +//+------------------------------------------------------------------+ +//| Moving Average of Oscillator | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { + if(rates_totalrates_total || prev_calculated<0) to_copy=rates_total; + else + { + to_copy=rates_total-prev_calculated; + if(prev_calculated>0) to_copy++; + } +//--- get Fast EMA buffer + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtFastMaHandle,0,0,to_copy,ExtFastMaBuffer)<=0) + { + Print("Getting fast EMA is failed! Error",GetLastError()); + return(0); + } +//--- get SlowSMA buffer + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtSlowMaHandle,0,0,to_copy,ExtSlowMaBuffer)<=0) + { + Print("Getting slow SMA is failed! Error",GetLastError()); + return(0); + } +//--- + int i,limit; + if(prev_calculated==0) + limit=0; + else limit=prev_calculated-1; +//--- the main loop of calculations + for(i=limit;i +#include +#include +#include +#include +#include +//+------------------------------------------------------------------+ +//| defines | +//+------------------------------------------------------------------+ +//--- indents and gaps +#define INDENT_LEFT (11) // indent from left (with allowance for border width) +#define INDENT_TOP (11) // indent from top (with allowance for border width) +#define INDENT_RIGHT (11) // indent from right (with allowance for border width) +#define INDENT_BOTTOM (11) // indent from bottom (with allowance for border width) +#define CONTROLS_GAP_X (10) // gap by X coordinate +#define CONTROLS_GAP_Y (10) // gap by Y coordinate +//--- for combo boxes +#define COMBOBOX_WIDTH (100) // size by X coordinate +#define COMBOBOX_HEIGHT (20) // size by Y coordinate +//--- for spin edit +#define SPINEDIT_WIDTH (50) // size by X coordinate +//+------------------------------------------------------------------+ +//| Class CPanelDialog | +//| Usage: main dialog of the Controls application | +//+------------------------------------------------------------------+ +class CPanelDialog : public CAppDialog + { +private: + CChartObjectSubChart m_subchart; // the sub-chart object + CComboBox m_symbols; // the symbols combo box object + CComboBox m_periods; // the timeframes combo box object + CCheckBox m_time; // the time scale management object + CCheckBox m_price; // the price scale management object + CLabel m_label; // the label object + CSpinEdit m_scale; // the scale management object + +public: + CPanelDialog(void); + ~CPanelDialog(void); + //--- create + virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2); + //--- chart event handler + virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam); + +protected: + //--- create dependent controls + bool CreateSubchart(void); + bool CreateSymbols(void); + bool CreatePeriods(void); + bool CreateTime(void); + bool CreatePrice(void); + bool CreateLabel(void); + bool CreateScale(void); + //--- fill dependent controls + bool FillSymbols(void); + bool FillPeriods(void); + //--- internal event handlers + virtual bool OnResize(void); + //--- handlers of the dependent controls events + void OnChangeSymbols(void); + void OnChangePeriods(void); + void OnChangeTime(void); + void OnChangePrice(void); + void OnChangeScale(void); + //--- change dialog title + void SetCaption(void); + }; +//+------------------------------------------------------------------+ +//| Event Handling | +//+------------------------------------------------------------------+ +EVENT_MAP_BEGIN(CPanelDialog) +ON_EVENT(ON_CHANGE,m_symbols,OnChangeSymbols) +ON_EVENT(ON_CHANGE,m_periods,OnChangePeriods) +ON_EVENT(ON_CHANGE,m_time,OnChangeTime) +ON_EVENT(ON_CHANGE,m_price,OnChangePrice) +ON_EVENT(ON_CHANGE,m_scale,OnChangeScale) +EVENT_MAP_END(CAppDialog) +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CPanelDialog::CPanelDialog(void) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CPanelDialog::~CPanelDialog(void) + { + } +//+------------------------------------------------------------------+ +//| Create | +//+------------------------------------------------------------------+ +bool CPanelDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) + { + if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2)) + return(false); +//--- create dependent controls + if(!CreateSubchart()) + return(false); + if(!CreateTime()) + return(false); + if(!CreatePrice()) + return(false); + if(!CreateLabel()) + return(false); + if(!CreateScale()) + return(false); + if(!CreatePeriods()) + return(false); + if(!CreateSymbols()) + return(false); +//--- change dialog title + SetCaption(); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "Chart of Chart" object | +//+------------------------------------------------------------------+ +bool CPanelDialog::CreateSubchart(void) + { +//--- coordinates + int x=ClientAreaLeft()+INDENT_LEFT; + int y=ClientAreaTop()+INDENT_TOP; + int w=ClientAreaWidth()-(INDENT_RIGHT+COMBOBOX_WIDTH+CONTROLS_GAP_X+INDENT_LEFT); + int h=ClientAreaHeight()-(INDENT_BOTTOM+INDENT_TOP); +//--- create + if(!m_subchart.Create(m_chart_id,m_name,m_subwin,x,y,w,h)) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "Symbols" combo box | +//+------------------------------------------------------------------+ +bool CPanelDialog::CreateSymbols(void) + { +//--- coordinates + int x1=ClientAreaWidth()-(INDENT_RIGHT+COMBOBOX_WIDTH); + int y1=INDENT_TOP; + int x2=x1+COMBOBOX_WIDTH; + int y2=y1+COMBOBOX_HEIGHT; +//--- create + if(!m_symbols.Create(m_chart_id,m_name+"Symbols",m_subwin,x1,y1,x2,y2)) + return(false); + if(!Add(m_symbols)) + return(false); + m_symbols.Alignment(WND_ALIGN_RIGHT,0,0,INDENT_RIGHT,0); +//--- fill + if(!FillSymbols()) + return(false); +//--- select + m_symbols.SelectByText(Symbol()); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "Timeframes" combo box | +//+------------------------------------------------------------------+ +bool CPanelDialog::CreatePeriods(void) + { +//--- coordinates + int x1=ClientAreaWidth()-(INDENT_RIGHT+COMBOBOX_WIDTH); + int y1=INDENT_TOP+COMBOBOX_HEIGHT+CONTROLS_GAP_Y; + int x2=x1+COMBOBOX_WIDTH; + int y2=y1+COMBOBOX_HEIGHT; +//--- create + if(!m_periods.Create(m_chart_id,m_name+"Periods",m_subwin,x1,y1,x2,y2)) + return(false); + if(!Add(m_periods)) + return(false); + m_periods.Alignment(WND_ALIGN_RIGHT,0,0,INDENT_RIGHT,0); +//--- fill + if(!FillPeriods()) + return(false); +//--- select + m_periods.SelectByValue(Period()); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "Time scale" check box | +//+------------------------------------------------------------------+ +bool CPanelDialog::CreateTime(void) + { +//--- coordinates + int x1=ClientAreaWidth()-(INDENT_RIGHT+COMBOBOX_WIDTH); + int y1=INDENT_TOP+2*(COMBOBOX_HEIGHT+CONTROLS_GAP_Y); + int x2=x1+COMBOBOX_WIDTH; + int y2=y1+COMBOBOX_HEIGHT; +//--- create + if(!m_time.Create(m_chart_id,m_name+"Time",m_subwin,x1,y1,x2,y2)) + return(false); + if(!m_time.Text(" dates scale")) + return(false); + if(!Add(m_time)) + return(false); + m_time.Alignment(WND_ALIGN_RIGHT,0,0,INDENT_RIGHT,0); +//--- state + m_time.Checked(m_subchart.DateScale()); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "Price scale" check box | +//+------------------------------------------------------------------+ +bool CPanelDialog::CreatePrice(void) + { +//--- coordinates + int x1=ClientAreaWidth()-(INDENT_RIGHT+COMBOBOX_WIDTH); + int y1=INDENT_TOP+3*(COMBOBOX_HEIGHT+CONTROLS_GAP_Y); + int x2=x1+COMBOBOX_WIDTH; + int y2=y1+COMBOBOX_HEIGHT; +//--- create + if(!m_price.Create(m_chart_id,m_name+"Price",m_subwin,x1,y1,x2,y2)) + return(false); + if(!m_price.Text(" prices scale")) + return(false); + if(!Add(m_price)) + return(false); + m_price.Alignment(WND_ALIGN_RIGHT,0,0,INDENT_RIGHT,0); +//--- state + m_price.Checked(m_subchart.PriceScale()); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create label for the "Scale" spin edit | +//+------------------------------------------------------------------+ +bool CPanelDialog::CreateLabel(void) + { +//--- coordinates + int x1=ClientAreaWidth()-(INDENT_RIGHT+COMBOBOX_WIDTH); + int y1=INDENT_TOP+4*(COMBOBOX_HEIGHT+CONTROLS_GAP_Y); + int x2=x1+COMBOBOX_WIDTH-SPINEDIT_WIDTH; + int y2=y1+COMBOBOX_HEIGHT; +//--- create + if(!m_label.Create(m_chart_id,m_name+"Label",m_subwin,x1,y1,x2,y2)) + return(false); + if(!m_label.Text("Scale")) + return(false); + if(!Add(m_label)) + return(false); + m_label.Alignment(WND_ALIGN_RIGHT,0,0,INDENT_RIGHT+SPINEDIT_WIDTH,0); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "Scale" spin edit | +//+------------------------------------------------------------------+ +bool CPanelDialog::CreateScale(void) + { +//--- coordinates + int x1=ClientAreaWidth()-(INDENT_RIGHT+SPINEDIT_WIDTH); + int y1=INDENT_TOP+4*(COMBOBOX_HEIGHT+CONTROLS_GAP_Y); + int x2=x1+SPINEDIT_WIDTH; + int y2=y1+COMBOBOX_HEIGHT; +//--- create + if(!m_scale.Create(m_chart_id,m_name+"Scale",m_subwin,x1,y1,x2,y2)) + return(false); + if(!Add(m_scale)) + return(false); + m_scale.Alignment(WND_ALIGN_RIGHT,0,0,INDENT_RIGHT,0); +//--- set up + m_scale.MinValue(0); + m_scale.MaxValue(5); + m_scale.Value(m_subchart.Scale()); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Fill the "Symbols" combo box | +//+------------------------------------------------------------------+ +bool CPanelDialog::FillSymbols(void) + { + int total=SymbolsTotal(true); + for(int i=0;iArraySize(value)) + total=ArraySize(value); +//--- + for(int i=0;i +#include +#include +#include +#include +#include +#include +#include +//+------------------------------------------------------------------+ +//| defines | +//+------------------------------------------------------------------+ +//--- indents and gaps +#define INDENT_LEFT (11) // indent from left (with allowance for border width) +#define INDENT_TOP (11) // indent from top (with allowance for border width) +#define INDENT_RIGHT (11) // indent from right (with allowance for border width) +#define INDENT_BOTTOM (11) // indent from bottom (with allowance for border width) +#define CONTROLS_GAP_X (10) // gap by X coordinate +#define CONTROLS_GAP_Y (10) // gap by Y coordinate +//--- for buttons +#define BUTTON_WIDTH (100) // size by X coordinate +#define BUTTON_HEIGHT (20) // size by Y coordinate +//--- for the indication area +#define EDIT_HEIGHT (20) // size by Y coordinate +//+------------------------------------------------------------------+ +//| Class CPanelDialog | +//| Usage: main dialog of the SimplePanel application | +//+------------------------------------------------------------------+ +class CPanelDialog : public CAppDialog + { +private: + CEdit m_edit; // the display field object + CButton m_button1; // the button object + CButton m_button2; // the button object + CButton m_button3; // the fixed button object + CListView m_list_view; // the list object + CRadioGroup m_radio_group; // the radio buttons group object + CCheckGroup m_check_group; // the check box group object + +public: + CPanelDialog(void); + ~CPanelDialog(void); + //--- create + virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2); + //--- chart event handler + virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam); + +protected: + //--- create dependent controls + bool CreateEdit(void); + bool CreateButton1(void); + bool CreateButton2(void); + bool CreateButton3(void); + bool CreateRadioGroup(void); + bool CreateCheckGroup(void); + bool CreateListView(void); + //--- internal event handlers + virtual bool OnResize(void); + //--- handlers of the dependent controls events + void OnClickButton1(void); + void OnClickButton2(void); + void OnClickButton3(void); + void OnChangeRadioGroup(void); + void OnChangeCheckGroup(void); + void OnChangeListView(void); + }; +//+------------------------------------------------------------------+ +//| Event Handling | +//+------------------------------------------------------------------+ +EVENT_MAP_BEGIN(CPanelDialog) + ON_EVENT(ON_CLICK,m_button1,OnClickButton1) + ON_EVENT(ON_CLICK,m_button2,OnClickButton2) + ON_EVENT(ON_CLICK,m_button3,OnClickButton3) + ON_EVENT(ON_CHANGE,m_radio_group,OnChangeRadioGroup) + ON_EVENT(ON_CHANGE,m_check_group,OnChangeCheckGroup) + ON_EVENT(ON_CHANGE,m_list_view,OnChangeListView) +EVENT_MAP_END(CAppDialog) +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CPanelDialog::CPanelDialog(void) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CPanelDialog::~CPanelDialog(void) + { + } +//+------------------------------------------------------------------+ +//| Create | +//+------------------------------------------------------------------+ +bool CPanelDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) + { + if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2)) + return(false); +//--- create dependent controls + if(!CreateEdit()) + return(false); + if(!CreateButton1()) + return(false); + if(!CreateButton2()) + return(false); + if(!CreateButton3()) + return(false); + if(!CreateRadioGroup()) + return(false); + if(!CreateCheckGroup()) + return(false); + if(!CreateListView()) + return(false); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the display field | +//+------------------------------------------------------------------+ +bool CPanelDialog::CreateEdit(void) + { +//--- coordinates + int x1=INDENT_LEFT; + int y1=INDENT_TOP; + int x2=ClientAreaWidth()-(INDENT_RIGHT+BUTTON_WIDTH+CONTROLS_GAP_X); + int y2=y1+EDIT_HEIGHT; +//--- create + if(!m_edit.Create(m_chart_id,m_name+"Edit",m_subwin,x1,y1,x2,y2)) + return(false); + if(!m_edit.ReadOnly(true)) + return(false); + if(!Add(m_edit)) + return(false); + m_edit.Alignment(WND_ALIGN_WIDTH,INDENT_LEFT,0,INDENT_RIGHT+BUTTON_WIDTH+CONTROLS_GAP_X,0); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "Button1" button | +//+------------------------------------------------------------------+ +bool CPanelDialog::CreateButton1(void) + { +//--- coordinates + int x1=ClientAreaWidth()-(INDENT_RIGHT+BUTTON_WIDTH); + int y1=INDENT_TOP; + int x2=x1+BUTTON_WIDTH; + int y2=y1+BUTTON_HEIGHT; +//--- create + if(!m_button1.Create(m_chart_id,m_name+"Button1",m_subwin,x1,y1,x2,y2)) + return(false); + if(!m_button1.Text("Button1")) + return(false); + if(!Add(m_button1)) + return(false); + m_button1.Alignment(WND_ALIGN_RIGHT,0,0,INDENT_RIGHT,0); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "Button2" button | +//+------------------------------------------------------------------+ +bool CPanelDialog::CreateButton2(void) + { +//--- coordinates + int x1=ClientAreaWidth()-(INDENT_RIGHT+BUTTON_WIDTH); + int y1=INDENT_TOP+BUTTON_HEIGHT+CONTROLS_GAP_Y; + int x2=x1+BUTTON_WIDTH; + int y2=y1+BUTTON_HEIGHT; +//--- create + if(!m_button2.Create(m_chart_id,m_name+"Button2",m_subwin,x1,y1,x2,y2)) + return(false); + if(!m_button2.Text("Button2")) + return(false); + if(!Add(m_button2)) + return(false); + m_button2.Alignment(WND_ALIGN_RIGHT,0,0,INDENT_RIGHT,0); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "Button3" fixed button | +//+------------------------------------------------------------------+ +bool CPanelDialog::CreateButton3(void) + { +//--- coordinates + int x1=ClientAreaWidth()-(INDENT_RIGHT+BUTTON_WIDTH); + int y1=ClientAreaHeight()-(INDENT_BOTTOM+BUTTON_HEIGHT); + int x2=x1+BUTTON_WIDTH; + int y2=y1+BUTTON_HEIGHT; +//--- create + if(!m_button3.Create(m_chart_id,m_name+"Button3",m_subwin,x1,y1,x2,y2)) + return(false); + if(!m_button3.Text("Locked")) + return(false); + if(!Add(m_button3)) + return(false); + m_button3.Locking(true); + m_button3.Alignment(WND_ALIGN_RIGHT|WND_ALIGN_BOTTOM,0,0,INDENT_RIGHT,INDENT_BOTTOM); +//--- succeed + return(true); + } +//+------------------------------------------------------------------+ +//| Create the "RadioGroup" element | +//+------------------------------------------------------------------+ +bool CPanelDialog::CreateRadioGroup(void) + { + int sx=(ClientAreaWidth()-(INDENT_LEFT+INDENT_RIGHT+BUTTON_WIDTH))/3-CONTROLS_GAP_X; +//--- coordinates + int x1=INDENT_LEFT; + int y1=INDENT_TOP+EDIT_HEIGHT+CONTROLS_GAP_Y; + int x2=x1+sx; + int y2=ClientAreaHeight()-INDENT_BOTTOM; +//--- create + if(!m_radio_group.Create(m_chart_id,m_name+"RadioGroup",m_subwin,x1,y1,x2,y2)) + return(false); + if(!Add(m_radio_group)) + return(false); + m_radio_group.Alignment(WND_ALIGN_HEIGHT,0,y1,0,INDENT_BOTTOM); +//--- fill out with strings + for(int i=0;i<4;i++) + if(!m_radio_group.AddItem("Item "+IntegerToString(i),1<low[i]) + { + //--- switch to SHORT + ExtDirectionLong=false; + ExtSARBuffer[i]=GetHigh(i,ExtLastRevPos,high); + ExtEPBuffer[i]=low[i]; + ExtLastRevPos=i; + ExtAFBuffer[i]=ExtSarStep; + } + } + else + { + if(ExtSARBuffer[i]ExtEPBuffer[i-1] && i!=ExtLastRevPos) + { + ExtEPBuffer[i]=high[i]; + ExtAFBuffer[i]=ExtAFBuffer[i-1]+ExtSarStep; + if(ExtAFBuffer[i]>ExtSarMaximum) + ExtAFBuffer[i]=ExtSarMaximum; + } + else + { + //--- when we haven't reversed + if(i!=ExtLastRevPos) + { + ExtAFBuffer[i]=ExtAFBuffer[i-1]; + ExtEPBuffer[i]=ExtEPBuffer[i-1]; + } + } + //--- calculate SAR for tomorrow + ExtSARBuffer[i+1]=ExtSARBuffer[i]+ExtAFBuffer[i]*(ExtEPBuffer[i]-ExtSARBuffer[i]); + //--- check for SAR + if(ExtSARBuffer[i+1]>low[i] || ExtSARBuffer[i+1]>low[i-1]) + ExtSARBuffer[i+1]=MathMin(low[i],low[i-1]); + } + else + { + //--- check for new Low + if(low[i]ExtSarMaximum) + ExtAFBuffer[i]=ExtSarMaximum; + } + else + { + //--- when we haven't reversed + if(i!=ExtLastRevPos) + { + ExtAFBuffer[i]=ExtAFBuffer[i-1]; + ExtEPBuffer[i]=ExtEPBuffer[i-1]; + } + } + //--- calculate SAR for tomorrow + ExtSARBuffer[i+1]=ExtSARBuffer[i]+ExtAFBuffer[i]*(ExtEPBuffer[i]-ExtSARBuffer[i]); + //--- check for SAR + if(ExtSARBuffer[i+1]LoData[i]) result=LoData[i]; + return(result); + } +//+------------------------------------------------------------------+ diff --git a/Indicators/Examples/Price_Channel.mq5 b/Indicators/Examples/Price_Channel.mq5 new file mode 100644 index 0000000..86f79ed --- /dev/null +++ b/Indicators/Examples/Price_Channel.mq5 @@ -0,0 +1,113 @@ +//+------------------------------------------------------------------+ +//| Price_Channell.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +//--- indicator settings +#property indicator_chart_window +#property indicator_buffers 3 +#property indicator_plots 2 +#property indicator_type1 DRAW_FILLING +#property indicator_type2 DRAW_LINE +#property indicator_color1 DodgerBlue,Gray +#property indicator_color2 Blue +#property indicator_label1 "Channel upper;Channel lower" +#property indicator_label2 "Channel median" +//--- input parameters +input int InpChannelPeriod=22; // Period +//--- indicator buffers +double ExtHighBuffer[]; +double ExtLowBuffer[]; +double ExtMiddBuffer[]; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- indicator buffers mapping + SetIndexBuffer(0,ExtHighBuffer,INDICATOR_DATA); + SetIndexBuffer(1,ExtLowBuffer,INDICATOR_DATA); + SetIndexBuffer(2,ExtMiddBuffer,INDICATOR_DATA); +//--- set accuracy + IndicatorSetInteger(INDICATOR_DIGITS,_Digits); +//--- set first bar from what index will be drawn + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,InpChannelPeriod); +//---- line shifts when drawing + PlotIndexSetInteger(0,PLOT_SHIFT,1); + PlotIndexSetInteger(1,PLOT_SHIFT,1); +//--- name for DataWindow and indicator label + IndicatorSetString(INDICATOR_SHORTNAME,"Price Channel("+string(InpChannelPeriod)+")"); + PlotIndexSetString(0,PLOT_LABEL,"Channel("+string(InpChannelPeriod)+") upper;Channel("+string(InpChannelPeriod)+") lower"); + PlotIndexSetString(1,PLOT_LABEL,"Median("+string(InpChannelPeriod)+")"); +//--- set drawing line empty value + PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); + PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0); +//--- initialization done + } +//+------------------------------------------------------------------+ +//| get highest value for range | +//+------------------------------------------------------------------+ +double Highest(const double &array[],int range,int fromIndex) + { + double res; + int i; +//--- + res=array[fromIndex]; + for(i=fromIndex;i>fromIndex-range && i>=0;i--) + { + if(resfromIndex-range && i>=0;i--) + { + if(res>array[i]) res=array[i]; + } +//--- + return(res); + } +//+------------------------------------------------------------------+ +//| Price Channell | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { + int i,limit; +//--- check for rates + if(rates_total0?diff:0); + SumN+=(diff<0?-diff:0); + } + //--- calculate first visible value + ExtPosBuffer[ExtPeriodRSI]=SumP/ExtPeriodRSI; + ExtNegBuffer[ExtPeriodRSI]=SumN/ExtPeriodRSI; + if(ExtNegBuffer[ExtPeriodRSI]!=0.0) + ExtRSIBuffer[ExtPeriodRSI]=100.0-(100.0/(1.0+ExtPosBuffer[ExtPeriodRSI]/ExtNegBuffer[ExtPeriodRSI])); + else + { + if(ExtPosBuffer[ExtPeriodRSI]!=0.0) + ExtRSIBuffer[ExtPeriodRSI]=100.0; + else + ExtRSIBuffer[ExtPeriodRSI]=50.0; + } + //--- prepare the position value for main calculation + pos=ExtPeriodRSI+1; + } +//--- the main loop of calculations + for(i=pos;i0.0?diff:0.0))/ExtPeriodRSI; + ExtNegBuffer[i]=(ExtNegBuffer[i-1]*(ExtPeriodRSI-1)+(diff<0.0?-diff:0.0))/ExtPeriodRSI; + if(ExtNegBuffer[i]!=0.0) + ExtRSIBuffer[i]=100.0-100.0/(1+ExtPosBuffer[i]/ExtNegBuffer[i]); + else + { + if(ExtPosBuffer[i]!=0.0) + ExtRSIBuffer[i]=100.0; + else + ExtRSIBuffer[i]=50.0; + } + } +//--- OnCalculate done. Return new prev_calculated. + return(rates_total); + } +//+------------------------------------------------------------------+ diff --git a/Indicators/Examples/RVI.mq5 b/Indicators/Examples/RVI.mq5 new file mode 100644 index 0000000..6b9b92e --- /dev/null +++ b/Indicators/Examples/RVI.mq5 @@ -0,0 +1,101 @@ +//+------------------------------------------------------------------+ +//| RVI.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +#property description "Relative Vigor Index" +//--- indicator settings +#property indicator_separate_window +#property indicator_buffers 2 +#property indicator_plots 2 +#property indicator_type1 DRAW_LINE +#property indicator_type2 DRAW_LINE +#property indicator_color1 Green +#property indicator_color2 Red +#property indicator_label1 "RVI" +#property indicator_label2 "Signal" +//--- input parameters +input int InpRVIPeriod=10; // Period +//--- indicator buffers +double ExtRVIBuffer[]; +double ExtSignalBuffer[]; +//--- +#define TRIANGLE_PERIOD 3 +#define AVERAGE_PERIOD (TRIANGLE_PERIOD*2) +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- indicator buffers mapping + SetIndexBuffer(0,ExtRVIBuffer,INDICATOR_DATA); + SetIndexBuffer(1,ExtSignalBuffer,INDICATOR_DATA); + IndicatorSetInteger(INDICATOR_DIGITS,3); +//--- sets first bar from what index will be drawn + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,(InpRVIPeriod-1)+TRIANGLE_PERIOD); + PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,(InpRVIPeriod-1)+AVERAGE_PERIOD); +//--- name for DataWindow and indicator subwindow label + IndicatorSetString(INDICATOR_SHORTNAME,"RVI("+string(InpRVIPeriod)+")"); + PlotIndexSetString(0,PLOT_LABEL,"RVI("+string(InpRVIPeriod)+")"); + PlotIndexSetString(1,PLOT_LABEL,"Signal("+string(InpRVIPeriod)+")"); +//--- initialization done + } +//+------------------------------------------------------------------+ +//| Relative Vigor Index | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { + int i,j,nLimit; + double dValueUp,dValueDown,dNum,dDeNum; +//--- check for bars count + if(rates_total<=InpRVIPeriod+AVERAGE_PERIOD+2) return(0); // exit with zero result +//--- check for possible errors + if(prev_calculated<0) return(0); // exit with zero result +//--- last counted bar will be recounted + nLimit=InpRVIPeriod+2; + if(prev_calculated>InpRVIPeriod+TRIANGLE_PERIOD+2) + nLimit=prev_calculated-1; +//--- set empty value for uncalculated bars + if(prev_calculated==0) + { + for(i=0;ii-InpRVIPeriod;j--) + { + dValueUp=close[j]-open[j]+2*(close[j-1]-open[j-1])+2*(close[j-2]-open[j-2])+close[j-3]-open[j-3]; + dValueDown=high[j]-low[j]+2*(high[j-1]-low[j-1])+2*(high[j-2]-low[j-2])+high[j-3]-low[j-3]; + dNum+=dValueUp; + dDeNum+=dValueDown; + } + if(dDeNum!=0.0) + ExtRVIBuffer[i]=dNum/dDeNum; + else + ExtRVIBuffer[i]=dNum; + } +//--- signal line counted in the 2-nd buffer + nLimit=InpRVIPeriod+TRIANGLE_PERIOD+2; + if(prev_calculated>InpRVIPeriod+AVERAGE_PERIOD+2) + nLimit=prev_calculated-1; + for(i=nLimit;i + +#property indicator_separate_window +#property indicator_buffers 2 +#property indicator_plots 1 +#property indicator_type1 DRAW_LINE +#property indicator_color1 MediumSeaGreen +#property indicator_style1 STYLE_SOLID +//--- input parametrs +input int InpStdDevPeriod=20; // Period +input int InpStdDevShift=0; // Shift +input ENUM_MA_METHOD InpMAMethod=MODE_SMA; // Method +//---- buffers +double ExtStdDevBuffer[]; +double ExtMABuffer[]; +//--- global variables +int ExtStdDevPeriod,ExtStdDevShift; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- check for input values + if(InpStdDevPeriod<=1) + { + ExtStdDevPeriod=20; + printf("Incorrect value for input variable InpStdDevPeriod=%d. Indicator will use value=%d for calculations.",InpStdDevPeriod,ExtStdDevPeriod); + } + else ExtStdDevPeriod=InpStdDevPeriod; + if(InpStdDevShift<0) + { + ExtStdDevShift=0; + printf("Incorrect value for input variable InpStdDevShift=%d. Indicator will use value=%d for calculations.",InpStdDevShift,ExtStdDevShift); + } + else ExtStdDevShift=InpStdDevShift; +//--- set indicator short name + IndicatorSetString(INDICATOR_SHORTNAME,"StdDev("+string(ExtStdDevPeriod)+")"); +//---- define indicator buffers as indexes + SetIndexBuffer(0,ExtStdDevBuffer); + SetIndexBuffer(1,ExtMABuffer,INDICATOR_CALCULATIONS); +//--- set index label + PlotIndexSetString(0,PLOT_LABEL,"StdDev("+string(ExtStdDevPeriod)+")"); +//--- set index shift + PlotIndexSetInteger(0,PLOT_SHIFT,ExtStdDevShift); +//---- + } +//+------------------------------------------------------------------+ +//| Custom indicator iteration function | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total,const int prev_calculated,const int begin,const double &price[]) + { +//--- variables of indicator + int pos; +//--- set draw begin + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,ExtStdDevPeriod-1+begin); +//--- check for rates count + if(rates_totallow[k]) dmin=low[k]; + if(dmax +//--- indicator settings +#property indicator_chart_window +#property indicator_buffers 4 +#property indicator_plots 1 +#property indicator_type1 DRAW_LINE +#property indicator_color1 DarkBlue +#property indicator_width1 1 +#property indicator_label1 "TEMA" +#property indicator_applied_price PRICE_CLOSE +//--- input parameters +input int InpPeriodEMA=14; // EMA period +input int InpShift=0; // Indicator's shift +//--- indicator buffers +double TemaBuffer[]; +double Ema[]; +double EmaOfEma[]; +double EmaOfEmaOfEma[]; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- indicator buffers mapping + SetIndexBuffer(0,TemaBuffer,INDICATOR_DATA); + SetIndexBuffer(1,Ema,INDICATOR_CALCULATIONS); + SetIndexBuffer(2,EmaOfEma,INDICATOR_CALCULATIONS); + SetIndexBuffer(3,EmaOfEmaOfEma,INDICATOR_CALCULATIONS); +//--- sets first bar from what index will be drawn + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,3*InpPeriodEMA-3); +//--- sets indicator shift + PlotIndexSetInteger(0,PLOT_SHIFT,InpShift); +//--- name for indicator label + IndicatorSetString(INDICATOR_SHORTNAME,"TEMA("+string(InpPeriodEMA)+")"); +//--- name for index label + PlotIndexSetString(0,PLOT_LABEL,"TEMA("+string(InpPeriodEMA)+")"); +//--- initialization done + } +//+------------------------------------------------------------------+ +//| Triple Exponential Moving Average | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const int begin, + const double &price[]) + { +//--- check for data + if(rates_total<3*InpPeriodEMA-3) + return(0); +//--- + int limit; + if(prev_calculated==0) + limit=0; + else limit=prev_calculated-1; +//--- calculate EMA + ExponentialMAOnBuffer(rates_total,prev_calculated,0,InpPeriodEMA,price,Ema); +//--- calculate EMA on EMA array + ExponentialMAOnBuffer(rates_total,prev_calculated,InpPeriodEMA-1,InpPeriodEMA,Ema,EmaOfEma); +//--- calculate EMA on EMA array on EMA array + ExponentialMAOnBuffer(rates_total,prev_calculated,2*InpPeriodEMA-2,InpPeriodEMA,EmaOfEma,EmaOfEmaOfEma); +//--- calculate TEMA + for(int i=limit;i +//--- indicator settings +#property indicator_separate_window +#property indicator_buffers 4 +#property indicator_plots 1 +#property indicator_type1 DRAW_LINE +#property indicator_color1 Red +#property indicator_width1 1 +#property indicator_label1 "TRIX" +#property indicator_applied_price PRICE_CLOSE +//--- input parameters +input int InpPeriodEMA=14; // EMA period +//--- indicator buffers +double TRIX_Buffer[]; +double EMA[]; +double SecondEMA[]; +double ThirdEMA[]; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- indicator buffers mapping + SetIndexBuffer(0,TRIX_Buffer,INDICATOR_DATA); + SetIndexBuffer(1,EMA,INDICATOR_CALCULATIONS); + SetIndexBuffer(2,SecondEMA,INDICATOR_CALCULATIONS); + SetIndexBuffer(3,ThirdEMA,INDICATOR_CALCULATIONS); +//--- sets first bar from what index will be drawn + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,3*InpPeriodEMA-3); +//--- name for index label + PlotIndexSetString(0,PLOT_LABEL,"TRIX("+string(InpPeriodEMA)+")"); +//--- name for indicator label + IndicatorSetString(INDICATOR_SHORTNAME,"TRIX("+string(InpPeriodEMA)+")"); +//--- indicator digits + IndicatorSetInteger(INDICATOR_DIGITS,5); +//--- initialization done + } +//+------------------------------------------------------------------+ +//| Triple Exponential Average | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const int begin, + const double &price[]) + { +//--- check for data + if(rates_total<3*InpPeriodEMA-3) + return(0); +//--- + int limit; + if(prev_calculated==0) + { + limit=3*(InpPeriodEMA-1); + for(int i=0;i +//--- indicator settings +#property indicator_separate_window +#property indicator_buffers 5 +#property indicator_plots 1 +#property indicator_type1 DRAW_LINE +#property indicator_color1 DodgerBlue +//--- input parameters +input int InpFastPeriod=7; // Fast ATR period +input int InpMiddlePeriod=14; // Middle ATR period +input int InpSlowPeriod=28; // Slow ATR period +input int InpFastK=4; // Fast K +input int InpMiddleK=2; // Middle K +input int InpSlowK=1; // Slow K +//--- indicator buffers +double ExtUOBuffer[]; +double ExtBPBuffer[]; +double ExtFastATRBuffer[]; +double ExtMiddleATRBuffer[]; +double ExtSlowATRBuffer[]; +//--- indicator handles +int ExtFastATRhandle; +int ExtMiddleATRhandle; +int ExtSlowATRhandle; +//--- global variable +double ExtDivider; +int ExtMaxPeriod; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- indicator buffers mapping + SetIndexBuffer(0,ExtUOBuffer,INDICATOR_DATA); + SetIndexBuffer(1,ExtBPBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(2,ExtFastATRBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(3,ExtMiddleATRBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(4,ExtSlowATRBuffer,INDICATOR_CALCULATIONS); +//--- set accuracy + IndicatorSetInteger(INDICATOR_DIGITS,2); +//--- set levels + IndicatorSetInteger(INDICATOR_LEVELS,2); + IndicatorSetDouble(INDICATOR_LEVELVALUE,0,30); + IndicatorSetDouble(INDICATOR_LEVELVALUE,1,70); +//--- set maximum and minimum for subwindow + IndicatorSetDouble(INDICATOR_MINIMUM,0); + IndicatorSetDouble(INDICATOR_MAXIMUM,100); +//--- set first bar from which index will be drawn + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,InpSlowPeriod-1); +//--- name for DataWindow and indicator subwindow label + IndicatorSetString(INDICATOR_SHORTNAME,"UOS("+string(InpFastPeriod)+", "+string(InpMiddlePeriod)+", "+string(InpSlowPeriod)+")"); +//--- get handles + ExtFastATRhandle=iATR(Symbol(),0,InpFastPeriod); + ExtMiddleATRhandle=iATR(Symbol(),0,InpMiddlePeriod); + ExtSlowATRhandle=iATR(Symbol(),0,InpSlowPeriod); +//--- + ExtDivider=InpFastK+InpMiddleK+InpSlowK; + ExtMaxPeriod=InpSlowPeriod; + if(ExtMaxPeriodrates_total || prev_calculated<0) to_copy=rates_total; + else + { + to_copy=rates_total-prev_calculated; + if(prev_calculated>0) to_copy++; + } +//---- get ATR buffers + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtFastATRhandle,0,0,to_copy,ExtFastATRBuffer)<=0) + { + Print("getting ExtFastATRhandle is failed! Error",GetLastError()); + return(0); + } + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtMiddleATRhandle,0,0,to_copy,ExtMiddleATRBuffer)<=0) + { + Print("getting ExtMiddleATRhandle is failed! Error",GetLastError()); + return(0); + } + if(IsStopped()) return(0); //Checking for stop flag + if(CopyBuffer(ExtSlowATRhandle,0,0,to_copy,ExtSlowATRBuffer)<=0) + { + Print("getting ExtSlowATRhandle is failed! Error",GetLastError()); + return(0); + } +//--- preliminary calculations + if(prev_calculated==0) + { + //--- set empty value for first bar + ExtBPBuffer[0]=0.0; + ExtUOBuffer[0]=0.0; + //--- set value for first InpSlowPeriod bars + for(i=1;i<=InpSlowPeriod;i++) + { + ExtUOBuffer[i]=0.0; + TL=MathMin(low[i],close[i-1]); + ExtBPBuffer[i]=close[i]-TL; + } + //--- now we are going to calculate from limit index in main loop + limit=InpSlowPeriod+1; + } + else limit=prev_calculated-1; +//--- the main loop of calculations + for(i=limit;i=PeriodCMO && ArrayRange(price,0)>Position) + { + for(int i=0;i0.0) + UpSum+=diff; + else + DownSum+=(-diff); + } + if(UpSum+DownSum!=0.0) + resCMO=(UpSum-DownSum)/(UpSum+DownSum); + } + return(resCMO); + } +//+------------------------------------------------------------------+ diff --git a/Indicators/Examples/VROC.mq5 b/Indicators/Examples/VROC.mq5 new file mode 100644 index 0000000..3219c7d --- /dev/null +++ b/Indicators/Examples/VROC.mq5 @@ -0,0 +1,98 @@ +//+------------------------------------------------------------------+ +//| VROC.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +#property description "Volume Rate of Change" +//--- indicator settings +#property indicator_separate_window +#property indicator_buffers 1 +#property indicator_plots 1 +#property indicator_type1 DRAW_LINE +#property indicator_color1 Green +#property indicator_style1 0 +#property indicator_width1 1 +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +//--- input parametrs +input int InpPeriodVROC=25; // Period +input ENUM_APPLIED_VOLUME InpVolumeType=VOLUME_TICK; // Volumes +//---- indicator buffer +double ExtVROCBuffer[]; +//--- global variable +int ExtPeriodVROC; +//+------------------------------------------------------------------+ +//| VROC initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- check for input value + if(InpPeriodVROC<=1) + { + ExtPeriodVROC=25; + printf("Incorrect value for input variable InpPeriodVROC=%d. Indicator will use value=%d for calculations.", + InpPeriodVROC,ExtPeriodVROC); + } + else ExtPeriodVROC=InpPeriodVROC; +//--- define index buffer + SetIndexBuffer(0,ExtVROCBuffer); +//--- set indicator short name + IndicatorSetString(INDICATOR_SHORTNAME,"VROC("+string(ExtPeriodVROC)+")"); +//--- set indicator digits + IndicatorSetInteger(INDICATOR_DIGITS,2); +//--- set draw begin + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,ExtPeriodVROC-1); +//---- OnInit done + } +//+------------------------------------------------------------------+ +//| VROC iteration function | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { +//--- check for rates count + if(rates_totaldPrevVolume) + ExtColorsBuffer[i]=0.0; + else + ExtColorsBuffer[i]=1.0; + } +//--- + } +//+------------------------------------------------------------------+ diff --git a/Indicators/Examples/WPR.mq5 b/Indicators/Examples/WPR.mq5 new file mode 100644 index 0000000..e92b51f --- /dev/null +++ b/Indicators/Examples/WPR.mq5 @@ -0,0 +1,112 @@ +//+------------------------------------------------------------------+ +//| WPR.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +#property description "Larry Williams' Percent Range" +//---- indicator settings +#property indicator_separate_window +#property indicator_level1 -20.0 +#property indicator_level2 -80.0 +#property indicator_levelstyle STYLE_DOT +#property indicator_levelcolor Silver +#property indicator_levelwidth 1 +#property indicator_maximum 0.0 +#property indicator_minimum -100.0 +#property indicator_buffers 1 +#property indicator_plots 1 +#property indicator_type1 DRAW_LINE +#property indicator_color1 DodgerBlue +//---- input parameters +input int InpWPRPeriod=14; // Period +//---- buffers +double ExtWPRBuffer[]; +//--- global variables +int ExtPeriodWPR; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- check for input value + if(InpWPRPeriod<3) + { + ExtPeriodWPR=14; + Print("Incorrect InpWPRPeriod value. Indicator will use value=",ExtPeriodWPR); + } + else ExtPeriodWPR=InpWPRPeriod; +//---- name for DataWindow and indicator subwindow label + IndicatorSetString(INDICATOR_SHORTNAME,"%R"+"("+string(ExtPeriodWPR)+")"); +//---- indicator's buffer + SetIndexBuffer(0,ExtWPRBuffer); + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,ExtPeriodWPR-1); +//--- digits + IndicatorSetInteger(INDICATOR_DIGITS,2); +//---- + } +//+------------------------------------------------------------------+ +//| Williams’ Percent Range | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { +//---- insufficient data + if(rates_totalcur_position-period;i--) + { + if(Highestcur_position-period;i--) + { + if(Lowest>array[i]) Lowest=array[i]; + } + return(Lowest); + } +//+------------------------------------------------------------------+ diff --git a/Indicators/Examples/W_AD.mq5 b/Indicators/Examples/W_AD.mq5 new file mode 100644 index 0000000..e6955e2 --- /dev/null +++ b/Indicators/Examples/W_AD.mq5 @@ -0,0 +1,95 @@ +//+------------------------------------------------------------------+ +//| W_AD.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +#property description "Larry Williams' Accumulation/Distribution" +//--- indicator settings +#property indicator_separate_window +#property indicator_buffers 1 +#property indicator_plots 1 +#property indicator_type1 DRAW_LINE +#property indicator_color1 LightSeaGreen +//---- buffers +double ExtWADBuffer[]; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//---- define buffer + SetIndexBuffer(0,ExtWADBuffer); +//--- set draw begin + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,1); +//--- indicator name + IndicatorSetString(INDICATOR_SHORTNAME,"W_A/D"); +//--- round settings + IndicatorSetInteger(INDICATOR_DIGITS,_Digits); +//---- OnInit done + } +//+------------------------------------------------------------------+ +//| Custom indicator iteration function | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { +//--- + if(rates_total<2) + return(0); +//--- start working + int pos=prev_calculated-1; +//--- correct position, set initial value + if(pos<=0) + { + pos=1; + ExtWADBuffer[0]=0.0; + } +//--- main cycle + for(int i=pos;iprev_cl) + ExtWADBuffer[i]=ExtWADBuffer[i-1]+cl-trl; + else + ExtWADBuffer[i]=ExtWADBuffer[i-1]+cl-trh; + } + } +//---- OnCalculate done. Return new prev_calculated. + return(rates_total); + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsEqualDoubles(double d1,double d2,double epsilon) + { + if(epsilon<0.0) epsilon=-epsilon; + if(epsilon>0.1) epsilon=0.00001; +//--- + double diff=d1-d2; + if(diff>epsilon || diff<-epsilon) return(false); +//--- + return(true); + } +//+------------------------------------------------------------------+ diff --git a/Indicators/Examples/ZigZag.mq5 b/Indicators/Examples/ZigZag.mq5 new file mode 100644 index 0000000..95d86d0 --- /dev/null +++ b/Indicators/Examples/ZigZag.mq5 @@ -0,0 +1,297 @@ +//+------------------------------------------------------------------+ +//| ZigZag.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +#property version "1.00" +#property indicator_chart_window +#property indicator_buffers 3 +#property indicator_plots 1 +//---- plot Zigzag +#property indicator_label1 "Zigzag" +#property indicator_type1 DRAW_SECTION +#property indicator_color1 Red +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 +//--- input parameters +input int ExtDepth=12; +input int ExtDeviation=5; +input int ExtBackstep=3; +//--- indicator buffers +double ZigzagBuffer[]; // main buffer +double HighMapBuffer[]; // highs +double LowMapBuffer[]; // lows +int level=3; // recounting depth +double deviation; // deviation in points +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- indicator buffers mapping + SetIndexBuffer(0,ZigzagBuffer,INDICATOR_DATA); + SetIndexBuffer(1,HighMapBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(2,LowMapBuffer,INDICATOR_CALCULATIONS); + +//--- set short name and digits + PlotIndexSetString(0,PLOT_LABEL,"ZigZag("+(string)ExtDepth+","+(string)ExtDeviation+","+(string)ExtBackstep+")"); + IndicatorSetInteger(INDICATOR_DIGITS,_Digits); +//--- set empty value + PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); +//--- to use in cycle + deviation=ExtDeviation*_Point; +//--- + return(0); + } +//+------------------------------------------------------------------+ +//| searching index of the highest bar | +//+------------------------------------------------------------------+ +int iHighest(const double &array[], + int depth, + int startPos) + { + int index=startPos; +//--- start index validation + if(startPos<0) + { + Print("Invalid parameter in the function iHighest, startPos =",startPos); + return 0; + } + int size=ArraySize(array); +//--- depth correction if need + if(startPos-depth<0) depth=startPos; + double max=array[startPos]; +//--- start searching + for(int i=startPos;i>startPos-depth;i--) + { + if(array[i]>max) + { + index=i; + max=array[i]; + } + } +//--- return index of the highest bar + return(index); + } +//+------------------------------------------------------------------+ +//| searching index of the lowest bar | +//+------------------------------------------------------------------+ +int iLowest(const double &array[], + int depth, + int startPos) + { + int index=startPos; +//--- start index validation + if(startPos<0) + { + Print("Invalid parameter in the function iLowest, startPos =",startPos); + return 0; + } + int size=ArraySize(array); +//--- depth correction if need + if(startPos-depth<0) depth=startPos; + double min=array[startPos]; +//--- start searching + for(int i=startPos;i>startPos-depth;i--) + { + if(array[i]0) + { + i=rates_total-1; + //--- searching third extremum from the last uncompleted bar + while(counterZrates_total-100) + { + res=ZigzagBuffer[i]; + if(res!=0) counterZ++; + i--; + } + i++; + limit=i; + + //--- what type of exremum we are going to find + if(LowMapBuffer[i]!=0) + { + curlow=LowMapBuffer[i]; + whatlookfor=Pike; + } + else + { + curhigh=HighMapBuffer[i]; + whatlookfor=Sill; + } + //--- chipping + for(i=limit+1;ideviation) val=0.0; + else + { + for(back=1;back<=ExtBackstep;back++) + { + res=LowMapBuffer[shift-back]; + if((res!=0) && (res>val)) LowMapBuffer[shift-back]=0.0; + } + } + } + if(low[shift]==val) LowMapBuffer[shift]=val; else LowMapBuffer[shift]=0.0; + //--- high + val=high[iHighest(high,ExtDepth,shift)]; + if(val==lasthigh) val=0.0; + else + { + lasthigh=val; + if((val-high[shift])>deviation) val=0.0; + else + { + for(back=1;back<=ExtBackstep;back++) + { + res=HighMapBuffer[shift-back]; + if((res!=0) && (reslasthigh && LowMapBuffer[shift]==0.0) + { + ZigzagBuffer[lasthighpos]=0.0; + lasthighpos=shift; + lasthigh=HighMapBuffer[shift]; + ZigzagBuffer[shift]=lasthigh; + } + if(LowMapBuffer[shift]!=0.0 && HighMapBuffer[shift]==0.0) + { + lastlow=LowMapBuffer[shift]; + lastlowpos=shift; + ZigzagBuffer[shift]=lastlow; + whatlookfor=Pike; + } + break; + default: return(rates_total); + } + } + +//--- return value of prev_calculated for next call + return(rates_total); + } +//+------------------------------------------------------------------+ diff --git a/Indicators/Examples/ZigzagColor.mq5 b/Indicators/Examples/ZigzagColor.mq5 new file mode 100644 index 0000000..2eebae9 --- /dev/null +++ b/Indicators/Examples/ZigzagColor.mq5 @@ -0,0 +1,288 @@ +//+------------------------------------------------------------------+ +//| ZigzagColor.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +//--- indicator settings +#property indicator_chart_window +#property indicator_buffers 5 +#property indicator_plots 1 +#property indicator_type1 DRAW_COLOR_ZIGZAG +#property indicator_color1 DodgerBlue,Red +//--- input parameters +input int ExtDepth=12; +input int ExtDeviation=5; +input int ExtBackstep=3; +int level=3; // recounting's depth +//--- indicator buffers +double ZigzagPeakBuffer[]; +double ZigzagLawnBuffer[]; +double HighMapBuffer[]; +double LowMapBuffer[]; +double ColorBuffer[]; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- indicator buffers mapping + SetIndexBuffer(0,ZigzagPeakBuffer,INDICATOR_DATA); + SetIndexBuffer(1,ZigzagLawnBuffer,INDICATOR_DATA); + SetIndexBuffer(2,ColorBuffer,INDICATOR_COLOR_INDEX); + SetIndexBuffer(3,HighMapBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(4,LowMapBuffer,INDICATOR_CALCULATIONS); +//--- set accuracy + IndicatorSetInteger(INDICATOR_DIGITS,_Digits); +//--- name for DataWindow and indicator subwindow label + IndicatorSetString(INDICATOR_SHORTNAME,"ZigZag("+(string)ExtDepth+","+(string)ExtDeviation+","+(string)ExtBackstep+")"); + PlotIndexSetString(0,PLOT_LABEL,"ZigzagColor"); +//--- set drawing line empty value + PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); + } +//+------------------------------------------------------------------+ +//| get highest value for range | +//+------------------------------------------------------------------+ +double Highest(const double&array[],int range,int fromIndex) + { + double res; +//--- + res=array[fromIndex]; + for(int i=fromIndex;i>fromIndex-range && i>=0;i--) + { + if(resfromIndex-range && i>=0;i--) + { + if(res>array[i]) res=array[i]; + } +//--- + return(res); + } +//+------------------------------------------------------------------+ +//| Detrended Price Oscillator | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { + int i,limit=0; +//--- check for rates count + if(rates_total<100) + { + //--- clean up arrays + ArrayInitialize(ZigzagPeakBuffer,0.0); + ArrayInitialize(ZigzagLawnBuffer,0.0); + ArrayInitialize(HighMapBuffer,0.0); + ArrayInitialize(LowMapBuffer,0.0); + ArrayInitialize(ColorBuffer,0.0); + //--- exit with zero result + return(0); + } +//--- preliminary calculations + int counterZ=0,whatlookfor=0; + int shift,back=0,lasthighpos=0,lastlowpos=0; + double val=0,res=0; + double curlow=0,curhigh=0,lasthigh=0,lastlow=0; +//--- set empty values + if(prev_calculated==0) + { + ArrayInitialize(ZigzagPeakBuffer,0.0); + ArrayInitialize(ZigzagLawnBuffer,0.0); + ArrayInitialize(HighMapBuffer,0.0); + ArrayInitialize(LowMapBuffer,0.0); + //--- start calculation from bar number ExtDepth + limit=ExtDepth-1; + } +//--- + if(prev_calculated>0) + { + i=rates_total-1; + while(counterZrates_total -100) + { + res=(ZigzagPeakBuffer[i]+ZigzagLawnBuffer[i]); + //--- + if(res!=0) counterZ++; + i--; + } + i++; + limit=i; + //--- + if(LowMapBuffer[i]!=0) + { + curlow=LowMapBuffer[i]; + whatlookfor=1; + } + else + { + curhigh=HighMapBuffer[i]; + whatlookfor=-1; + } + //--- + for(i=limit+1;i(ExtDeviation*_Point)) val=0.0; + else + { + //--- + for(back=ExtBackstep;back>=1;back--) + { + res=LowMapBuffer[shift-back]; + //--- + if((res!=0) && (res>val)) LowMapBuffer[shift-back]=0.0; + } + } + } + //--- + if(low[shift]==val) LowMapBuffer[shift]=val; + else + LowMapBuffer[shift]=0.0; + //--- high + val=Highest(high,ExtDepth,shift); + //--- + if(val==lasthigh) val=0.0; + else + { + lasthigh=val; + //--- + if((val-high[shift])>(ExtDeviation*_Point)) val=0.0; + else + { + //--- + for(back=ExtBackstep;back>=1;back--) + { + res=HighMapBuffer[shift-back]; + //--- + if((res!=0) && (reslasthigh && + LowMapBuffer[shift]==0.0) + { + ZigzagPeakBuffer[lasthighpos]=0.0; + lasthighpos=shift; + lasthigh=HighMapBuffer[shift]; + ZigzagPeakBuffer[shift]=lasthigh; + ColorBuffer[shift]=0; + } + if(LowMapBuffer[shift]!=0.0 && HighMapBuffer[shift]==0.0) + { + lastlow=LowMapBuffer[shift]; + lastlowpos=shift; + ZigzagLawnBuffer[shift]=lastlow; + ColorBuffer[shift]=1; + whatlookfor=1; + } + break; + default: return(rates_total); + } + } + +//--- OnCalculate done. Return new prev_calculated. + return(rates_total); + } +//+------------------------------------------------------------------+ diff --git a/Profiles/Charts/British Pound/chart01.chr b/Profiles/Charts/British Pound/chart01.chr new file mode 100644 index 0000000000000000000000000000000000000000..47870653bbd866d12772597ff4e3167f82e603b2 GIT binary patch literal 4434 zcmeHL+fLg+5S`~r{fB-)3$cL&qy(uKsZUiap*~wl3?w2KD^8&4$G1IaW|y^-wF^SD zQdOY@ygNHPmosO^{QS|Eu}owrD_P6Ayp$I*m0SjrNGhjtCS80d(sR#=bnw>+R#SXa zx|FTVWh6_P;nYWYCtu{NT*wFAE#wlKr`XLU!wp;E3bpfWeYb?%cim0pSod?RT;sFG zEd#f<#`9Qipe@LEzM=+F)K!zv*w*lZq*k`>_?|W49!y? z*SY2>sxmtJJ^M zd7RcYlD9gDTLM|uDf3mw$nWLr=&8$-4J{M9XsXK{<9_BWb$qi%o(iC$h%xncrK9nEuKRK8>U$i zYkb0vXOT>`(JEF4Yu&ODcqW5RUyaRs8SbWzF}@e7=cGlG=eP}|A$1J2<1dDiW1YFqpq&}CERyY5v6He;nOxSD*UsKU?SEB^ALoaUDkn+v!#sN~ zKa7c+t-nI_IXh&C>D)1+k2QNRCjr01h|pWgjkWui?#$VJbefp^PuBef{8_?6z7^0n z_K{ceS!bUqqRtLyU4`B>caMOTf3bUbB*yBSSq#h&n^)s~$-fscuFVobvrRSo)BRIx z$};y{HARLbM{rg0?3W0YybcN literal 0 HcmV?d00001 diff --git a/Profiles/Charts/British Pound/chart02.chr b/Profiles/Charts/British Pound/chart02.chr new file mode 100644 index 0000000000000000000000000000000000000000..e291c7a97ecb8cd239e282e84ee0a943a1e91ac7 GIT binary patch literal 4432 zcmeHL+in^$5S`~r{fB-)n*bpYBoe6?sZUiaMSWfo76Rh7Vj+}%eA{zo?0D~O8by(+ z3N4B4@pvw0j%WG#V<=;p$w;=clPh^CFJvyUTuNIyav=lh;kzw;9S<;P4`=%-oyt*G zaw8jAV%JA`Ctu{NT+0VtO=JSibF9V^;e?}bhT3^jel>;M_snXH@hzU6q}b8b9XpK2 zvVg82-I5b&Wj>~PqY{+g$Xd^y!%jQ9Bj>Q-LeB8r)1BOtLh}e-OdvhQzHd0S<$Nrz zOw^whq}J-qiRu|RE2_2mJtNiJhSfcIW#`wO(}smrR@`XD>Q^GUQ(q`ij!y8@$91I{ z3YnQ=ywzx#Ww)9|!v(#&!}?P8E~3Hut94 zs-0}k8;ZL;j>8RJoQaetY&Ls4uy^b!Hk;)nU+8Hs(Q`C*9tFBQe~7f#aFQzzm)j{2L0R*2D` znR}|5;u{U$z1YRF>#wh_$NKTS++fy|rS9-79YcpPS-Bb;MRsdqR-RJMRCrghu8w^} zI62!j6lcTuQr{cO=prZN+4pJeTex1(emkHw^ffNbS}&i%JF*Nb?-n8zv~{}dvQm2pShA>{cNW| literal 0 HcmV?d00001 diff --git a/Profiles/Charts/British Pound/chart03.chr b/Profiles/Charts/British Pound/chart03.chr new file mode 100644 index 0000000000000000000000000000000000000000..eea8c598dd2b9648fec6bfa438c15084a27e14af GIT binary patch literal 4432 zcmeHL+fLg+5S`~r{fB-)3vmd9N`Tah)TgSIP@k<31BuARiW6x1@omqU@vy$E(;|dg zRaIoj?#|B6<;tlQH5jgG?${*!LBu zcCB2hKXXVe)SEr%>LF5QMO>Tj8L8$3Rv+O*OS&yc5UH3I7n-r|l~iuk7fQ6FQy_-s zsmFD$848)X!g!_8vItyj77Z8l?iTAa*_06tQCjIdkzg4vfUPN_xsJ?KbI2^T?X)ad z+;V6p4q|dkoHBz?9*+y0nPG<62|kUm|E4l)R?iTL0`>)Io6j)6El;G!88k6&L~{;# z!sUodtSbYE<>Vu>B z-z;*R)-@(r?ICUnWCxJ7m{l?IYxz2Q>hk0h%S01Rb-4k~XU_U1->i|R9H^>G1#PtR zq=qbG=n1e$Zk&{L<@{mtL_N8a+2aYTlGhg)8v}mCH%d`HSE&gQ$k7Pn9GTx@94go_ z&5Bs#2`kPbscNHDtPa+?Wh3xR3Y}h!-D@e%rj9ZGE>sWMk#@y2Imc}v9p{DWF5{9E z5uhD03+ocD{UMr-+1nNe&6L=!`9${B!dM2mR^=H(gJr!vUq^{Y(xiU}BX8v0eHUlu z|6|1O1&*SS$ydOs^{->p_W|m>iP|~_cH=LOk^wlMOh?U@MY0_$cG9YFu4lS>2doFa z*`f}uS|~xxWMyWp+R5hZP~7D>4jsHXlPXWxY_&V^?sx=C`}iE<+so44eeHi$iy!8P zGZOES=7)LqRDKu}cUymj==1K7BBt|_89mnQ!Mq9h3L`>qDL2;cUzB?cD}PJfpTnOe zEaW=@ePbVaA)l0ir-(W`oOKm?)7?D+R{q8A;YbV}Fw{4>H86wog5B~xDzSb3Uck7< zJ6D|->{iphH9xkd%*LmxDZbGpxRd(3S9f(i){j5S4Q4%A>K4zeWauy^E61_XWVc<+ z%2V2z3hyd*t0T9BldHFe=4=?B>U%>QUF3v1`#z0*H|1T>emkHw^fhbDS~o1<9a)Bz nca6?vvpG5$*^BS<)qAbsn>S(JY52>8_qvC3Fn5IanKStbAKj-Z literal 0 HcmV?d00001 diff --git a/Profiles/Charts/British Pound/chart04.chr b/Profiles/Charts/British Pound/chart04.chr new file mode 100644 index 0000000000000000000000000000000000000000..4c680e47537aeb24d5dea6ccd8834cbd6a05cb59 GIT binary patch literal 4434 zcmeHL+iuf95S?cv{(%pG5+_Ytq_z?li6;b7#k1wcNfR|qtT<^29}k=}_LN6w_zBF&-qU8RFUo?_$*&suWK zIn+68ypQA>)?B|Q2bkf1j3UFD)S&)S7P|Tjo^o}@HpJ6I3`5xEOwP$+IYAs_XiqTj z+s@ObWULY0Kx?5E4>U8hx!+otlc?ngULRrgVdtC(-iCaYy|~nx?U%%ItFcg{nH{%u zR@CuEYh>ABE+%+im1=dRbu?s9ehc|rHbq7~e=8j)7NR1jQ{-rZIy6VhHDuDM5v=OQYuX9C^y&pKIHAit#NZ!Db3e%p38X?QrGt zJ6$bB{C5?sTOL?1;+A<_B5w=D&q%YyOovrM-uLT8+JDE|jSXZRhRV}whKTm-t z;@IkD96bdV$&J&ZuL9?ozG;&u6Ud1Ko3+5ZG2kbBqZaiu)tUloM&R#q>i(Hn=HoKv@ycxLhXL9gU1;MDNP)6xKaUPo;e1Ks#*M@e6~!_Z|_B-^oLr;QG$JXPr( zu?|3OM#1ygm{uPuOUAci;(&C&fPghWPeUvqALMJ$_gm zfsuHUv^XrXr;5Xvc)#}(WS?h;7&&G4lNm#32Kx;P8kuLt3tn$||`ET1DfvJ5-# m3M_1+8Fn(V7w_}sbFJZmJU*oZ< z?Y&D?lK<;7hYbuc!=3>ew8kzL$pO&Q4V=Hv{dD7h|Gic07cYyw;t6AF@kqaqi=A-w zq!_B_LtQ;6o@#{m1!w4;k*ZhE)b6L!)dL;B(C>M1rf;l;Z=CCRzj&p-V(X>iOWjla zv7V1Z3)&wSM`7$k-KUMcrt!Cm4L!q}o`P@koip{kr>7XI^>cmiM~yn^$}l|78?`zL zPxGbvSr&CRr}XCE*$X`{>#kSyjWylLiX;AVnoqMrPFYpnP3Q?X>J{gn&+jb@H1r$L7{%1 zhJw-UL_ISPn%W&}l-EMf=>g)PxUaJ|U;KXRSDtF_o{v!E$)4#O2jP44;osZS*sn@w z?TKHD#%KCAqm)}8==}T9-O}fQdV=O~!in13oV2Im`nj&`g;w4Z*NlSiLf;2^`geLF zW@nk2)vM=fb#h6C>NUoGAv%G?W^rT0Pt`VX@wtAEh3jp#+0fkN{;I9UxtO^KPclc2 zH7AY&Z|v*yYyF;H-jC0z$?cFc8{r3TGLE;Iexc_A&)BE&F8pSwA;FAFaQn2D7rHNI z%U-xs@0uFYfU%nHqS_)=%eX$JXVZQ*qnpR3#q^$sYGG73SC7~h_H>|A z)*02A^2G?PTg6x5`I_)gpB=~2fl%p1F(~fnGnnk@X!zTV3A(OoN%@?bj_c(4FnuoO zo-sBnkiYQ$%bKj<`a!t*E^t0_n{(I(@5Q-sb|Uo-bQW1+vI8B1-sGD|M>|{AM^R=n zbI0$ZY(vwh+jGM(3cTU8n>O!n=?C8?2 zUDD@Wc>_1Yf0wmG9l>>2mdNFytcBBX4*O^z>YDyUVh?onymakM$EShkkbF=VJMut3 z$U&!Ow6tz#9iRJKlcn;xFdGP!LAawbYUU%Yi5}QAt|x|JHt_6wqIY>_nC2L&CC_4h z$%-h8|KKc(0d&4Lld6LzC&vbia!hn#lzx(s0)^cTNRtL zBy{HQ-6?-VcL3$_ML!?S`|c4~RnO5w>k9$=LOAG2Mg->X9h$F+=5VA&^6!#U)sLL>)|J&lmH_`|mYe2r0xg|wPwHu+%3m{>Z zZWRf*q^&esl_UcPL%J_ss3K9OZ+FtjQJB4VM_{$W3#R`U2LYtfPNP2Wk{8;I;7F`j zkT82F4-$Chee*&YiP>jsibQf0X7AngLe$J?35!WA0s_m@1t5-X^gvN=G{a;n@x)c_ zkV5_WdiJ@$T$%e8x5-2K^S~L)R0*DP;$(ojh`j@c8*iK zu|Nm?@rmvUKZB!X9U(`%mukdbVm7c3>vmpr42`p%@R>Fm9KSR|#W3Os#1;>uzl?mr zhmu#s)hzR%&LcD}{G*L77>PT_2GyU$>cr3*-$T@zM#|J?Q zZe8--qF}i$Y3Pxaa!k^Fn7YMgnyYH%rC^1gv-|?uZ?^v3ir&;WExLjgoy(RZzSyrH za}^4ctt+lnvG`Y#K59l|ws9PltxHs}8`d+)x&BevxU>|i)Y?@P_<^4JyI|EB^|1_| zONtT0L*60xPUk=(y>F<$6}Z58f}^I0V;6C*b&b`pB|z51Eo-u`SjJW*f&}`LXiv6) ztT*{(uOAr{{}wWM+hjrcR*G!8r`Ge2V7g&Fcph$-<Xa9S@(6|k zl6!G5;Q5xscQM8?>pUd}i%0oJT!Phwhm(gRnnp5A$c!vyMFlxQ?NL8|ht zsI;Os)+{pS+bsF4{?W6XuEj0yj53P&Fcz^fo62hP$ZGF}_{_dOZ5KaC_k+=kpnEJ@ zV|bAXE+hB4NQ(^Q93NlQqBoOeV*7lg)#LRQ#ew@~!|zN8!cSM@SB~*?h2FfQ$Jmb9 zcR4JI>p*Tz+6;|=>??bOk0dn?WYZn%=asIujkwLIKZOL*bNtwQinQ+Wl*&Pn)L8h z)n4sKas9D+iG}HtT+vLp0^aJ+j)Mo?x~@u$#kS)-c7tTFh+190bYU4>51v*Z^BbO3 zOT8OBsow09Kifngntaj}{WW_$sA;7BykC4UFzKW628lrxu1Dt{EBbaU-}Y6ou+4Wm zQSOHoT&zt(m&M!<>kpnu=ivpjzKf^?wa-}RcjW)>CPgQ@9usLu*+nAOutzxh* z94C!mu2{q_#NPcx*kbG2(W2nFddZhmXk3Ks&7S^Kjf=&Em4&rsYbw79JFu|Q{-wMY zR-U^@l7d*f5sdPAGuG^Y&|ej&Nk$^g*xC4WJ0Yt{74&_19T%c76*AFE^Lnz^ihnXk z*++oNjTGw7-@Ey+Ytq5S0c0>a%EJTrGqz5Q{`31B(Eg^RHg)NDL{BKXFRHs`>@@$o z=*(4ozBg*Sqc-gHG89jE8$3m@BRi9ZNw?$S9r>;)==iqTX86G(SbaoGB0pFy)41<# z9vu0QvhSTj=d_;8$7Tga^i=S=v9Fi2`PfjnuPEU-g})Uoi6${`{xg#C@{N%!j$zT}gVleV`f@pXn~|;Rnw%HpNaKj>T*5ic`=QDY)EI z%(nZHja%>pHZLQx=64W#evnB|!#92HErHxxDfy6f)R1APLWZh&s*9*>HEqn?rJ}{+ zw$YYK!K;gL@P4V0V1KK-x+{DLGO3(d%BEFZYxkkIS!u8oa>K@7-xc4A*T!pBoTpBL zX2HL>8l(D}mlV`;jz4K#o8_-oJCGU3Rf#eqPX!q!`lGy>K3A-+${#)YozU+%Gv71(Tl){H?(3>_kn%g9*BWRU2 z#Axc=_c0=f#&GWQeX!cCg-yY$yOFB)VtYT7`oI1no$%1S2uz!|U1M<7Sc`xH@kv{A z8RPbM6`8yzjIiH#ia*MSWi1&t_^|l1KCwELL zKGh{vd%w!|eZvat%kG0O>j>?H=x`Yat93Dp-0>@8GZ1f@yNIoY%FJp;NO zn^{K0zg*Sn$BTj>@lUhdsRCpdO=3TBr)gGoSVkbmN24DFS8XdF@Ux<#aR<|@>TSCj z$s*Ismyv0F#HCD;X?V*xt3Td~$UGJTc(y}P+xTNgpX*i8#O^GD-4>y4M>PLvGeq_u z=o!ol#s_9^zdSLD>p-llC=)Ane-fS8`@vR8lNn9ZT5V!X&Ep~k$;x>Af}_pG*hLpQ z3@+=-*JVAv)%{g{-PDYMS0$t%q*#ve&$SNNv1F&NSaAcV<*~P~6U+O`2N5YB*9ds-^(ylebY|-@ z(wbF3uH6@j&K5iH8t_@?Z2NVEc}4~|GJG+jU|wo-{-J#Y6b)pydtVkox%$^v{ddPD zv-JqIZ8sSx?%qqCOS++Rf4KrQeVNX_r~a&5vZpuYn8x`K{L^juEaUq?rpT_G+FfL? z!CL4d4`FXK>?giz{Q2=_f-L5fw_?}ws(tOJ(gu;MvNcynOznL*DS5zYW4X;2E86Rt ztbGjOI&g{6(tDCpUK`!6k}j<$R_%~6^a^Q9Vjf-;~tC`(ua?SaV1DR>^p=)fWjb&A* zRZqX!hv`NlT^~B0clPWJZz`KDV>Z19)`8mY<`y%tUFjERp2wYMysDfC*Z5uvz7Ji> z98T%S=4ag9iYPB@`|?PS>KmZ*u6!}MZu=crjUN^@aVP2}tOgnhkC*U4$Gj`g_VD)^ zY`OerLCX6MjnCDVygfPriEnLF(Ad!kxyC2H#yhr{FGoTUJw;8(qi~j|s^i(-SKtlj zy#1{|U%@J*Et4N>S009^BzGM5{bkoI-qdWK;I>vQJy8xHONqbfds%cdO4oHt>$1f9 z+xr(zDpP)TdjCzcF@;Cw@A=nG;p&==JhZNl@oT60_uBt;C)3Q1eSh3kwp!DA%LiS-5MH{KEOWWJ-)c-E^rb`VI>KaX#J_=Tit;Y7cQg%Efo*bhL?fqSB zr#7PygF90GZQsobhq8LGKU=k_=4xA(Dje0c z(^q*VSc?Ak3ZK+I&4wet=UH%DqsOjFc{u1g>kgbc&6z&qtEL)~l+|6cpp#>Kb}XTa z#CFT`8WL9ZH`fDoljXB`cVF4@GWU4JM>8!a*8{b;Ao7en9ur(7?yFX#+?BRJ(CU7C z@f5D{T9Wej$mU=h5toX)R@79hKs)z5LQ>61{8*cQX4oKK$^HjQu5Yb*ng z;#;O)L_fDjN3?sYNv69P*h&D95-1*&%!xoo)T+NlRB<-+JucySMJpjoi6FWf*QpXzDf z9cYI4jysIbOxdSnwfiOYw6E)9{Z8CiJ=(s5?8}6P~6Mt;vk#9l!ksJEC zPqj{)yRG@VuA^PGwHJEQXRMKX+QmSv->Bcun)RwD1HYfQYBlt&?rFR&{cNuoE%fQl zMy5|&J+@Z#X=$Z-t2p$CUH#<1{p9yTi)HG>oj%n3?ES4r2ogRMZWkIEKFDh~(k$mfFRUKK zLGeg;jbFlgmY*DmcPAc2Tk)ZK^nE|Z2>p7R`z&?Wc6=@xkJX!5(yjZt|9-YwsMXg< z&>Ts)P~D22qYYB|-q;Fz9YsmXl0y{-08)J8L2-7asnQJ)4h zSFI&2N#li8qfs_zn#EQWf$HiU6(b7CcE80&)@u)u-=Rt<|%toCEnaInw|7HC#5*7ZXmPZ;DiQ1mYl#Pna zVq-v;nJ;JdZ>Vdt6fg9NR%_fiD{h} zTLhj75)*Yb(rnV6MDXWLp%qG{L4a zaphd8?FSxHEK5&ROXF+$f1uT} zVv8^~)fbN|#2VnROl{+_<@@!ZV026*spu^<8TMqHi^Z=c&{%JtfJ1kV%C@^B>Oq^^ zfJ#TQ0T(RF#-1YQ7rOhM_+qI4NWxH_^c($$%cjEU)FTBY){~3kV?+I}=#A`}OmJns zXC2hOWbejv87);jZ^h0f1muD5PgF6wuta2Ltv;E-&bz_4#yLBVaY~By zd*8j*r+xh-?(e?+Q2l681gkpdC-(yPSoHd3j%_EGK{kUNw0UIk8@-BpT+O3L7UC&6qP@cR(r$K9mCM-(%Rs2~6?N^PTxVv7PwQn8$ zW32gPZePg9ged*E&)hcqZEw&J8Zy@49Q%C)lz>eV*!0;!j%- zW%G!ysIeepL1hblA1OB8E9Bc%Jtxv**}ay}`l1n+^IAt)(6ZsouQJai*!Lc1f2QkCeGSD#wl$vOKk~IYR8~;6T8!VGHv~haS_aP$Sf1c02zYr%pR)4HT5k2%wu|oATn|$!z!0tQ}Kw>)HZojC>P9rx> z`l_4SO~`sJqsA#1F#?rh#B3iv9V>!Y74zUPk(=kOmta-M;BjZ8Hmee>b`y4+>Nj{V zRP4Q;+YR!>AammW@Ub&>t(^PcQ;U20ls!{k%=Z;RsH(Y4hPrc$17c`H){yn8s)+Nt zqE=JqD4=8KD5m|$*is>j){AeFBy-H74;)XD(S=VkC>Ft{nwda`s4PSu=z)!zq7N!9 zp;9yP-y$-vWJl0m$cRbKQ++1qls$35@3knUEJD@J2%m8V31?G>Xt5%Cj%<8AcIYM$ ztICt0Lhu*SiE3!8&ZJ7Ch-8)XBl739=%+KcQA9qwx%R1il+Otb^<&M*8Fj#E4M?Uu zWKPQY*~LcUY#tvVYB2U)PyPhE&l_AfLs=>oc!!0GBeI3O5fx%a>XApvl~~@kY^6js zGnv)jnOl9lW@;#wt$ul)|8$U9Rq0SfJFSDws<|vCB?dKHQfF1s&7!l~i!DO))gvU* z2$n%HN^+I&-F}*U9_t}O&dJ^!&7Sbt8^i0J60I7?_%qgA!JnPlv?l@uV&Z94|&f-zt=do`C zx~Zt^8|iH9vT1ICI^CEh)>2(0)USJxjM`r~O*H%~6euI$b7suB3O{CB?TgKxv) z)Q&7`%+pz(mA61?L1vt@KJ%um(uQx^pwgg-PFnQ(tC%;Dw1n)p;fAkbr?GX&&N|55 P&-oq~?0WpZoUh%VqUCf{ literal 0 HcmV?d00001 diff --git a/Profiles/Charts/Default/chart03.chr b/Profiles/Charts/Default/chart03.chr new file mode 100644 index 0000000000000000000000000000000000000000..2171f3ba9cc4c26085b8e6d50e30216a732fc3a4 GIT binary patch literal 25378 zcmeI5+fQ4`9mnUnQlI({_+{0t)Fd{TTa{D_kTj^xHcHa%V+7a%8Za!_N!Y(;|FnH< z-uqUm?e{Z3kLTQgW6s4{s1U~IoH=v(-ETAe_dk!_zB_cg?%a*tAKkCruiTLvxF@dX zmfX7AaI5<4`OgivqHkSYFYErg>-*Lh?$VvOJ$LGk_12%1?~IgwdZBhdCY}y-eW2g5yU-ge{*AG&_uU8e6Fd%gErqjslj%sv_V^_-~H$gk$1V6vv46+e&S z-oiV(zUQ814IKGp7RB%M1gWA~?0Jk`{p6kd=+{DvJapnpp9qhPeBv<_G4o#6=N?)% zvjdMsqYK)9)bnFEnL;$q{@mY(5)8u^qOBuAbDUU3xRb;o_{h)GuwZaIQ_s*rQM*%( zaxClxcz|)RxUaiLFJV6UC+|eN<0%$d*`D4Q`1j}|ytk{dKP2wjijM{33%$)K$<_ni zznspNJ_qUvn8OKYYHu`YtKs=rPj-E)&=b!Lf}ecf1Fim(Rs?k#G~q(yiFAvxTAs}y zk$%Sb2Z9yYfT!1{beC=gFOT(eD(pV-biLteB;6{@%TOeo38kEhGDe<5_VxW(zvr_V z1t(@z$xDgl=^6tkrh7y#cZJcO+V=HMo|12FpQiD2`z68I zFp;JCbi2OB2WLxDd1lm@T~+KYNmI0<{a6r3f>hYF?V<|DHUUjKr=y_MQIKH^FFf8bmzXlk9x#-5CDIA{t0y@G1upx~71z<7p8JEYyZR0#ol8D~^^W^Zrz1P* zrQ6YW(+(YB4yyR*=Yzgr1a#%Vw=g?{dr_M_xkaxXacAHCUY{L7fU9L)nZ!uSKe!m_ zy6*Kvpzxt6(70(=5aN5F52N{^Rt(h#3k!MB*ZK|9z&sCG)>I$FR|WCD#_tHWNDQz$ z)K!2sYdjI%1pAO@Ks1e^GO(}GKX6|W+}Aa(VSy`?u=QgB8y+hBda!U6%@^U~r&63y zjE(um30T>fVFgZE_2b_KtgMMQpn@!K?8skxsk`5aD@OW@tQyINd#}G}&WYDnNT>Pv zqI};#f5US@;0dmbW}ATihAfOWd18I03!Zu1dLbEao&Z$;TQ3>W?+1c<^btDlXJKSn zzv#H5l6s-q2xu^l&%8_?Ni%Tw2We{V?kEboEvfxh-(KmbF4cmjsdaaIhjAAnUU}%WLt^Krx6@{d~~Vt7viTOupO{NlDAwd3wh> z$CGc?LLm1>y#8y1yh(D?ElD|07woU=9~s;AUgKSZfArS3yne^pLX()rKqF72JIwyd zYWUk=q53G`0?#p8%XW$pU=Vvm##>ul1EMLbX)PWRgE1MnN{A z*iS6ORZWf`V-Lo4(R#PYcQf`%U+`^D9yW>3tVP~7KC|N|qe(=VlQt+<&E&TifzSTT z{v=yBQM~{aN)yk2SnyPXP)$a?OUJ$N6_-Sf4kcr$a|rUY492RBV0dUYdqJ%eahi5? znQ;^m2`U`WK-)gLie!8)Sve7e$(F|aUC3u2%Ugp+sTd-QR|fjG@4X|4V2l4*^FlWf zN#%-B>(1eUftA)G6A=U891P&;VozW%#B3^7#NTzz(<9;IMAzGDLuKbsJQ4A-tMAWs zZ%`5^^^TXuM)jyS*f4v$J&OT;uxRI|AWePXNcaE)A)-L#z`n-=&@V&#<$A&_%DJVavi$)_f*DTOreey7Bm6%w^W+VC+~0H zI}(TbrEjKK;HuY9)Mv36z}ltO&}99Quh$z(x5nz3r@jW7x-;sO%hCJ%y_$B78BmLY z-X)k5X)~&SCO_|~=k1RBUNmi#9^^gz5Tc?*p5CjBce$ze(H3RoP%|SNw~$3ypZSk) z3>ELox|5e%)oU@yV=ZgE_AI3(ttP}u^H@WMoeMKmXyWNp<%I4q*@oYU&yUw1@LUF8 zb&P|(L`H{7_MlaW`*Nq-m{ti|yA8cf)oG~0AzS@g{I#VTz}x%yWpGn{6lNVX%vzy# zsYAb0lV(+Etg6{OGnl}a2$GJRLVl-^)dvt^iS};f3*_IH{JVd7ZaFBaaq1b#JdNJW z(}3r@4S5>Wl%o&YkziTOyphg8QeoFx)N)(j^Eo*zVDm_-VyNB`L!65o@=LA3{6b_J z`I=^Q&LS{Ym(@TO?vH{KdpxWHni`ifa;}=qP&}^rHET0{gqO2ksEevw3gqz64(;$6 zwf4z?L&4{+ZJ|;!I4zJQMvw1dymWDsQM^i#OglST@mbr2htqG9)Vqv z|5*oih~=~;1#iMmu)B%)ocMUdo5&Bs# z(P*9u5d2YgBI6l_TDjJl$r);}~>)3b3K9a@p$ox>dE}KzC zn$9V_@{wdx<(^Rc9EXLLC$Fx`i-jLaJ$i@4_S2sbf8Q!Wg zszvUI)EUOePcGdd{)*l#bul61RV_YRt|uySiQR;}m)Wq*XXU* zvP+XJFS;|t`q{sEsvH+jtIMl;MlvZCwSSXR>X(C=s z;oz~%7dN}UhmQCEqHM<-Bxc!!?X(C;#_H#gE5z%_*7MofKIOc>GW{5R#u_a&W^w$t zx_?a$zAp=^&FII5;=jZUs8OJ94u6O}_m^5h#CFYvD5T{~_PpO6_W!;2 zd6h3-Cy;@(wq-ntCdX%29H(wTFC$?PJ$0_n*ZwZ6%5zEeiilO&R>bq$!>8rFEOYtF zuZ_5IIP;5G)lk<&k}Y!oT(PVz!QngqX(#BF!Bv&M(;jynP+k^{kw|Uiuds%yLHVzu zyk=k=dcN-vPG{Ylfpvb2`wsPZ^5#wZ9p{%GvF~3tlr6JI9j(de*IrwOdLE0Zvim1l zuUUs5MXf`XQSff5Y@@<&W9H-Lb!K%Nh`pw5`?m3~ueEBKChK`#NQ>afnXS)BlvnL$<8&{J*_A&}=k~p$OOmHR+LfJ+ zn%3^swaFsl6fshojn^Q@IO{ww)xs$(aEaxzsp>Tzu{|}MqRO6vGBT`*aXX@8G*7I8 z!@F%RJ2wyJ9u=I?3!H8~yB95b^U1yDS6Yvj@dks)Gh*L%Mr%BeHP{SPYU6!h3X{~x zq0!(k&ex#=j%dnfkI$=5_qFpMIm!HfpYBV&3n$z^6wR$ELKaUWDLy@T-ZOr!cJrb7 zWfyAfz1lgyMlnPrIkEXLM=3lX_@|%z$+cXgEiXkQ@pN0xpC0Hgr$5_SxX1{00`L}9 zD0Vk3JE?23^K;2W*-Re!-2utD*nLJLqjNl+VZ46g>s`?7c`ixL)XvLJ&tS<*3}Pk7 zaYo9o#OiIR#hF^wXgrm?6 z_rqdX3L9ZFtm*fnesAjcYFLRs%VAmHH)HF5cpu(`{csYF_12%lv+yu{6L!L1;?vV` zD9A^8+6}wv;eFr^(CKOPXf|ov={&G31lj zg7zn&7yCZaINkTE`ri!en$@ai$-BJM7vw$7;!v$$=)J$G*UO$9#`(Nat6rSVf*{=y z)b)#TOoo`=+l$Z_)p}j;t$p&nMZumln*B(*%b)Cqw{cFiC}Szl_`c}Mh~Gp?fhEuU zg|5#c)_nakQq%lF`?q?29L|TB&Dc7N_u&Xrx-T9(5>^Knkn^1)EultvoTi3xcPhy6 z!=!d6>g8BeOrwYLQ1d`{%{OU0p6ta|2@=nY!FLgMSF?Yo8NsE-=0=o7-X3i+ zP|H)jy)53cq>esk3@?Q*D1v;$xn(HG^*}!-qVRpSS(P>@w;GpgxDqLaTTa9sy(ldQ z`hKj>nIO5Z#9f!S^T^iK^O8on8v8cSpKEqdHp8?uZwz6(mGOoAU)AzlEEd3n1@qs`hi(e$dZ6y>QuHfpr)l4!|ak0?pwC`7c%f+&iPTTxr+HOkGO zZa>QBqwSYO2UB94??>CMsDEg-6i0x3z>(v#%Fv4ZNh{h9gmJWpVK9?>BYbX)^-7c} zax?QUYmpOS;je0WAgIVy;$=fcam2=L$xp#27-vUQM6&$a$Ap4PPsj# z*1d2y&TkU^?+IGw8}nOH-z^NaYvvPd*rN0#9Jm~RuZE89tc5Qmk9>bDT)MAAUG0P? zy3-N;(6Y8~@B`17M@P@mJFg>`z;D>nZhU6%gL~Pw+^+?{qYow_o7Zj zveCF3(RL)RKNMG5!uEtUz9*is92^P{NP_*YCB2LNN*)+=C}W%1wMPZxu_FzEOuZGR zk*oehT6~DoKN~fs>nG7+^MWcXqS0FH|0YmnU9tfejLXJj#S>3-_mAR>p8g^UJ$V!_ z^cOvT9(5;_nqDrd!v_1C!Z)&Onc&JAs|oCH%HFjp6C1)lQrHQPqNeYQ-|d^Cfj)~e ziM4qttY@#a6aKC@mi0m79_gJbG^p1DdKA82(`bJ+qz1jtp9<^J)%0R2x1pKpP+_fc zDinJ#70}!_hX%}VL2{S$(DZz|A_!OwJQ{muO-aP0o=g*Lce9d#p1_xBM>58#GU_>5 zH#w5VL+uOq_)CwXKIlm+arb*!3GO})50sm_8=mXij($4f^Vq(p_h?Z?do|fVF(}+) zFa9?ZY&$U>Q5~5%dt~t2G#*#`)Wg^NLZ7nV`&47^%1b=a&+AAHY&+JSIhAoSou4%g zbgUR2ZZaj8d$rq97hxHQ{8Bve znRp#fi=5%OHkySB^?QL9cvveJwD2{Sz6n1IsUVJQ&zc~E$;LOS&3|mxBt?*D2FEaE zdU{=lEF-#u=hNGl>!BxJ&v@*3v%Q1%=t+jBP5G=72Tk&ft4QK}y#4lka6Cb1(nfTO z##oYvlyU^mlmj@Chy7aGA!R5}!$;lqsvov&U*FGlrxWwr`?7iX;;d~E8?mCuyIbhSRHWZBc4nvmiRd-$oxk6;)Cm(-=3E@IqdOe_YU^ zD_V85YR@_bdA2GNGb?Olo(sOntJ^$I9fBUt*;iT~r18vqQJfuo`}^aiQPITX9v^NcF8O6j+s} zZ<_+p910Mt;}M}{^12Cr(097#>5=I1M%NG3hN_}N$wa2hp1yyjd)`Ko2Ap~KEZ8EUb}RZ!1>?XYfRUC_28`%+ctHIIJqmspdcf-+eZGS}Q$Xw0f4 ztK9~5h>nW6it5(3qxn;xigjm2cc+pR)q#)HV{b>T{F3NF4x>4GthXpFHgrl(JYm+jeRd7DP-n`cO zLHxa;A3WEj>C3iv9x=mp(kOZLWI!*Y6~0rEDnxADBUjpyrXjD9cFc5C$v;iDy2<{D zZ{Rt`dRv-nEn4oZ!EPQkbEIIu37H`Nz$Z>xEP1%pHINPT?mJ}Et!AljXrfTnPjdl~3F-MQTz)n9rfxHhIAJ1!uc||2>Uf|?yN#Vcb+wUp6 zSuLkIpPsyywRo|XMOJB{p|vciPR6mF92qiHq|7r>0G|$BNRQZRFJu(|)hP6QUjd|q}AA*|3X0n>sL9uz|rP$oWn=4xY@3-L;ZPY-}&>+U_J>Vo|~?Z_GXHl6MCY66)X_A8?Yk+SE?uX(R~l05X? z6SaaeXgjX!`h@fE)$)dip7Kn{UsLfDtE%L`+oT!0w&@Q|Nc9S_P+H?>zXTb(0qG%L%6@ykF8dJkkRZ+jX;XrVmWqnqRLN3r-Lo1b_6V^i zlj>PK?`G;*Scl>4j`sMxh*@?{k)tE_q&QfFNIlQWnuTDckmk$h3RyW;oe@Oh5pQ?{OL z@%T;ypA}UtKCc4D{F(QD!k_C6WgMxkBOBAEUf-1ef+fL!!FNe3x%iW=`*$t^uLiHh z>$^q&#o5WUi~5DUpsqgH1pFSyiB&X8ll@Z(z`1bnOHUNUPT`q7jdz(<*#oLy>9{8E zhZ7Ooqo?ax97F8Hxe=}B{3AO_Ij_y}!nUePpDSyEf5h*6F5{>6QrCe!8mY|#%ge&C zYg3?Nvpc7W)aqgRTX9|$d6*u@3G&Y!!=u%7&EUG+$Il(>KHIe!Y-iX%Z7e&V%KjMZ zXm-ivI$fV(#lB>6syTYCo7bt|3(+kV>(rHRUc|W2dXygX$Qt-u%Jyt#vC5G30M_hS zYt0o`MQ`Vcp16j{v2ITkBs1qdOWa$Mh4`&L+w!Q2F>n>hXtMwEsVP3!q}kn1a75dA z)LhfMEy{2fCwVznz$0B`;qU}Go09yg_k!e_u+Mcm^@%<{W9L)8P~AQpVGvU|N7`hB zVQRD)VX)Vc2!r+Idil#L@>8#e>&TFD!Z#Aa?3(vn%hVtT?Y)>OYhBcK?DwX=hZrJ7 zc%0@puJwxV5NTDXRWtoNpFV1v>PH&hL)b38@@W^_5%0v;oR5(9uNm{i=)`nhEgGjr zwbg~X@aK>14e5>RT0i(&_+<6Qkuudimz`39JUHV`bX_g;G&^)`Hkm#4_Og2IE1%9k zN`d;m*pDk;iXG>_P~e?W7m_OrTp7YSqqHEe%3e2Tue{ToGp*TaTSYI8XIbabFFP05 zuaoz}ksI=EM8b(X649m@xt)G?#qAP zik>s=P2>NcqFy`=9Sr8P&RM~|6QeS!B+-@N?ebI7(`nn6x5%)8>{=ssY=}_@T~<|M`)gFjMA1y8~g0 b|DWP_{C_@xf0-QetSt51MXOr>ei{A;h}4IH literal 0 HcmV?d00001 diff --git a/Profiles/Charts/Default/order.wnd b/Profiles/Charts/Default/order.wnd new file mode 100644 index 0000000000000000000000000000000000000000..77fa67016ac1f48bf71753402c1368b0d9c44a5a GIT binary patch literal 106 tcmezWFPR~OA(5eop@hMJ!GuAN0mLt2;AP+fvtTmDIAx4*${3=^0024W5!e6# literal 0 HcmV?d00001 diff --git a/Profiles/Charts/Euro/chart01.chr b/Profiles/Charts/Euro/chart01.chr new file mode 100644 index 0000000000000000000000000000000000000000..5db5fd755075f11eaa8881115a61ff81142e27af GIT binary patch literal 4434 zcmeHL+iuf95S?cv{(%pGHg?;DN^KoH;Y@&mR{ukdgFdAxpWEm-0f!lFOwelFC~-moB~&>AB}bI{51ht0}%I zUCKtLawBt@;M7O?DqrxqmJhmH$SpLFv71YV8#clfYUkPdZV9>Xx|_-Lo zXC0eICS?|~BHAQZ(7}lI)l#d8s=U{D3yDRGT+G_QI6mfWwp5W;ZdrYTnoCi2{B0I_ zoYpmxw>pSh0$J86^Hs;l@8#?0smqfMEfd>ls>_|?e&#H7e6vKJ3ZSYk6|~XLiyE?w zqes9ZxpCy`$}^bB6ZPayW{)>49J9~xYz+7be^H9^g-VTpKtA>HTp;rsJckN4OtT`E z_=FwLBAIHVRjdxyx@9BqOa`648k_er+)W(=e9u(RS&JsmaVtp2d7*m0aY=><(2kge zbqTM1AI-+>yZ!~ulxWv{A;)TAEQ8#u@{FP3X(;iLd^$$n$@|AX&dmSEh@T5Qib5ve z0H^G;?APR5Upt{f>KJIpUkoLuI&+;vJ2PlmB-^oKM>`eH{akk+fc3yP8`Pmy3nhr9 z+-24*CY!TE@s!7L=-}Hcnev3KR=WeI$F6cSxvVR%oxR7}|Ed=6=ZB9fCrR_eJUf&h z#>CCm4-tLN4jE!Pb>eJ8vHE5f12e?t)p%d>?*)u&vqaErQ_b#l|J<6g z%pIzx$dKenPO+T&o2%=&e*9f-Fzd-uYkVe-p~Ev-IgX8Oc57o+-m;si@UCK09r+{N zT%8)WSHttA_OV@bkrV3ddl>uf-7IMTJ)kx8HQ!pbS-ymKWEoc89Xgk-7U*PTFTT%L a=UT%zCt=Ps{NIG{b^Fg=JQ3b!uH+XBqo;oW literal 0 HcmV?d00001 diff --git a/Profiles/Charts/Euro/chart02.chr b/Profiles/Charts/Euro/chart02.chr new file mode 100644 index 0000000000000000000000000000000000000000..d212bab5e313f002fe101f51f3e36110bf0aa262 GIT binary patch literal 4432 zcmeHLZEq4m5T4H_{s(`6wm>PAq-|oA zj&^rvXXoXaXXp6!^IRq}m$7VQE0^+GUdcjYxsa~(dy*NYxU+x^^BYq_1gTNv1;zZ>H)m6^PA4;!ooT$t~F!LE0Nr(FO;Z8CwS`Py3!1V z%-mqS(P)`vGtHvmg5KR>eJMK^(O~^X=ZOT%a0YBG5Y27POg@LbT01QZ7Pl0diGw#Sn) z$fV3dRz#cR4mudov07?1k(c)xr;ymR$kkaJ_{PV)&6YgUvXa#&s9-V@|C&V}r$voj ztacE$E@b`rW0fuPlmb;nsi2K^o)?g13_S-H z$&GVYSM-juCQsCpJDEM6uyMS;#@HC}GybC#B1ID3(4b!ZMEuOFv zSdrRj6{~}_ZuSJ8iJ;S0WAj>sv#Dc(@3rbVZPDa8ZU^alUdW$sToNGyw4=_#qJ-D} z7|q7)RsVu!O0;V}mt(cCE`wal^NgXvvR<7pqQpn?&oS~|KHT5p%=~|h_`blSC}i>- zaBBB#AJyFl=Q7Uq`1@Ow^uZkL7O2^>NVa3e&MOtp^;lQ;z@sWB zPB!Na#a$l9;RY|yM9LF3o4*~{I}Vha$z=n1>+C(&`!8?tu(T!_6`wZx^m3uW6e95oq%6qMCdK$CVKm4ZqMjGI%KAouKO$alfXj06VNx_BX8u3 zVtIk6^M|)vVH&@qF{die!Fzd-ucX*bLp~IN0T#t=1yR|VZPpM`qysKDO$G#z) zobMXSvtfLp?+sOSkrRsS`#kpDx?a$JJD@f6H7?CsFQ36XvJ5M4hMUV~Q`}@^FTT&` a`&z>{J7M-T{AI%5b&v18xFfvJT*_}iT&Gh2 literal 0 HcmV?d00001 diff --git a/Profiles/Charts/Euro/chart03.chr b/Profiles/Charts/Euro/chart03.chr new file mode 100644 index 0000000000000000000000000000000000000000..bfa62d386e9680de07d8fc3414e3cc07ec3122b1 GIT binary patch literal 4432 zcmeHL+iuf95S?cv{(%pGHcrzEQd$WCj|hp1XDf}HCTcELoV0|G2hN%Cu)eGVRaJoy ziri**XJ_Yf=FB?ZzYS$9QyIxxHgX})<(bSRlXFR=FK6;vPVhI8Q#?mH*TeT-`JK{* z>|`NVvXVJ=y_e7O3D2dxQ(d`SL-P!)nWQ*jC!C>n?yavDko&5u16|E9zQMD>8Ruei z8;r+t3td6FCkL=7d`$C7B`Cj=rJg;5opyF#jv+sQZ>R8*JI#|Z;xLCyDiiGcf>XOz zuGOCfq?YQ<0d(~cDYGK3&G(E{a{{YR@S!E$79@yN%!(_`SocaQcj^lz+R-TxL-W+* zy3h=T%uFy|YqTr^H=0Gm1--k&`dqeUL_?I;I!`26h6`Y8hG=dgGu0e23vD|s3l_H= znu&v$+zO}6;giSX3TI}RVRnK~BkaGe%$n76M52IwLE7ds%2U^4j2qFML*8&@ z7IFPvPs?ECeFW*u7jertt`N7S;%BVUVx--2k9)UVqNqJpJVa zbg_!fBa<=u6Rh?Sw*;~S$Xd**82Pn)9X)k<@`+`liKe>T0OvDj{gQ7s$Wsnf)unjK53OLw2NHF-^{KTS&)wp}NbsBt-;h zN6f;yglm6@W@GlY#X&PA_G=!>p;{QrAlIrqV`#9fx9969@kpBV?_lJOy#3k5nfd=1 z@q2-zC}i>#aBBVQ4E244I&Y%3j)DF7i=$)!&L`7Rvt^NN$BLb{DxB+?uHFOdfp2!G zL#q}_5HnesS*v!kIXe`0IgUdIZ_cF36E<7z4!k>_z|uZG$N2WLwD(Z^U)AD=`QePj zd!+eco;{Tx#>Cy$PY`|H9a6+}Q8J^)nmw2|0bgN6=q=^O+Wm`ik74C+sryU#vx0?u zC!lZaBQNBmGVlyhXNR+{LT|deN5IOz*gYJHp#z5cCbtG=a9*%mzDFgt&)*9e*Ldfu z^Mc)K+PCJ%)|A=!R5isnngn-JfA{LHuE+ZEXSuv->_stOW9 z)uvf{JRYApb8P45kFiW;A(8B4FIVzXUdU2nxs*V0k{5_~l5BN#QxdI%cq*W8Ak> zq}868uILt48})dm$k1oAH#a6y&jF$yV)jAnm;li_yz)^@G-u5{q1@?OXi-JSd%Dc> zc&j-wbcn?q@4H;CZZwa^4EEole=Ua$QIFqF+sTC>!*l_R=Ey^}C7(kgSB=xMV7OUE z>({ddhu6rS!()OuW3(_keoYZFyvns&)NA0BB0g_z?J?Sq=y5({cp`4(b8_O9@4wgC zVyyqZz;(lc`66$L;}*DWls{8Ni%7d!9PZ6_f!5!-R$~D6FdN2(1L6uX3o~OrhsyI2 zu=Q3JAuFQI@&F%1G}1_|Ci3>q;|vzN7Q4D=z2Z2`+hWNxEiFaegBo?AQv7cbIi40h z2I%bow*a<%*cuvnjy!B%WKYqadSaO-_3@|1v8MJw-(agMwQ1ZT^IFx9{3z3s5C|}i zx(JIFzpJ2bub^jB_G-l5GcDRZkL9gK$lb4;LH1SIU|FxW7g^$vG;3l|H$$Ey@8tby zA7|$Ob0nW@BIq;u20S(X@wC)GosN8k6gkk&zj~H*RXeOIEsIn;R_vlu;p~sK_a0pL zdUHe_`Whr>;w-b~muk)(ilZEl{SIDk2~{VoHNQLXgvFC$7k>kMd#yE0_Ld`l+&Y{h z@g!;Mu$4X6I!uY1qn`tPo*hD9%Ic>wI;^<|^CaMUhzM6pyD3oT>Bq)goX}~i%0F56 z*I3UM5%N~RwNZs$$!AsIB~a%MXS)hl)4Y3luKbI;hht)0eHWF%>4M!194d9=+`WLf z*6&r@@EgQq0gCfLcSUcAre&$Y&Ho`iX(;cpXeuOm*6(_oJ9_n9mC1-Le+bN~PV literal 0 HcmV?d00001 diff --git a/Profiles/Charts/Euro/order.wnd b/Profiles/Charts/Euro/order.wnd new file mode 100644 index 0000000000000000000000000000000000000000..f916de3bb7ecbfe36f73939b45d1516ed5f659c5 GIT binary patch literal 106 tcmezWFPR~OA(5eop@hMJ!H7YR0mLt2;AP+fvtTkNIAx4+${3=^0023d5!e6# literal 0 HcmV?d00001 diff --git a/Profiles/Charts/Market Overview/chart01.chr b/Profiles/Charts/Market Overview/chart01.chr new file mode 100644 index 0000000000000000000000000000000000000000..ce260511466a1e1394ee4e33f1466ff4ca0ecc4d GIT binary patch literal 5652 zcmeHLZEG4q5T4J4{s(_RV|;&sB+ya{EtD2Y3;lGcXQITYc$&oi__oh8bIb1OdB!45 zNQ<2Dc4ud1XP$X>HotzJ$v{TZlZ7nhLSD)X8A~kZQk9x?q$@3aSEVg={Nh*>PgkFo zN++_G8|lkTCRp`VzQ|koAfM&C&dy~B&11~Q62Zb+I702Tl$}i=_d{oE($M)BBUgBq zl3-0u$Ch{>$ThTi`HGaK5`0YeOeH8klc`!C!&9?P3l;3Di*Np_sO|)sd)UVi(wA6w z539RohPtC0NKGNt#g58&ychIgTc2CiQ{5(CPCc--`Rl6Co##tmGq-ytl3U#oCAMSa z{X0)1exsT48M?&#LStrexYBGIKIrK!<|ndB$I+=%Kq33lh8QR30qChUsThBW#=0(1Q zNJ}=nu7jP(O8jdcIhP5UQX?RcZ#}%v zk@+>=eFYn)SrJP-e#WyVwb3h92W#E3;dv&4PFIb)=OWmqjsd=>s;60?$#L8Y()qj) z+BYtV5CQs;=V4aDX+K1>vHSM^yk<%iYd(`x^)N4koC|rz(C{#nxJW)6BRoBaKtf60 zA$!C?N#0|OOnAQsJ1zzzT^C`^Q^pQCp$twXPq6Fhr1k0X?K5~NdZ@Xsnj5HlSNVCG z4@FN0T*lsmAD#uqYnET~AZvNFRr{Qeb@nc(WOis|c~=)iS&RxKFBlJy=XrK9OsDKHcJ(r2Fvi>-x{IDNHvKMn4AjT2y? z-6i`FGKY0rr?_K`_1xq+(}#qcq4&E_GLO!G`y@L7>O0yy5}9qS!6vG~-RO?NO6+mS zcgB0XW09N8f?;g4(tTgT`N!lYGHD0Cw&8Q7fSdN!)>ApdKjE}4$s6SXcJl12O7bn> zgXdH?C&(U=R##*f-Fn?E|4+I>T4^grxwaL@L4C%y zWvS=cz-z0gxzg-76y4F>np7i4Kt0B(u50AoYa$@*LNQmyE?W|L(zDRxJUjlRF0UJ9 z$TM?~@m{lK8F)|@O&3J^1p8VJbw+)b_Bu}`7{evBwL&(lj+v0dSaFh#DR?0}+{IY1 zycLK{9dw;%hh5fS&*fu|Ju}RZ9e<`2>mP$zL%l|xO5pR}HlJbsRPRVE86q)nRC57; z)0H8j{iwTTKzZy?I{Bh*na3USwpINsG+WHHL+K9Lqk4BuchO(?f z=g=a1V_w%4Pe)(#r|Q`|$sTvu*L{79v30;N_(d=J7wVNmfgGh67hwK`v9Dm$G%KRQ z$6I_?WHh2;b+FbAkMA=HV!CR)Y)h~=V=VB!)i~^q#MKqa^|%APyZb`8%6dtH3=l^b z!ls9d{x^}Wv!5gOk?GMNc_!}_VHblh<@bYDFBRex(9g8H$#bZM-RnQoc9XZ2*W|HZ zL(em9Y_emq>hiNHr9D&YF{nAdq1cbz?!0$0)Cw!uDwZ9Yw+vS~E&5ydrmiP9lW47* zU)bTTbMyVd7vMnN={l;jjreuW;WcaTi%aLQZu+mGAHI+Ue}i8>LHLU1YcaxYNKV4} m81u$_I6K6w<&pOSHN{f$d`uJUf2^&V*K6ddfPWrs>lxNhl|@FJK@;;vHs`<_ugoLL zk7_N0m&X9pSugUIdE6myTjkG8v&Bq1&t2ZH<19Zzh=<;$2@x#xV6gpiuUYDh?O&v4*Z&eTHH2n%`ax?A#ba*b*ciAjSkpcP<^00|; z+FzsDCi|twUNaHxn#XdZ9)>DNS$)nJ8?5S=>rIxpOd6Uw2wA9e>g>$@k!?owK}ExET}X-`}!?nmOxOL8~IC9Xob;(czS5Dm{Yhe%_qWht@4bkTY3T zS?hLAbDmJ#<#_B*@bi^a=Y*}+PY2!;2k&tNGbJd@w G_wonw)YNwX literal 0 HcmV?d00001 diff --git a/Profiles/Charts/Market Overview/chart04.chr b/Profiles/Charts/Market Overview/chart04.chr new file mode 100644 index 0000000000000000000000000000000000000000..d0f44302637d73d5678b4d683c46edc9efbb2ae2 GIT binary patch literal 3168 zcmeHJO^?$+4D}g_e}a~#-F~dpu7p5{3n#=mN|Sa|ZTg|6-BNx$@SdGvCQX{%0}>oi z)HE}GV|(mp&;0x`l~i&`WG@G~m)G)2R+7m~BI(OS?qq~_Bx4!iE5f@cLwt?o7GFe{ za+bBsWh(_%eU&frLEg(J`KZ#JETDM>X(ll&oP{&9YHeLw0{2~|v_jn(W*+c6z{(63 zId{M~l}Bjv_@3Ngg@1_K!6p&JZ)Ky_SMZe9xwj#Hwqm0HwwDx;WlxiyJuj@0Whyy;pKLGI!edNJ3WU6;i2q#hH|jE>jj;=0xx zS#;?A661Z4s|U@aF@y3a$O}1E5p`Thf#N*55LNuh5u+vY(3}Z#$ZXtT%?O;EAda@$ zvS4wujJEG*3l0~^k&DM1HZ#mHJAO|I81Wd)n%4#5RKh=xcI->QS2E9y7Z`DeE3nJ) z%F9n`EyMm#HLlxEm@o2{aoi$q8|6=`(PE^X6&LsGIL2tKPajblYLtx)NB9-P3Nv6j zN076QZ3l)j4_Ogi$Rl(xqKSHHH4);S#sv`j4qThJzT>!Rs+ffwc^+S9PaV&GVwt#PQyq5;`^;Its*MBkv;(W^D6fr`HU*!^ zW6PWM=p3wOZ_KN@Vh17C@P=leOdux{Y}E#1>wur}MHKNnMde^1M+wF|Wd4k?uVCYJ zrpP3a_^wE8^orHNS~q`upNXN97~lQdWHD@0M~e4G^{}JTuXeQcxMQWYtIxTP9wP$u zqs>F>HV*O94jO8<&ffIcYbK&w^Hkodhdli*Gx*Z{zSHU@LmUITGi}^0k-`6&w$r%l zOeRDAM5Zm9>{zV2yiui;XDU4fHOE^N`>|s%yF-RrVFg>ovLo}9;VQ>Pe+o~kdU7+d z*1F-s4sV^C_Yd9yd-6utk)4+w|DAn!&f5Lr+CHqC{%hXb8N`a~_THc1*LM)!qj_88 qJ>BZv-@f~px6Fs=0cI_ZJQv6z-qdH+`P9{kC~KZeob{*sz5D`9Md?!j literal 0 HcmV?d00001 diff --git a/Profiles/Charts/Market Overview/order.wnd b/Profiles/Charts/Market Overview/order.wnd new file mode 100644 index 0000000000000000000000000000000000000000..dc3384eda883302683bf6a4fa17b88d81b88e4f3 GIT binary patch literal 106 tcmezWFPR~OA(5eop@hMJ!I(jh0mLt2;AP+fvtTktIAsiR%9x-=bcr#o@FldXx*_{e|aH@OApKj-UczD}ESkaKvfJ-s?6 AQUCw| literal 0 HcmV?d00001 diff --git a/Profiles/SymbolSets/forex.crosses.set b/Profiles/SymbolSets/forex.crosses.set new file mode 100644 index 0000000000000000000000000000000000000000..a3e0cb520ca5236d381733cad30c8d91b8d1aed3 GIT binary patch literal 218 zcmY+7ISPP45CkjU-sh8LiZgr literal 0 HcmV?d00001 diff --git a/Profiles/SymbolSets/forex.major.set b/Profiles/SymbolSets/forex.major.set new file mode 100644 index 0000000000000000000000000000000000000000..2f37ab7078beebd447798d488a00af095b2a3f9c GIT binary patch literal 64 xcmezW&yc}_fs4VFA(SBqh=UnifIN2wCx!qx4)k9J@Zsd-*J1<%@h!T}vsTd4|16{vJ{b^}UNY zBzub%g{C&QCsWM{d}Qo~yIt`;3AD!iyHR|OuZ-kD&%(GK#=@WU5?Ipmz2f0uVIf&m%=ZU-Fxke_<5X~wwQ%5XC6uQ_m)OhrfWwc@_SlpJ-Ow?o8 zmasAhdM+L}u$g0q==d{b*nd}>HPq*b(;EJHX`9b6zg3HNk{p^CH|FkAvyNG09?{oF zwU)!nN8}H)$WCqA!qo~=%e}YZ8ud?b9!4y-mvvR)DG~d)M6;%tE36P=SOT+!=I$83 z=Xh6pEe`YJatSil>ONJhcy7zY4bC%y6|eIINRlt?3?^mKVePd^Zr~Tu%+yn>$GW`J zSU_UcA{X=4Gn>P^&6j$XuNz+X!FVb1l;7r&tC3Knu>#rQ9M#^}ybkm8_wr%phVrS_ z43TJNaws=|eb!gH<2uX1=Bd0kYP<-t+U|lWGTUdUosP05&x#{U6Fpj3?QW0-#>TbR z_(dtoFI8%a4CE-oc!^VNG4||X^~7qd@cI?cuGB`aSUJ9GJjbyb9TON*v9%FwQ^y#e z3)MqrreASsZ4X4InSzs_YB$D zHz2yL!d&rEFUH-;2 zKb1v!t9H@l4D>&d>su`cnmOvR=X$-SIA#y}Z|aHvDH8b0UXFeD@v8dUa~Out#S5+j gV^=kJv8Nywr$B?9GP~;IXv8`0>3qf=z7M{VU-2D#;Q#;t literal 0 HcmV?d00001 diff --git a/Profiles/Templates/BollingerBands.tpl b/Profiles/Templates/BollingerBands.tpl new file mode 100644 index 0000000000000000000000000000000000000000..186190e0c98d3c3c3849fe5463d02ddce7fc6d73 GIT binary patch literal 4866 zcmeHL+in^$5S`~r{RcjvN?8(ekswl|N`0zSHSIInumn&DAa+SgKfdibGdT7x-fe`M z-W07!SbIDk&zW;<^Zi>-hBA>s&T+D_63R8AiR63;7_QDOU`_&cz7JH z@xBUjGgi#33TS_a{+XfSwvbw#5%~r0mgLkv{6fE8kM17d0WCW zQIBD}z$`PM=kjrdIWx2n9lxd&<8Oji!)b;*<%rK)TYHA~jm~H*$>523W9=@r>R3e< z5i@eHvt@|#9`(a2vQ?Y6a&G~vA$lE1Sc+DVDIx^Gei*sL~GVl>aRv$C0wf1ie&-1hz-8wVZ|Z`E&bn z<(BO`${BjCR&v>nN<)5iw(4XxSY4I(MvuKxRoh-LL1p_2r9Ro3%$|&+N)tWKu-fh* zbG)0@zQ;FO(SE5`6I3AIQoJv*iVfbqdKjO`#sVMTrX1Y;;OsNX7aF zn43O^_&ZlWR3gR|w>EuU!#b`>;V9Fw0W!ci9Bb<>yn4sfE_TD zVGO~?;(MVQU>P54Mq4-m7?<;B)JxUmv0+^_WAk*V8?sa{GH|lPSoUYyd$0WCNzZt} zore1CDw;c42JVp2Wh?TWhHJrb@4LR@P`W*5?)cc?`mndmp=u zp~zFy9jb!rZRc+G?Vd=Rl!txc8Oin`!+f{Byg%`NLQAtI%VOH*cc)9lXc+tc(~P-U&|Gq&zo7eFIT$yOM~6@4d1_&D+way9g}-Le^+`e UV>r%MR)2<#?<8#X_ri1e0W3B39smFU literal 0 HcmV?d00001 diff --git a/Profiles/Templates/Momentum.tpl b/Profiles/Templates/Momentum.tpl new file mode 100644 index 0000000000000000000000000000000000000000..7592b39c531033830a08166b4fda2a90a0fcf2ef GIT binary patch literal 7214 zcmeHL+iIFY5T5Ho-ysiB(x^EJNubc17D`J?FM1`$->Ag+i<+eN;oE-SjGNi@Kjcu- zgdn20yR)-%{APCl{63PN45ceGS;&dJmRB;8Opc`?O*xdd?BlnAZ&MCrS9WyVl0B@n zlzJ{pxsX%IWsF_l<(s^hkMc!+=;~DZ;5@==CLNrx6wZ)4PfAzkp!*fAW*86fUC10e zn!00waZk>{%c*x{8*=%_IOj@1`dlV@_6TzF?46a|J!n0~Oh?W@^|NNBuhL(DY67Y@ zq~C@`(i7*9E9DnZ9tFj$G;av~AHIF5NM_NDE!4Puv%0 z7|$a64AgHH38cTm`dBUtHk|1^eQ!RUBbr9A=pxc0%*0-!C5m#IC(LqFaHi+W=yIGg zhQ)(DPH|?28G6Wd>SF(SG;5w8!%lO^=hQZzVScG6nkE@I(Qb_2Dd;VdOd?w3T2IR$ zcQ7+lxNxsmE9iE66{LqxVmsA)%9qi4nusp&nQFk4lT3C4!E zpYV@Vq@OC)5D~~x7vm{Bzr@(l!}5vQxWLy}9AC+eQZaKpYaHX4jR6TPcFNW|IGa3r z_?;-9y_H|fsSRH*L0yhX@h-!$4lF=9Le^GOIC__%UHLw%D@FbMY*N&7K9aX8VVMW- z?%y2MfqD*POWxr>t=h$?zwxzS@zYxWWII7b9o zBD1`QVin3T%Y3%{B|fv}aA%0jQ2mQD9nE~Bi}Btt>5ZPs2wj&o?i+csb)rNY%EDeV zoK+X!T#M_dp`BT$IG>_mKnkN~?3ZOwjDf7)hBNG;xbLN4p;ZL-a_n7M`9i!nVml_? z7Z2O$D7Mjokn5q|Kr9x^c;6QhDJ{EY##>WsyGd?dU5`5VCfDN(F^QgMb{yVhQB{=w z&ph~s49!t-dE+FWuy5Fs&x(>GU<*4M>mq2=>I`vgd5PUZ=!ME+oL+o*<*4JFb_<@> z>5cVy=SJG2S67gK)xvt}r>cJ@Ju5MLt?{aY`m7%9xUaZT z)X;Cm*25D${N%WXuFv}TSZ|5N+kf0)Jf?i-tIprvr6>(8nyt--_buL;tsfYmudvxE zx*TE`UytHjjN#IA?nJ(7#1Lgi8a-Qhv0FeJ_9g@T8v>6%Xg|}(?SXcwM&W=a?78>` z^0Mx1LAwnKSHI`+=3eaI{Uzu&1a?d?w?RjI^!IR2Yeg~?%?^xBS>H@vH-5^Bh ycxbWmdpNBa?!46$n?CKKH++j#M}rMI_#4YzISzC8LrQf@*fux^$OpJ;AM5u4 z>8bgx`Hfk)yiUH)0Sk{E0Qdgn8XlA5r0W9E4seE&xP#Xscw2@vfFqw0^5JOw z1nMq8{hXB_zx^59e!%-N{wU)MD=EtJ9X=i7JI`I%>y&D8M1ClF((=rH8i9sId?$s% zkIK>EKZ1;o&Ch^-2DnESD&=_utr6#;J^p@jT(o%}=~H?5yZHwwBz@=59O=Kf)SSb3 zj-&swTA8z-PH`Q1=DJ_-?>+E&j#rgd(U32{zrd0Yp!tthg6CLCE-0Tl^KWZ0ikI)S zBp#nL?g*4A0ciQp6L|!~{0*gF`y?iozIDUq2)XABZ{RQmn z7Hru00Hf8)1jem|J_L*EQM8hS<*m7G-a^;%ejB=b3(LKa7j+(MeGe4w!*&UuHp2Kt z?|F=fcnaHn5?Kjjq4=F|vy2DM2mCn3DCkGB1;|D)YV@O}{}cEbX+Hw{vGtsHR#KGj z*`?PkK;FAp&*;aR*Un>wJI}NGc#$hP|InT%9cMUB4D{9emv|^8 zM$ZeJ$)QWGcdO`;jB84pa5Rq$LH}Q{w2)&bG2-|AcOF@(>T$Aq&x`#1qqjiW1BayO z-h?Lk%$VYINJ%i-^Gc`lv~;MM_qdjnx@(y$dyFm-^1SaY#e-I{s6lbyIw{;_!2MHPs^z7Koaaw-KHx8)=Xj646CCs%d?BhUI=&%rk%)C5OX@1eudIxw96amKb{Ym{-6!~DoE z*tK))+hK$fn?pVOVbUqGOJ{$48 z^}KsfM&ILNn%Ejd!?{{0=@Y!ukgA-A@i^&H=+AOrA-=C6wpOj~T=dsyxo-YuDdqj9 z5n>eYk1X1VxdR*ZW9M^w_e82@7qxVTR*iLvVF}$h>0Pt%Wc@AF8{w?fpN=uUNHkIy zjuKME`(=JibCtZV(s!96gsYXOF01?))McHeSJ4B)hE-i(i}Qp>#{2Jq3TMV7po11o+8)BelScvZ|nY?7svQxuL>)YG(IsA*z$OZd19IfbB=j67V&$mVmv2+KF8RcW1mnzG1G(&9L>8nOORM zJTC#?#r+b{{R}g_Y&14=U&pwh4#wD3vxv-9LPC`PCi*j7m^?K`oeILtuF)@ zz4}5>-|!<;Us#Nvq{zQ-DK#Ev^U@2o+nFD4`ce|cl)g|@HWD|gQ2JEXab+9!i>?l? z&%dcYM)phcHu!eS49-nWK z<*|jfJ0!lU&RqwV?heB_3iqP2iqUFPG97ywT7>QabvCRsm2g5b8@-%AU#hDcXLTB1 zvX_f(tVG4>S0W|gYn4(0wqJLYfbVLO640;v#68Y*>xgYH?cN~vKBZ;z>*?WAHAw3I zP*_3bTU1+KlDdMsjby$Y&NSPymaMMksj{>GYGl(m>Z&B2_v^cGS6vw&=?=kHs?-2ELT=vb@u~Yk6m5m=wyxT_I~OUL2*~q1WRW--8m)|I=M-& zZt~+g+Y5cV3OA=K>g%~Xm_u#a?jpb5Z0fMIC#~*-|6!nxN-_BR>EbM-8tz`}=Ro(Z zpf3he+`W4c+sMcfbHk%67c;jS=U2LCFE+ge7)ZE8vZj})eM)a*Qtf!cKb9{7yd4?u%gJfv?03$ z7X`+Xsim_yonw{l4;%%vv^U6AwmyG;WT{q=VfW*&a}lGIM9SN5J>0IMCOWmUu2Lz_F@^iP zLN zX3uQh8b_)Oz!=htP7X>7PzB5n8KQns;dWyibIoHMRMe#`jGUru3tS4M`-INN3E zY-4)cDQ_`8hIZbrtDUUECN^z_raj>nj+C*FG_H2pm9q9BSh+S2^_ZK`$+YoSn=8;B(ADcm$ZH)1kb{SkJ zFY*0DDqz`7IGrq;eWea(yX5NUkSXmoMTe333BDq`^hel9#oz3B13Oy9t0eDDc-#5E zPL@MI;9Ns~2j|VCe=2W1O?cZSIGhEIQ5CS`rWLVDko|cjZ6}Sfo#%S1sjpD{%-7ai zx6Ou_<8;C`%>-bWT)6~qU&-?E>qqq>o@5`x=hjfC)&H(eSd-OTd~=i*ImH;;t*stk z*BC7nus{3>-4x&Rd(gD4lZP-ZM3v!{Nel~rY*-m()6o+GGk9G&wlwM z<|T*Dc3ID2K5>$&&WE~rkRRhiPb}p_LUCHRJ~i!{E#XDe%2T~)I$2KZKTR@L3ftv7 zi=Go_<^J(fbI){|ZtksPYSUh$l(cJfIFE@b>n}&ON9LXBWZBPaVouUB_Ni=_bG_$$ fnVGQAqyLMN(7%O65yj_J@Di0Wmur(N%S@??MTyi=rbvd|Sa!Mm*OR=5 zUJ%D%2AG{|MW(jMot;^ryI&t@^kA_6{m-iUi`rBZwV|f!Kz*;a)JVNkGxb58;^=$z zT&=4e^$%PhsXOX3bsw)6>LEV!XcMhAapf7_$N1hzJyQ471GR#qsk&50>P%g!_vr7v zI>+%5dS$yUwTs@^BWcalg?g;de^h+k!{0;vKSvL5aek`y@ZWIt2*;MSx&_1`K>st)A87>m>2KioE#A-YN0eq-RwD8mM`!rV zYcu^l!`BA5*ab~uM_#t|(H3}E!)J0x?w?#EVdN{VeuWEB3=)~mtrgmSxH1~k!6>z5= zpUm;%nRD3V8SLeQdWG|s_(YvtYV2pQuRE||>jR88oAW;IMD!t4j2=ZRIaFS%yXqx$ zE$?@syO*%s2Y6BEq1Io4!(-Sk`=^aC0?~UOBc@%zcE1g*gwag=&b3*_1M35BBw`$M zW6>(G5sD^$(b9hbea6c7pnj%3=e0(P_+DOn%_{IdLVLz9Mh<%PDd=9{>}$>STitdA zE$nq(J;sYt$@Pc&I{CQ7c~YRSKDeeslo&;4xRS${eBZXBM>4J%-bA7m#CZDus^*0f zTf|7;_1_hYD@Bi!)~{NK-O|S^$S1K}bYSATKW<2@=Qpj!hs7oqjf&XpW4zc?KkEO7 z7{_+iQ;Zs7yOgON3|v%v3pj%Xd<4Qr&}67<`UGvAV?5)vMA%>F_QA2$*8#1OXJc9@ z=b+36Q#PGvp?O;HvkU5EiWjx9jf|q0RftyZ&wZq+MRK$glxZKGaV+QU(?XRoiSxf{AubJJoj$6Tw>p@b znbcVQ0IAmW%ytX8PFdgkh0HEK&bJ#IiczXwbgmmQ%cO6Ptn^?MoU5quA;u*aJsCwO@cie%k=2eL^(gfmQt;D;KF=$=I6hc{ zs2g%r$9jjcP`|RY2`pJ>+Se7P;YYD5?mjhaS+A3M&zi29EgQNae|7N98`EBBt9pj~ zh}FUu_}dv|Y?B#-Z(A|mmQ6!39-C`PdI+OW?!3&emfY4EG;N8a)J`N%wN;H}oJSySG8o8O24vA^sGy29k%k(RMuE+`SVC+C`7u9n=~dvWardq%!_vs|E9uIb@cec72Ww`mO@w!1+x3(<#Xe=;>OkhjJSNUb8jEG} zmTm1P`>>zBJSI*tjau7YGlt*%g!sVsrq$-^7$H96)9X`Su~VOZ`}2wP2ovKYjl*(! z%Z{#0G##m{?Z$eFp_WFgZ7*StumcZahQx|NGrOslSNtTT*r&{5p&x-*JDZO3i+OSxFKIl=eYt;6VkF`{8>t!}U}n{iH&xM1BiNot?PEnR zZA$K}%Xm2H)R*EE`;_^gm=#dx)Iqa|xtQm;^wV-LleetFS~w0gL#=w8F*MT1wC4po zS|+iHZl&`n^(muSQ|_;LHx>0}8ePl}syRwyvrL|`-GgTs8fj$O_6*t#?_2NT)pedJ z9uiXQO6KB{bJ)xIX7uc%Kf(gxeDj_T+PV&9-}djy7eDRC5=?QxLI{? z)U7nQ9^5QPsm?mfX!a?$sfM;E^Wy%(J0~t5X&n0Ylt&fMjL;TypF60sL{^AdZ;|Ij zefuMYSnQ8mlHa!7dzT@XaSqHHXX?p3Yf^mLW=Q0U_TLP(MXlf0d6BCeByXZOtW~V7 zTpn)-xm*Ts2zip&DlxSTxuV?-;SC|@MXqkEH`x2mTr2PErc9@-FmVpRnlsn5$h}9d zIpx`~mv%>qklz$9=@GxZj4$LZ$3Noy8~fyl-4xHo#*a{z96r-n-^B66B2`?eQqP0j z81H*xS3V>h$93y+lh$k(Uepv%<3-J|Z0bK%7#j}L_})a%2}k9{F#k?kzB#yDmWg6$UJty|eKWE=f_lU^nGq$&iSd+CW z?weD_DeXKq=jRgyoQ3llN#0ZD3b!>>Kc6{IfX=Yzg-=Q{7H<1(HmKPwlQzRpnx=;GMlgeQ%#Dsm53b({yb_^_WmbGaZ$zr{?S`QdjP^0pupl zVdOS?W+vWL-?6Ca-yMxbPHP7~FKImT<7Zb<-{<(YM*Z&N6Yr(&;EoroB-@BiteeR0 z1Y>=!S-w>rr&6@jcG_ONs^W#ud<=yHX)gy3%z~S)-&!n=mFq@$O5-zpJag+7u9w~1 zY*sKgJ1a_d&ijVu3~iy0y%ybhfgdmYXa7H9S2ym0`%dqj_YHPTlbtH-?+HLE<_>8U zjYrosWCyn5%BFmNzx;n+Kz$gzzG@NsHv75_Ho<+mjHi})QGd}tRS)=FeW9a@aBB9b z^<#v;V{6`im|Sgd_t)l(Q&yCQ^)e!1)+hM8vo2ac@$>%?dVf2w@Ngeo?m&ANynTT= z?*sg8=yfG_=L_Fo{du;JN*IM7&b2N`icB&Gng9vzsO65bZtc;q%)mG2T~PLhE65TKS$+Y+3Ce^8L^U%4bz|M)A}R<<@sY`o2fq z(Q`@p#gEI<9HZ*)({f~Pc1?Ksm~d0`HscTFk}saE8C<*Q+l`oA^lu_-7k#ttD^E)k zeXgJDf{Gi@yXfD>{Vsa9<7gMXo7l{|u-vt_D;@0X{Yu-(HN&}(U)#*h%gX0|VgKO@ zfc7aEEtp@0%B5h(CzFp<=awc84Ut(I+IC)C%mn;w(zY;1`7PY2nBU68y8IT!2$tX0 zjZ68hY_!R5V`E5u8)K7hWXNw#3no?Bt2w`&>&yAAd=JfUXJiz=E4EuCGYvCCJKJKd z$mWsd@h6tYf1RnZX1%Tz(1Xp>iWW0d*J~?Fvewf*J=f~G yr{-I0oAio0w)kot{l0lK`|m&V<_oi8HqEl>nxD*;X`3-~V*2K-Im6YK*)dDzrFntp zV`kh;n1}d#ZKm;?S1ahXf+x@My^eNcX2v`)lV%E6U2|pj%(=NXrx@?lT;O^Sqq1My zY+y8w$hrFF(#+ZW?+pJQ;4_W?7Z~9f_q%2r|COp4T%Y0D1x7wZs{`~uz(@<`bMu** zziB7G$1n@;9b)c-K^xwa`=qOn(GKy1l9<5XB6wSdM0P-9*WOtGbsR;WZ=l6GIAGfa z+@J8CkF<_`-j!Yn7z70JMzqa zzvKTy@Oh2Dm{!q_FTd|##fQ-Psg>Y0dXfvuXUzO%twrbMH?4^G$IQ_{lGOTBaN5T= z?RgLUUSP~Ub01p1vg4ka7M}f`80`f2v!hMHH)Oo(qlIIKJY8BUsPF0=J*iEBNGHY5 zv)W^Y+&q9ZuOWBZ@!>#TymJBXIETHwH9g$F!Y}IN%F4bE`x=K0J0D=AS{aNnp3sNP zqIwjqRGHh)8l{}xe&q>D>?sEqE>g3HlloBInA5W^#CGA}=dL-kT z(k2{DAv@6j=PfPd*h!4@`~EwHj1+sE^zM04f4ImkBlN%>sd+e{N3I!9oc<^UMtZh% z`c6xRS~)^nQt8?{sn8Q+sfaGlA+2|qWe;3uCC-R-3@hTuS(&}VGiK5go9iB#N6?~J zEu;M5O;5%|eI`;2vtpRt<_27!)Z&Cuk`xy4;$$>BPJDX^vpjVtPpQL@n@?M>AsYHr zv>S3IQTQv^ThGS8miZcXD|WpM9Jq}?Vy9&wWNCZf_^q`q(cLS2hyjVQirRK;J850i zE~Jz=Qc$||`NsNJvz96G`!2?uB}jVHd~YRL-7<^#xeJkpXnh?khecSN+FSGSr${Qd zn^{&M39el}9Sti-;=|Q+t1)KX`~Ybz+EsZQXv@bfTy1vjI`ajtHgLU*m3bSjxgymS zr$ZEJ^pV1gSzMNm27=47`8Y-ovldwhdQi+-gy2$ZCh0AaPa<`8z3o=w+4Z)@OPO2I z+OSzYL{&W?EWu{P#6+X_Ap2Rf3QV(#3_`k{1{|g%(hc!WD3K7KF;3;RkcWrf_i}XZ!e-psTz6{fNUVdMEJl;zsL&Wtzjx@jaeu87s(pw4C+%bZ^1Wpo z*wfYevWQb`DOE#!X6tSt^33A*5M7ei7%l1yKBA=!_pBw0->LLj)7Z3Y8sCbfZ5$l-ouqC;6qP7p1nve5ZGa5t=y9n6Ac! zJMeAuBYcay@T^QSUw_E`_s6xXcmC=%+&_;w@iQ`Y;LyRxv~#W)izj%CYdA4RWQ=my z%CBvPdllpMT&KGa!^8S^*`F>6Tw(}?x9IGa}9Jat8<5n`Q&lJj>xcp@>R*0-3lQ;gZugVk*!ToHvQhRQ5H z{~Sil`5K}qcW9nxxGb_|$q)JUdC51l_VVg|mLlmJuMkI9-*IDy(Wb}?HKvUx&K60; zN}saweOcGXtxQyO_j|~&`*;`V7<)?>csJu5`#uxiS*JOibW)jSF0;G6 zt;`z}lZdl>n1gROwFdP?ce*~7QCX}G?bV$fUkJ|e`o7~|=W|t5af_)8D{!%ld_Q-n zsH_4lRveF(jcV^dqEBB~vvMb+#rujPNwFpSyNg)~sz;=)Ieh1a7Bp+Vg!TLh8{%7A zd=E!#DLroS=ts!u7qCgbeWdo&!kZTEtqGpw;e2^sDC6t@ymwbZOya!HpDEuSS&`kg zl_EV6^4y-O(A{y;SH+Ky@cs#NJ3lR4JKo*Ca=BkBul%N6=>FdSNB%s~!WFmpURCMO zKvIwKIl_BRq4b^Q(aNgJv`qFzBc(iA?v>?Or)RFu;y1vYEv0-WzlJ$ed!199AF{h| zaV(87SKSi@imuaDFDK73nW+WTlUS9NVH!nLrz}K)*)u1?fBM{b6@B{Dh380OZK>C> z&J~}CPp@P39lpG5$|@`0>S0!02ZGT#{Hz+TgC+XWiql-{-c8Rt6BF~&0rus-j-0`4 fiW@geK0l!)$S +#include +//--- +#include "AccountInfoSampleInit.mqh" +//+------------------------------------------------------------------+ +//| Script to testing the use of class CAccountInfo. | +//+------------------------------------------------------------------+ +//--- +//+------------------------------------------------------------------+ +//| Account Info Sample script class | +//+------------------------------------------------------------------+ +class CAccountInfoSample + { +protected: + CAccountInfo m_account; + //--- chart objects + CChartObjectLabel m_label[19]; + CChartObjectLabel m_label_info[19]; + +public: + CAccountInfoSample(void); + ~CAccountInfoSample(void); + //--- + bool Init(void); + void Deinit(void); + void Processing(void); + +private: + void AccountInfoToChart(void); + }; +//--- +CAccountInfoSample ExtScript; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CAccountInfoSample::CAccountInfoSample(void) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CAccountInfoSample::~CAccountInfoSample(void) + { + } +//+------------------------------------------------------------------+ +//| Method Init. | +//+------------------------------------------------------------------+ +bool CAccountInfoSample::Init(void) + { + int i,sy=10; + int dy=16; + color color_label; + color color_info; +//--- tuning colors + color_info =(color)(ChartGetInteger(0,CHART_COLOR_BACKGROUND)^0xFFFFFF); + color_label=(color)(color_info^0x202020); +//--- + if(ChartGetInteger(0,CHART_SHOW_OHLC)) + sy+=16; +//--- creation Labels[] + for(i=0;i<19;i++) + { + m_label[i].Create(0,"Label"+IntegerToString(i),0,20,sy+dy*i); + m_label[i].Description(init_str[i]); + m_label[i].Color(color_label); + m_label[i].FontSize(8); + //--- + m_label_info[i].Create(0,"LabelInfo"+IntegerToString(i),0,120,sy+dy*i); + m_label_info[i].Description(" "); + m_label_info[i].Color(color_info); + m_label_info[i].FontSize(8); + } + AccountInfoToChart(); +//--- redraw chart + ChartRedraw(); +//--- + return(0); + } +//+------------------------------------------------------------------+ +//| Method Deinit. | +//+------------------------------------------------------------------+ +void CAccountInfoSample::Deinit(void) + { + } +//+------------------------------------------------------------------+ +//| Method Processing. | +//+------------------------------------------------------------------+ +void CAccountInfoSample::Processing(void) + { + AccountInfoToChart(); +//--- redraw chart + ChartRedraw(); + Sleep(50); + } +//+------------------------------------------------------------------+ +//| Method InfoToChart. | +//+------------------------------------------------------------------+ +void CAccountInfoSample::AccountInfoToChart(void) + { + m_label_info[0].Description((string)m_account.Login()); + m_label_info[1].Description(m_account.TradeModeDescription()); + m_label_info[2].Description((string)m_account.Leverage()); + m_label_info[3].Description(m_account.MarginModeDescription()); + m_label_info[4].Description((string)m_account.TradeAllowed()); + m_label_info[5].Description((string)m_account.TradeExpert()); + m_label_info[6].Description(DoubleToString(m_account.Balance(),2)); + m_label_info[7].Description(DoubleToString(m_account.Credit(),2)); + m_label_info[8].Description(DoubleToString(m_account.Profit(),2)); + m_label_info[9].Description(DoubleToString(m_account.Equity(),2)); + m_label_info[10].Description(DoubleToString(m_account.Margin(),2)); + m_label_info[11].Description(DoubleToString(m_account.FreeMargin(),2)); + m_label_info[12].Description(DoubleToString(m_account.MarginLevel(),2)); + m_label_info[13].Description(DoubleToString(m_account.MarginCall(),2)); + m_label_info[14].Description(DoubleToString(m_account.MarginStopOut(),2)); + m_label_info[15].Description(m_account.Name()); + m_label_info[16].Description(m_account.Server()); + m_label_info[17].Description(m_account.Currency()); + m_label_info[18].Description(m_account.Company()); + } +//+------------------------------------------------------------------+ +//| Script program start function | +//+------------------------------------------------------------------+ +void OnStart(void) + { +//--- call init function + if(ExtScript.Init()==0) + { + //--- cycle until the script is not halted + while(!IsStopped()) + ExtScript.Processing(); + } +//--- call deinit function + ExtScript.Deinit(); + } +//+------------------------------------------------------------------+ diff --git a/Scripts/Examples/AccountInfo/AccountInfoSampleInit.mqh b/Scripts/Examples/AccountInfo/AccountInfoSampleInit.mqh new file mode 100644 index 0000000..36f103e --- /dev/null +++ b/Scripts/Examples/AccountInfo/AccountInfoSampleInit.mqh @@ -0,0 +1,17 @@ +//+------------------------------------------------------------------+ +//| AccountInfoInitSample.mqh | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +//--- +//+------------------------------------------------------------------+ +//| Arrays to initialize graphics objects AccountInfoSample. | +//+------------------------------------------------------------------+ +string init_str[]= + { + "Login","TradeMode","Leverage","MarginMode","TradeAllowed", + "TradeExpert","Balance","Credit","Profit","Equity", + "Margin","FreeMargin","MarginLevel","MarginCall","MarginStopOut", + "Name","Server","Currency","Company" + }; +//+------------------------------------------------------------------+ diff --git a/Scripts/Examples/ArrayDouble/ArrayDoubleSample.mq5 b/Scripts/Examples/ArrayDouble/ArrayDoubleSample.mq5 new file mode 100644 index 0000000..6ba6e72 --- /dev/null +++ b/Scripts/Examples/ArrayDouble/ArrayDoubleSample.mq5 @@ -0,0 +1,102 @@ +//+------------------------------------------------------------------+ +//| ArrayDoubleSample.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +//--- +#include +#include +//--- +const int ExtArraySize=10000; +const int ExtArrayAdd=100; +string ExtFileName="ArrayDoubleSample.bin"; +//+------------------------------------------------------------------+ +//| Example class CArrayDouble | +//+------------------------------------------------------------------+ +int OnStart(void) + { + int i,pos; + double key; + CFileBin File; + CArrayDouble ArrayDouble; +//--- + printf("Start sample %s.",__FILE__); +//--- fill an array of background information +//--- open file for reading + if(File.Open(ExtFileName,FILE_READ)!=INVALID_HANDLE) + { + //--- read array from file + if(!ArrayDouble.Load(File.Handle())) + { + //--- error reading from file + printf("%s (%4d): error %d",__FILE__,__LINE__,GetLastError()); + } + //--- do not forget close file + File.Close(); + } +//--- check whether enough information in the array + if(ArrayDouble.Total() +//+------------------------------------------------------------------+ +//| inputs | +//+------------------------------------------------------------------+ +input int Width=800; +input int Height=600; +//+------------------------------------------------------------------+ +//| Script program start function | +//+------------------------------------------------------------------+ +int OnStart(void) + { + int total=1024; + int limit=MathMax(Width,Height); + int x1,x2,x3,y1,y2,y3,r; + int x[],y[]; +//--- check + if(Width<100 || Height<100) + { + Print("Too simple."); + return(-1); + } +//--- create canvas + CCanvas canvas; + if(!canvas.CreateBitmapLabel("SampleCanvas",0,0,Width,Height,COLOR_FORMAT_ARGB_RAW)) + { + Print("Error creating canvas: ",GetLastError()); + return(-1); + } +//--- deawing + canvas.Erase(XRGB(0x1F,0x1F,0x1F)); + canvas.Update(); +//--- start randomizer + srand(GetTickCount()); +//--- draw pixels + for(int i=0;i +//+------------------------------------------------------------------+ +//| inputs | +//+------------------------------------------------------------------+ +input bool Accumulative=true; +//+------------------------------------------------------------------+ +//| Script program start function | +//+------------------------------------------------------------------+ +int OnStart(void) + { + int k=100; + double arr[10]; +//--- create chart + CHistogramChart chart; + if(!chart.CreateBitmapLabel("SampleHistogramChart",10,10,600,450)) + { + Print("Error creating histogram chart: ",GetLastError()); + return(-1); + } + if(Accumulative) + { + chart.Accumulative(); + chart.VScaleParams(20*k*10,-10*k*10,20); + } + else + chart.VScaleParams(20*k,-10*k,20); + chart.ShowValue(true); + chart.ShowScaleTop(false); + chart.ShowScaleBottom(false); + chart.ShowScaleRight(false); + chart.ShowLegend(); + for(int j=0;j<5;j++) + { + for(int i=0;i<10;i++) + { + k=-k; + if(k>0) + arr[i]=k*(i+10-j); + else + arr[i]=k*(i+10-j)/2; + } + chart.SeriesAdd(arr,"Item"+IntegerToString(j)); + } +//--- play with values + while(!IsStopped()) + { + int i=rand()%5; + int j=rand()%10; + k=rand()%3000-1000; + chart.ValueUpdate(i,j,k); + Sleep(200); + } +//--- finish + chart.Destroy(); + return(0); + } +//+------------------------------------------------------------------+ diff --git a/Scripts/Examples/Canvas/Charts/LineChartSample.mq5 b/Scripts/Examples/Canvas/Charts/LineChartSample.mq5 new file mode 100644 index 0000000..802bb2e --- /dev/null +++ b/Scripts/Examples/Canvas/Charts/LineChartSample.mq5 @@ -0,0 +1,66 @@ +//+------------------------------------------------------------------+ +//| LineChartSample.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +#property description "Example of using line chart" +//--- +#include +//+------------------------------------------------------------------+ +//| inputs | +//+------------------------------------------------------------------+ +input bool Accumulative=false; +//+------------------------------------------------------------------+ +//| Script program start function | +//+------------------------------------------------------------------+ +int OnStart(void) + { + int k=100; + double arr[10]; +//--- create chart + CLineChart chart; +//--- create chart + if(!chart.CreateBitmapLabel("SampleHistogrammChart",10,10,600,450)) + { + Print("Error creating line chart: ",GetLastError()); + return(-1); + } + if(Accumulative) + { + chart.Accumulative(); + chart.VScaleParams(20*k*10,-10*k*10,20); + } + else + chart.VScaleParams(20*k,-10*k,15); + chart.ShowScaleTop(false); + chart.ShowScaleRight(false); + chart.ShowLegend(); + chart.Filled(); + for(int j=0;j<5;j++) + { + for(int i=0;i<10;i++) + { + k=-k; + if(k>0) + arr[i]=k*(i+10-j); + else + arr[i]=k*(i+10-j)/2; + } + chart.SeriesAdd(arr,"Item"+IntegerToString(j)); + } +//--- play with values + while(!IsStopped()) + { + int i=rand()%5; + int j=rand()%10; + k=rand()%3000-1000; + chart.ValueUpdate(i,j,k); + Sleep(200); + } +//--- finish + chart.Destroy(); + return(0); + } +//+------------------------------------------------------------------+ diff --git a/Scripts/Examples/Canvas/Charts/PieChartSample.mq5 b/Scripts/Examples/Canvas/Charts/PieChartSample.mq5 new file mode 100644 index 0000000..a228a42 --- /dev/null +++ b/Scripts/Examples/Canvas/Charts/PieChartSample.mq5 @@ -0,0 +1,97 @@ +//+------------------------------------------------------------------+ +//| PieChartSample.mq5 | +//| Copyright 2009-2017, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009-2017, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +#property description "Example of using pie chart" +//--- +#include +//+------------------------------------------------------------------+ +//| inputs | +//+------------------------------------------------------------------+ +input int Width=600; +input int Height=450; +//+------------------------------------------------------------------+ +//| Script program start function | +//+------------------------------------------------------------------+ +int OnStart(void) + { +//--- check + if(Width<=0 || Height<=0) + { + Print("Too simple."); + return(-1); + } +//--- create chart + CPieChart pie_chart; + if(!pie_chart.CreateBitmapLabel("PieChart",10,10,Width,Height)) + { + Print("Error creating pie chart: ",GetLastError()); + return(-1); + } + pie_chart.ShowPercent(); +//--- draw + for(uint i=0;i<30;i++) + { + pie_chart.ValueAdd(100*(i+1),"Item "+IntegerToString(i)); + Sleep(10); + } + Sleep(2000); +//--- disable legend + pie_chart.LegendAlignment(ALIGNMENT_LEFT); + Sleep(2000); +//--- disable legend + pie_chart.LegendAlignment(ALIGNMENT_RIGHT); + Sleep(2000); +//--- disable legend + pie_chart.LegendAlignment(ALIGNMENT_TOP); + Sleep(2000); +//--- disable legend + pie_chart.ShowLegend(false); + Sleep(2000); +//--- disable percentage + pie_chart.ShowPercent(false); + Sleep(2000); +//--- disable descriptors + pie_chart.ShowDescriptors(false); + Sleep(2000); +//--- enable all + pie_chart.ShowLegend(); + pie_chart.ShowValue(); + pie_chart.ShowDescriptors(); + Sleep(2000); +//--- or like this + pie_chart.ShowFlags(FLAG_SHOW_LEGEND|FLAG_SHOW_DESCRIPTORS|FLAG_SHOW_PERCENT); + uint total=pie_chart.DataTotal(); +//--- play with values + for(uint i=0;i +#include +#include +//--- +#include "ChartSampleInit.mqh" +//+------------------------------------------------------------------+ +//| Script to demonstrate the use of class CChart. | +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ +//| Chart Sample script class | +//+------------------------------------------------------------------+ +class CChartSample + { +protected: + CChart m_chart; // instance of the class to access properties chart + CChartObjectButton *m_button[NUM_BUTTONS]; // array of pointers other buttons + CChartObjectButton *m_button_tf[20]; // array of pointers period buttons + CChartObjectButton *m_button_sym[]; // array of pointers symbol buttons + int m_num_symbols; // number of symbol + CChartObjectEdit *m_edit[NUM_EDITS]; // array of pointers other edits + CChartObjectEdit *m_edit_color[13]; // array of pointers to colors show + CChartObjectEdit *m_edit_rgb[13][3]; // array of pointers to RGB show + CChartObjectLabel *m_label[NUM_LABELS]; // array of pointers to labels + CChartObjectPanel m_panel[NUM_PANELS]; // array of panels + +public: + CChartSample(void); + ~CChartSample(void); + //--- initialization + bool Init(void); + void Deinit(void); + //--- processing + void Processing(void); + +private: + void CheckPanelModes(void); + void CheckPanelAnothers(void); + void CheckPanelScales(void); + void CheckPanelShows(void); + void CheckPanelTimeframes(void); + void CheckPanelSymbols(void); + void CheckPanelColors(void); + void CheckPanelReadOnly(void); + }; +//--- +CChartSample ExtScript; +//+------------------------------------------------------------------+ +//| Constructor. | +//+------------------------------------------------------------------+ +CChartSample::CChartSample(void) : m_num_symbols(0) + { + } +//+------------------------------------------------------------------+ +//| Destructor. | +//+------------------------------------------------------------------+ +CChartSample::~CChartSample(void) + { +//--- does not perform any action +//--- all dynamic objects created in the method Init(), +//--- will be deleted when deleting panels, +//--- to which they were added + } +//+------------------------------------------------------------------+ +//| Method CheckPanelModes. | +//+------------------------------------------------------------------+ +void CChartSample::CheckPanelModes(void) + { + if(m_button[0].State() && m_chart.Mode()!=CHART_BARS) + { + //--- Set Bars Mode + m_button[1].State(false); + m_button[2].State(false); + m_chart.Mode(CHART_BARS); + } + if(m_button[1].State() && m_chart.Mode()!=CHART_CANDLES) + { + //--- Set Candles Mode + m_button[0].State(false); + m_button[2].State(false); + m_chart.Mode(CHART_CANDLES); + } + if(m_button[2].State() && m_chart.Mode()!=CHART_LINE) + { + //--- Set Line Mode + m_button[0].State(false); + m_button[1].State(false); + m_chart.Mode(CHART_LINE); + } + } +//+------------------------------------------------------------------+ +//| Method CheckPanelAnothers. | +//+------------------------------------------------------------------+ +void CChartSample::CheckPanelAnothers(void) + { + int i,j; +//--- Set Autoscroll + if(m_button[3].State()) + { + if(!m_chart.AutoScroll()) + m_chart.AutoScroll(true); + } + else + { + if(m_chart.AutoScroll()) + m_chart.AutoScroll(false); + } +//--- Set Shift + if(m_button[4].State()) + { + if(m_edit[0].Description()=="") + m_edit[0].Description(DoubleToString(m_chart.ShiftSize())); + else + { + i=(int)StringToInteger(m_edit[0].Description()); + j=i; + if(i>50) + i=50; + if(i<10) + i=10; + if(j!=i) + m_edit[0].Description(IntegerToString(i)); + if(i!=m_chart.ShiftSize()) + m_chart.ShiftSize(i); + } + if(!m_chart.Shift()) + m_chart.Shift(true); + } + else + { + m_edit[0].Description(""); + if(m_chart.Shift()) + m_chart.Shift(false); + } +//--- Set Shift Size + if(m_button[6].State()) + { + if(m_button[4].State()) + { + //--- Set Shift Size Up + i=(int)StringToInteger(m_edit[0].Description()); + if(i<50) + m_chart.ShiftSize(++i); + m_edit[0].Description(IntegerToString(i)); + } + m_button[6].State(false); + } + if(m_button[7].State()) + { + if(m_button[4].State()) + { + //--- Set Shift Size Down + i=(int)StringToInteger(m_edit[0].Description()); + if(i>10) + m_chart.ShiftSize(--i); + m_edit[0].Description(IntegerToString(i)); + } + m_button[7].State(false); + } + m_edit[2].Description(DoubleToString(m_chart.ShiftSize())); +//--- Set Foreground + if(m_button[5].State()) + { + if(!m_chart.Foreground()) + m_chart.Foreground(true); + } + else + { + if(m_chart.Foreground()) + m_chart.Foreground(false); + } + } +//+------------------------------------------------------------------+ +//| Method CheckPanelScales. | +//+------------------------------------------------------------------+ +void CChartSample::CheckPanelScales(void) + { + int i; + double d; +//--- Set Scale fix + if(m_button[8].State()) + { + if(m_edit[4].Description()=="") + { + m_edit[4].Description(DoubleToString(m_chart.PriceMax(0),4)); + m_edit[5].Description(DoubleToString(m_chart.PriceMin(0),4)); + } + if(!m_chart.ScaleFix()) + m_chart.ScaleFix(true); + } + else + { + if(m_edit[4].Description()!="") + { + m_edit[4].Description(""); + m_edit[5].Description(""); + } + if(m_chart.ScaleFix()) + m_chart.ScaleFix(false); + } +//--- Set Scale fix 1 to 1 + if(m_button[9].State()) + { + if(!m_chart.ScaleFix_11()) + m_chart.ScaleFix_11(true); + } + else + { + if(m_chart.ScaleFix_11()) + m_chart.ScaleFix_11(false); + } +//--- Set Scale + if(m_button[10].State()) + { + //--- Set Scale Up + i=(int)StringToInteger(m_edit[1].Description()); + if(i<5) + { + i++; + m_chart.Scale(i); + m_edit[1].Description(IntegerToString(i)); + } + m_button[10].State(false); + } + if(m_button[11].State()) + { + //--- Set Scale Down + i=(int)StringToInteger(m_edit[1].Description()); + if(i>0) + { + i--; + m_chart.Scale(i); + m_edit[1].Description(IntegerToString(i)); + } + m_button[11].State(false); + } + m_edit[3].Description(IntegerToString(m_chart.Scale())); +//--- Set Fixed Max + if(m_button[12].State()) + { + if(m_chart.ScaleFix()) + { + d=StringToDouble(m_edit[4].Description()); + if(m_chart.FixedMax()!=d) + m_chart.FixedMax(d); + m_edit[4].Description(DoubleToString(d,4)); + } + else + m_edit[4].Description(""); + m_button[12].State(false); + } +//--- Set Fixed Min + if(m_button[13].State()) + { + if(m_chart.ScaleFix()) + { + d=StringToDouble(m_edit[5].Description()); + if(m_chart.FixedMin()!=d) + m_chart.FixedMin(d); + m_edit[5].Description(DoubleToString(d,4)); + } + else + m_edit[5].Description(""); + m_button[13].State(false); + } +//--- Set Scale PPB + if(m_button[14].State()) + { + if(m_edit[6].Description()=="") + { + d=m_chart.PointsPerBar(); + if(d==0.0) + { + d=1.0; + m_chart.PointsPerBar(d); + } + m_edit[6].Description(DoubleToString(d,4)); + } + if(!m_chart.ScalePPB()) + m_chart.ScalePPB(true); + d=StringToDouble(m_edit[6].Description()); + if(m_chart.PointsPerBar()!=d) + m_chart.PointsPerBar(d); + } + else + { + m_edit[6].Description(""); + if(m_chart.ScalePPB()) + m_chart.ScalePPB(false); + } + } +//+------------------------------------------------------------------+ +//| Method CheckPanelShows. | +//+------------------------------------------------------------------+ +void CChartSample::CheckPanelShows(void) + { +//--- Set Show OHLC + if(m_button[15].State()) + { + if(!m_chart.ShowOHLC()) + m_chart.ShowOHLC(true); + } + else + { + if(m_chart.ShowOHLC()) + m_chart.ShowOHLC(false); + } +//--- Set Show Bid + if(m_button[16].State()) + { + if(!m_chart.ShowLineBid()) + m_chart.ShowLineBid(true); + } + else + { + if(m_chart.ShowLineBid()) + m_chart.ShowLineBid(false); + } +//--- Set Show Ask + if(m_button[17].State()) + { + if(!m_chart.ShowLineAsk()) + m_chart.ShowLineAsk(true); + } + else + { + if(m_chart.ShowLineAsk()) + m_chart.ShowLineAsk(false); + } +//--- Set Show Last + if(m_button[18].State()) + { + if(!m_chart.ShowLastLine()) + m_chart.ShowLastLine(true); + } + else + { + if(m_chart.ShowLastLine()) + m_chart.ShowLastLine(false); + } +//--- Set Show Separator + if(m_button[19].State()) + { + if(!m_chart.ShowPeriodSep()) + m_chart.ShowPeriodSep(true); + } + else + { + if(m_chart.ShowPeriodSep()) + m_chart.ShowPeriodSep(false); + } +//--- Set Show Grid + if(m_button[20].State()) + { + if(!m_chart.ShowGrid()) + m_chart.ShowGrid(true); + } + else + { + if(m_chart.ShowGrid()) + m_chart.ShowGrid(false); + } +//--- Set Show Objects Descriptor + if(m_button[21].State()) + { + if(!m_chart.ShowObjectDescr()) + m_chart.ShowObjectDescr(true); + } + else + { + if(m_chart.ShowObjectDescr()) + m_chart.ShowObjectDescr(false); + } +//--- Set Show Not Volumes + if(m_button[22].State()) + { + m_chart.ShowVolumes((ENUM_CHART_VOLUME_MODE)0); + m_button[22].State(false); + } +//--- Set Show Tick Volumes + if(m_button[23].State()) + { + m_chart.ShowVolumes((ENUM_CHART_VOLUME_MODE)1); + m_button[23].State(false); + } +//--- Set Show Real Volumes + if(m_button[24].State()) + { + m_chart.ShowVolumes((ENUM_CHART_VOLUME_MODE)2); + m_button[24].State(false); + } + } +//+------------------------------------------------------------------+ +//| Method CheckPanelTimeframes. | +//+------------------------------------------------------------------+ +void CChartSample::CheckPanelTimeframes(void) + { + int i,j; +//--- No Set Period PERIOD_MN + if(m_button_tf[19].State()) + m_button_tf[19].State(false); +//--- Set Period + for(i=0;i<20;i++) + if(m_button_tf[i].State()) + { + if(m_chart.Period()!=tf_int[i]) + m_chart.SetSymbolPeriod(m_chart.Symbol(),(ENUM_TIMEFRAMES)tf_int[i]); + else + continue; + for(j=0;j<20;j++) + if(i!=j) + m_button_tf[j].State(false); + } + } +//+------------------------------------------------------------------+ +//| Method CheckPanelSymbols. | +//+------------------------------------------------------------------+ +void CChartSample::CheckPanelSymbols(void) + { + int i,j; +//--- Set Symbol + for(i=0;i>16)); + m_edit_rgb[i][1].Description((string)((c&0xFF00)>>8)); + m_edit_rgb[i][2].Description((string)(c&0xFF)); + } + } +//+------------------------------------------------------------------+ +//| Method CheckPanelReadOnly. | +//+------------------------------------------------------------------+ +void CChartSample::CheckPanelReadOnly(void) + { + int i,j; +//--- Get VisibleBars + m_edit[7].Description((string)m_chart.VisibleBars()); +//--- Get WindowsTotal + m_edit[8].Description((string)(j=m_chart.WindowsTotal())); + j%=6; +//--- Get WindowIsVisible[i] + for(i=0;i=7) + m_label[i].FontSize(8); + if(l_pan[i]16) + x+=28; + if(i>17) + x+=28; + if((m_button_tf[i]=new CChartObjectButton)==NULL) + return(false); + m_button_tf[i].Create(m_chart.ChartId(),"ButtonTF"+IntegerToString(i),0,20+x,16*(i/11),sx,16); + if(m_chart.Period()==tf_int[i]) + m_button_tf[i].State(true); + m_button_tf[i].Description(tf_str[i]); + m_button_tf[i].Color(Blue); + m_button_tf[i].FontSize(8); + m_panel[4].Attach(m_button_tf[i]); + } +//--- creation m_button_sym[] + ArrayResize(m_button_sym,m_num_symbols); + for(i=0;i +#include +//+------------------------------------------------------------------+ +//| Class CSphere. | +//| Appointment: Class of the graphical object "Sphere". | +//+------------------------------------------------------------------+ +class CSphere : public CArrayObj + { +private: + int m_id; // sphere idintifier + color m_color; // sphere color + int m_num_parallel; // number of parallels + int m_num_meridian; // number of meridians + int m_radius; // sphere radius in pixels + int m_center_X; // coordinate of the center X + int m_center_Y; // coordinate of the center Y + CSphere *m_orbite_center; // "sun" + double m_orbite_radius; // orbital radius + double m_orbite_fi_X; // angle of inclination to the axis X + double m_orbite_fi_Y; // angle of inclination to the axis Y + double m_orbite_fi_Z; // angle of inclination to the axis Z + double m_d_fi_orb; // angular velocity of the orbit + //--- working variables + double m_fi_orb; + double m_fi_x; + double m_fi_y; + double m_fi_z; + +public: + CSphere(void); + ~CSphere(void); + //--- methods of access to protected data + int CenterX(void) const { return(m_center_X); } + int CenterY(void) const { return(m_center_Y); } + //--- + bool Create(const int id,const color c,const int x,const int y,const int r,const int p,const int m,const string str); + void SetOrbite(CSphere *sun,const double fi_x,const double fi_y,const double fi_z,const double d_fi_orb); + void Recalculate(void); + }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CSphere::CSphere(void) : m_id(0), + m_color(0), + m_num_parallel(0), + m_num_meridian(0), + m_radius(0), + m_center_X(0), + m_center_Y(0), + m_orbite_center(NULL), + m_orbite_radius(0.0), + m_orbite_fi_X(0.0), + m_orbite_fi_Y(0.0), + m_orbite_fi_Z(0.0), + m_d_fi_orb(0.0), + m_fi_orb(0.0), + m_fi_x(0.0), + m_fi_y(0.0), + m_fi_z(0.0) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CSphere::~CSphere(void) + { + } +//+------------------------------------------------------------------+ +//| Create object | +//+------------------------------------------------------------------+ +bool CSphere::Create(const int id,const color c,const int x,const int y,const int r,const int p,const int m,const string str) + { + CArrayObj *arr; + CChartObjectLabel *label; +//--- + m_id=id; + m_color =c; + m_num_parallel=(p>r/3) ? r/3 : p; + m_num_meridian=(m>r/3) ? r/3 : m; + m_radius =r; + m_center_X =x; + m_center_Y =y; + if(!Reserve(p)) return(false); +//--- loop parallels + for(int i=0;i +#resource "Kernels/bitonicsort.cl" as string cl_program +//+------------------------------------------------------------------+ +//| QuickSortAscending | +//+------------------------------------------------------------------+ +//| The function sorts array[] QuickSort algorithm. | +//| | +//| Arguments: | +//| array : Array with values to sort | +//| first : First element index | +//| last : Last element index | +//| | +//| Return value: None | +//+------------------------------------------------------------------+ +void QuickSortAscending(double &array[],int first,int last) + { + int i,j; + double p_double,t_double; + if(first<0 || last<0) + return; + i=first; + j=last; + while(i>1]; + while(ip_double) + { + if(j==0) + break; + j--; + } + if(i<=j) + { + //-- swap elements i and j + t_double=array[i]; + array[i]=array[j]; + array[j]=t_double; + i++; + if(j==0) + break; + j--; + } + } + if(first>1; +//--- + uint passes_total=0; + uint stages_total=0; +//--- + for(uint temp=data_count; temp>1; temp>>=1) + stages_total++; +//--- GPU calculation start + time_gpu=GetMicrosecondCount(); + for(uint stage=0; stage +#include + +#resource "Kernels/fft.cl" as string cl_program +#define kernel_init "fft_init" +#define kernel_stage "fft_stage" +#define kernel_scale "fft_scale" +#define NUM_POINTS 16384 +#define FFT_DIRECTION 1 +//+------------------------------------------------------------------+ +//| Fast Fourier transform and its inverse (both recursively) | +//| Copyright (C) 2004, Jerome R. Breitenbach. All rights reserved. | +//| Reference: | +//| Matthew Scarpino, "OpenCL in Action: How to accelerate graphics | +//| and computations", Manning, 2012, Chapter 14. | +//+------------------------------------------------------------------+ +//| Recursive direct FFT transform | +//+------------------------------------------------------------------+ +void fft(const int N,double &x_real[],double &x_imag[],double &X_real[],double &X_imag[]) + { +//--- prepare temporary arrays + double XX_real[],XX_imag[]; + ArrayResize(XX_real,N); + ArrayResize(XX_imag,N); +//--- calculate FFT by a recursion + fft_rec(N,0,1,x_real,x_imag,X_real,X_imag,XX_real,XX_imag); + } +//+------------------------------------------------------------------+ +//| Recursive inverse FFT transform | +//+------------------------------------------------------------------+ +void ifft(const int N,double &x_real[],double &x_imag[],double &X_real[],double &X_imag[]) + { + int N2=N/2; // half the number of points in IFFT +//--- calculate IFFT via reciprocity property of DFT + fft(N,X_real,X_imag,x_real,x_imag); + x_real[0]=x_real[0]/N; + x_imag[0]=x_imag[0]/N; + x_real[N2]=x_real[N2]/N; + x_imag[N2]=x_imag[N2]/N; + for(int i=1; i0) + fft(N,data_real,data_imag,XX_real,XX_imag); + else + ifft(N,XX_real,XX_imag,data_real,data_imag); +//--- CPU calculation finished + time_cpu=ulong((GetMicrosecondCount()-time_cpu)); +//--- copy calculated data + ArrayCopy(data_real,XX_real,0,0,WHOLE_ARRAY); + ArrayCopy(data_imag,XX_imag,0,0,WHOLE_ARRAY); +//--- + return(true); + } +//+------------------------------------------------------------------+ +//| FFT_GPU | +//+------------------------------------------------------------------+ +bool FFT_GPU(int direction,int power,double &data_real[],double &data_imag[],ulong &time_gpu) + { +//--- calculate the number of points + int num_points=1; + for(int i=0;inum_points) + points_per_group=num_points; +//--- set kernel arguments + OpenCL.SetArgumentBuffer(0,0,0); + OpenCL.SetArgumentBuffer(0,1,1); + OpenCL.SetArgumentLocalMemory(0,2,local_mem_size); + OpenCL.SetArgument(0,3,points_per_group); + OpenCL.SetArgument(0,4,num_points); + OpenCL.SetArgument(0,5,direction); +//--- OpenCL execute settings + int task_dimension=1; + uint global_size=(uint)((num_points/points_per_group)*local_size); + uint global_work_offset[1]={0}; + uint global_work_size[1]; + global_work_size[0]=global_size; + uint local_work_size[1]; + local_work_size[0]=local_size; +//--- GPU calculation start + time_gpu=GetMicrosecondCount(); +//-- execute kernel fft_init + if(!OpenCL.Execute(0,task_dimension,global_work_offset,global_work_size,local_work_size)) + { + PrintFormat("fft_init: Error in CLExecute. Error code=%d",GetLastError()); + return(false); + } +//-- further stages of the FFT + if(num_points>points_per_group) + { + //--- set arguments for kernel 1 + OpenCL.SetArgumentBuffer(1,0,1); + OpenCL.SetArgument(1,2,points_per_group); + OpenCL.SetArgument(1,3,direction); + for(int stage=2; stage<=num_points/points_per_group; stage<<=1) + { + OpenCL.SetArgument(1,1,stage); + //-- execute kernel fft_stage + if(!OpenCL.Execute(1,task_dimension,global_work_offset,global_work_size,local_work_size)) + { + PrintFormat("fft_stage: Error in CLExecute. Error code=%d",GetLastError()); + return(false); + } + } + } +//--- scale values if performing the inverse FFT + if(direction<0) + { + OpenCL.SetArgumentBuffer(2,0,1); + OpenCL.SetArgument(2,1,points_per_group); + OpenCL.SetArgument(2,2,num_points); + //-- execute kernel fft_scale + if(!OpenCL.Execute(2,task_dimension,global_work_offset,global_work_size,local_work_size)) + { + PrintFormat("fft_scale: Error in CLExecute. Error code=%d",GetLastError()); + return(false); + } + } +//--- read the results from GPU memory + if(!OpenCL.BufferRead(1,data,0,0,2*num_points)) + { + PrintFormat("Error in BufferRead for data_buffer2. Error code=%d",GetLastError()); + return(false); + } +//--- GPU calculation finished + time_gpu=ulong((GetMicrosecondCount()-time_gpu)); +//--- copy calculated data and release OpenCL handles + for(int i=0; i>(stage-pass))*(distance<<1); + uint right_id=left_id+distance; + double left_value=data[left_id]; + double right_value=data[right_id]; + uint same_direction=(id>>stage)&0x1; + uint temp = same_direction?right_id:temp; + right_id = same_direction?left_id:right_id; + left_id = same_direction?temp:left_id; + int compare_res=(left_value> N2) & stage; + //--- bit-reverse addresses + while(N2>1) + { + N2-=2; + fft_index>>=1; + stage<<=1; + br |= (index << N2) & fft_index; + br |= (index >> N2) & stage; + } + //--- load global data + x1 = in_data[br.s0]; + x2 = in_data[br.s1]; + x3 = in_data[br.s2]; + x4 = in_data[br.s3]; + + sum12=x1+x2; + diff12= x1-x2; + sum34 = x3+x4; + diff34=(double2)(x3.s1-x4.s1,x4.s0-x3.s0)*dir; + l_data[l_addr]=sum12+sum34; + l_data[l_addr+1] = diff12 + diff34; + l_data[l_addr+2] = sum12 - sum34; + l_data[l_addr+3] = diff12 - diff34; + l_addr += 4; + g_addr += 4; + } +//--- perform initial stages of the FFT - each of length N2*2 + for(N2=4; N2 +//--- OpenCL kernels +#resource "Kernels/matrixmult.cl" as string cl_program +#define BLOCK_SIZE 10 +//+------------------------------------------------------------------+ +//| MatrixMult_CPU | +//+------------------------------------------------------------------+ +bool MatrixMult_CPU(const double &matrix_a[],const double &matrix_b[],double &matrix_c[], + const int rows_a,const int cols_a,const int cols_b,ulong &time_cpu) + { + int size=rows_a*cols_b; + if(ArrayResize(matrix_c,size)!=size) + return(false); +//--- CPU calculation started + time_cpu=GetMicrosecondCount(); + for(int i=0; i +#include +#include + +#define CPU_DATA 1 +#define GPU_DATA 2 + +#define SIZE_X 600 +#define SIZE_Y 200 + +#resource "Kernels/wavelet.cl" as string cl_program +//+------------------------------------------------------------------+ +//| CWavelet | +//+------------------------------------------------------------------+ +class CWavelet + { +protected: + int m_xsize; + int m_ysize; + int m_maxcolor; + string m_res_name; + string m_label_name; + uchar m_palette[3*256]; + //--- + double m_data[]; + double m_wavelet_data_CPU[]; + double m_wavelet_data_GPU[]; + uint m_bmp_buffer[]; + + COpenCL m_OpenCL; + + double Morlet(const double t); + void ShowWaveletData(const double &m_wavelet_data[]); + int GetPalColor(const int index); + void Blend(const uint c1,const uint c2,const uint r1,const uint g1,const uint b1,const uint r2,const uint g2,const uint b2); + bool WaveletCPU(const double &data[],const int datacount,const int x_size,const int y_size,const int i,const int j,const bool norm,double &result[]); +public: + //--- + void Create(const string name,const int x0,const int y0,const int x_size,const int y_size); + bool CalculateWavelet_CPU(const double &data[],uint &time); + bool CalculateWavelet_GPU(double &data[],uint &time); + void ShowWavelet(const int mode); + }; +//+------------------------------------------------------------------+ +//| Morlet wavelet function | +//+------------------------------------------------------------------+ +double CWavelet::Morlet(const double t) + { + double v=t; + double res=MathExp(-v*v*0.5)*MathCos(M_2_PI*v); + return ((double)res); + } +//+------------------------------------------------------------------+ +//| GetPalColor | +//+------------------------------------------------------------------+ +int CWavelet::GetPalColor(const int index) + { + int ind=index; + if(ind<=0) + ind=0; + if(ind>255) + ind=255; + int idx=3*(ind); + uchar r=m_palette[idx]; + uchar g=m_palette[idx+1]; + uchar b=m_palette[idx+2]; +//--- + return(b+256*g+65536*r); + } +//+------------------------------------------------------------------+ +//| Gradient palette | +//+------------------------------------------------------------------+ +void CWavelet::Blend(const uint c1,const uint c2,const uint r1,const uint g1,const uint b1,const uint r2,const uint g2,const uint b2) + { + int n=int(c2-c1); + for(int i=0; i<=n; i++) + { + if((c1+i+2)0) + { + for(int j=0; jmax_value) + max_value=value; + + if(momentum_data[i] +#resource "Kernels/bitonicsort.cl" as string cl_program +//+------------------------------------------------------------------+ +//| QuickSortAscending | +//+------------------------------------------------------------------+ +//| The function sorts array[] QuickSort algorithm. | +//| | +//| Arguments: | +//| array : Array with values to sort | +//| first : First element index | +//| last : Last element index | +//| | +//| Return value: None | +//+------------------------------------------------------------------+ +void QuickSortAscending(float &array[],int first,int last) + { + int i,j; + float p_float,t_float; + if(first<0 || last<0) + return; + i=first; + j=last; + while(i>1]; + while(ip_float) + { + if(j==0) + break; + j--; + } + if(i<=j) + { + //-- swap elements i and j + t_float=array[i]; + array[i]=array[j]; + array[j]=t_float; + i++; + if(j==0) + break; + j--; + } + } + if(first>1; +//--- + uint passes_total=0; + uint stages_total=0; +//--- + for(uint temp=data_count; temp>1; temp>>=1) + stages_total++; +//--- GPU calculation start + time_gpu=GetMicrosecondCount(); + for(uint stage=0; stage +#include + +#resource "Kernels/fft.cl" as string cl_program +#define kernel_init "fft_init" +#define kernel_stage "fft_stage" +#define kernel_scale "fft_scale" +#define NUM_POINTS 16384 +#define FFT_DIRECTION 1 +//+------------------------------------------------------------------+ +//| Fast Fourier transform and its inverse (both recursively) | +//| Copyright (C) 2004, Jerome R. Breitenbach. All rights reserved. | +//| Reference: | +//| Matthew Scarpino, "OpenCL in Action: How to accelerate graphics | +//| and computations", Manning, 2012, Chapter 14. | +//+------------------------------------------------------------------+ +//| Recursive direct FFT transform | +//+------------------------------------------------------------------+ +void fft(const int N,float &x_real[],float &x_imag[],float &X_real[],float &X_imag[]) + { +//--- prepare temporary arrays + float XX_real[],XX_imag[]; + ArrayResize(XX_real,N); + ArrayResize(XX_imag,N); +//--- calculate FFT by a recursion + fft_rec(N,0,1,x_real,x_imag,X_real,X_imag,XX_real,XX_imag); + } +//+------------------------------------------------------------------+ +//| Recursive inverse FFT transform | +//+------------------------------------------------------------------+ +void ifft(const int N,float &x_real[],float &x_imag[],float &X_real[],float &X_imag[]) + { + int N2=N/2; // half the number of points in IFFT +//--- calculate IFFT via reciprocity property of DFT + fft(N,X_real,X_imag,x_real,x_imag); + x_real[0]=x_real[0]/N; + x_imag[0]=x_imag[0]/N; + x_real[N2]=x_real[N2]/N; + x_imag[N2]=x_imag[N2]/N; + for(int i=1; i0) + fft(N,data_real,data_imag,XX_real,XX_imag); + else + ifft(N,XX_real,XX_imag,data_real,data_imag); +//--- CPU calculation finished + time_cpu=ulong((GetMicrosecondCount()-time_cpu)); +//--- copy calculated data + ArrayCopy(data_real,XX_real,0,0,WHOLE_ARRAY); + ArrayCopy(data_imag,XX_imag,0,0,WHOLE_ARRAY); +//--- + return(true); + } +//+------------------------------------------------------------------+ +//| FFT_GPU | +//+------------------------------------------------------------------+ +bool FFT_GPU(int direction,int power,float &data_real[],float &data_imag[],ulong &time_gpu) + { +//--- calculate the number of points + int num_points=1; + for(int i=0;inum_points) + points_per_group=num_points; +//--- set kernel arguments + OpenCL.SetArgumentBuffer(0,0,0); + OpenCL.SetArgumentBuffer(0,1,1); + OpenCL.SetArgumentLocalMemory(0,2,local_mem_size); + OpenCL.SetArgument(0,3,points_per_group); + OpenCL.SetArgument(0,4,num_points); + OpenCL.SetArgument(0,5,direction); +//--- OpenCL execute settings + int task_dimension=1; + uint global_size=(uint)((num_points/points_per_group)*local_size); + uint global_work_offset[1]={0}; + uint global_work_size[1]; + global_work_size[0]=global_size; + uint local_work_size[1]; + local_work_size[0]=local_size; +//--- GPU calculation start + time_gpu=GetMicrosecondCount(); +//-- execute kernel fft_init + if(!OpenCL.Execute(0,task_dimension,global_work_offset,global_work_size,local_work_size)) + { + PrintFormat("fft_init: Error in CLExecute. Error code=%d",GetLastError()); + return(false); + } +//-- further stages of the FFT + if(num_points>points_per_group) + { + //--- set arguments for kernel 1 + OpenCL.SetArgumentBuffer(1,0,1); + OpenCL.SetArgument(1,2,points_per_group); + OpenCL.SetArgument(1,3,direction); + for(int stage=2; stage<=num_points/points_per_group; stage<<=1) + { + OpenCL.SetArgument(1,1,stage); + //-- execute kernel fft_stage + if(!OpenCL.Execute(1,task_dimension,global_work_offset,global_work_size,local_work_size)) + { + PrintFormat("fft_stage: Error in CLExecute. Error code=%d",GetLastError()); + return(false); + } + } + } +//--- scale values if performing the inverse FFT + if(direction<0) + { + OpenCL.SetArgumentBuffer(2,0,1); + OpenCL.SetArgument(2,1,points_per_group); + OpenCL.SetArgument(2,2,num_points); + //-- execute kernel fft_scale + if(!OpenCL.Execute(2,task_dimension,global_work_offset,global_work_size,local_work_size)) + { + PrintFormat("fft_scale: Error in CLExecute. Error code=%d",GetLastError()); + return(false); + } + } +//--- read the results from GPU memory + if(!OpenCL.BufferRead(1,data,0,0,2*num_points)) + { + PrintFormat("Error in BufferRead for data_buffer2. Error code=%d",GetLastError()); + return(false); + } +//--- GPU calculation finished + time_gpu=ulong((GetMicrosecondCount()-time_gpu)); +//--- copy calculated data and release OpenCL handles + for(int i=0; i>(stage-pass))*(distance<<1); + uint right_id=left_id+distance; + float left_value=data[left_id]; + float right_value=data[right_id]; + uint same_direction=(id>>stage)&0x1; + uint temp = same_direction?right_id:temp; + right_id = same_direction?left_id:right_id; + left_id = same_direction?temp:left_id; + int compare_res=(left_value> N2) & stage; + //--- bit-reverse addresses + while(N2>1) + { + N2-=2; + fft_index>>=1; + stage<<=1; + br |= (index << N2) & fft_index; + br |= (index >> N2) & stage; + } + //--- load global data + x1 = in_data[br.s0]; + x2 = in_data[br.s1]; + x3 = in_data[br.s2]; + x4 = in_data[br.s3]; + + sum12=x1+x2; + diff12= x1-x2; + sum34 = x3+x4; + diff34=(float2)(x3.s1-x4.s1,x4.s0-x3.s0)*dir; + l_data[l_addr]=sum12+sum34; + l_data[l_addr+1] = diff12 + diff34; + l_data[l_addr+2] = sum12 - sum34; + l_data[l_addr+3] = diff12 - diff34; + l_addr += 4; + g_addr += 4; + } +//--- perform initial stages of the FFT - each of length N2*2 + for(N2=4; N2 +//--- OpenCL kernels +#resource "Kernels/matrixmult.cl" as string cl_program +#define BLOCK_SIZE 10 +//+------------------------------------------------------------------+ +//| MatrixMult_CPU | +//+------------------------------------------------------------------+ +bool MatrixMult_CPU(const float &matrix_a[],const float &matrix_b[],float &matrix_c[], + const int rows_a,const int cols_a,const int cols_b,ulong &time_cpu) + { + int size=rows_a*cols_b; + if(ArrayResize(matrix_c,size)!=size) + return(false); +//--- CPU calculation started + time_cpu=GetMicrosecondCount(); + for(int i=0; i +#include +#include + +#define CPU_DATA 1 +#define GPU_DATA 2 + +#define SIZE_X 600 +#define SIZE_Y 200 + +#resource "Kernels/wavelet.cl" as string cl_program +//+------------------------------------------------------------------+ +//| CWavelet | +//+------------------------------------------------------------------+ +class CWavelet + { +protected: + int m_xsize; + int m_ysize; + int m_maxcolor; + string m_res_name; + string m_label_name; + uchar m_palette[3*256]; + //--- + float m_data[]; + float m_wavelet_data_CPU[]; + float m_wavelet_data_GPU[]; + uint m_bmp_buffer[]; + + COpenCL m_OpenCL; + + float Morlet(const float t); + void ShowWaveletData(const float &m_wavelet_data[]); + int GetPalColor(const int index); + void Blend(const uint c1,const uint c2,const uint r1,const uint g1,const uint b1,const uint r2,const uint g2,const uint b2); + bool WaveletCPU(const float &data[],const int datacount,const int x_size,const int y_size,const int i,const int j,const bool norm,float &result[]); +public: + //--- + void Create(const string name,const int x0,const int y0,const int x_size,const int y_size); + bool CalculateWavelet_CPU(const float &data[],uint &time); + bool CalculateWavelet_GPU(float &data[],uint &time); + void ShowWavelet(const int mode); + }; +//+------------------------------------------------------------------+ +//| Morlet wavelet function | +//+------------------------------------------------------------------+ +float CWavelet::Morlet(const float t) + { + double v=t; + double res=MathExp(-v*v*0.5)*MathCos(M_2_PI*v); + return ((float)res); + } +//+------------------------------------------------------------------+ +//| GetPalColor | +//+------------------------------------------------------------------+ +int CWavelet::GetPalColor(const int index) + { + int ind=index; + if(ind<=0) + ind=0; + if(ind>255) + ind=255; + int idx=3*(ind); + uchar r=m_palette[idx]; + uchar g=m_palette[idx+1]; + uchar b=m_palette[idx+2]; +//--- + return(b+256*g+65536*r); + } +//+------------------------------------------------------------------+ +//| Gradient palette | +//+------------------------------------------------------------------+ +void CWavelet::Blend(const uint c1,const uint c2,const uint r1,const uint g1,const uint b1,const uint r2,const uint g2,const uint b2) + { + int n=int(c2-c1); + for(int i=0; i<=n; i++) + { + if((c1+i+2)0) + { + for(int j=0; jmax_value) + max_value=value; + + if(momentum_data[i] +#include +//--- +#include "OrderInfoSampleInit.mqh" +//+------------------------------------------------------------------+ +//| Script to testing the use of class COrderInfo. | +//+------------------------------------------------------------------+ +//--- +//+------------------------------------------------------------------+ +//| Order Info Sample script class | +//+------------------------------------------------------------------+ +class COrderInfoSample + { +protected: + COrderInfo m_order; + //--- chart objects + CChartObjectButton m_button_prev; + CChartObjectButton m_button_next; + CChartObjectLabel m_label[20]; + CChartObjectLabel m_label_info[20]; + //--- + int m_curr_ord; + int m_total_ord; + +public: + COrderInfoSample(void); + ~COrderInfoSample(void); + //--- + bool Init(void); + void Deinit(void); + void Processing(void); + +private: + void InfoToChart(void); + }; +//--- +COrderInfoSample ExtScript; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +COrderInfoSample::COrderInfoSample(void) : m_curr_ord(-1), + m_total_ord(-1) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +COrderInfoSample::~COrderInfoSample(void) + { + } +//+------------------------------------------------------------------+ +//| Method Init. | +//+------------------------------------------------------------------+ +bool COrderInfoSample::Init(void) + { + int i,sy=10; + int dy=16; + color color_label; + color color_info; +//--- tuning colors + color_info =(color)(ChartGetInteger(0,CHART_COLOR_BACKGROUND)^0xFFFFFF); + color_label=(color)(color_info^0x202020); +//--- + if(ChartGetInteger(0,CHART_SHOW_OHLC)) + sy+=16; +//--- creation Buttons + m_button_prev.Create(0,"ButtonPrev",0,10,sy,100,20); + m_button_prev.Description("Prev Order"); + m_button_prev.Color(Red); + m_button_prev.FontSize(8); +//--- + m_button_next.Create(0,"ButtonNext",0,110,sy,100,20); + m_button_next.Description("Next Order"); + m_button_next.Color(Red); + m_button_next.FontSize(8); +//--- + sy+=20; +//--- creation Labels[] + for(i=0;i<20;i++) + { + m_label[i].Create(0,"Label"+IntegerToString(i),0,20,sy+dy*i); + m_label[i].Description(init_str[i]); + m_label[i].Color(color_label); + m_label[i].FontSize(8); + //--- + m_label_info[i].Create(0,"LabelInfo"+IntegerToString(i),0,120,sy+dy*i); + m_label_info[i].Description(" "); + m_label_info[i].Color(color_info); + m_label_info[i].FontSize(8); + } + InfoToChart(); +//--- redraw chart + ChartRedraw(); +//--- + return(0); + } +//+------------------------------------------------------------------+ +//| Method Deinit. | +//+------------------------------------------------------------------+ +void COrderInfoSample::Deinit(void) + { + } +//+------------------------------------------------------------------+ +//| Method Processing. | +//+------------------------------------------------------------------+ +void COrderInfoSample::Processing(void) + { + ulong ticket; +//--- + if(m_total_ord!=OrdersTotal()) + { + m_total_ord=OrdersTotal(); + if(m_total_ord==0) + { + m_label_info[0].Description("0"); + m_label_info[1].Description(""); + m_curr_ord=-1; + return; + } + else + { + m_label_info[0].Description(IntegerToString(m_total_ord)); + if(m_curr_ord==-1) + m_curr_ord=0; + if(m_curr_ord>=m_total_ord) + m_curr_ord=m_total_ord-1; + m_label_info[1].Description(IntegerToString(m_curr_ord)); + } + } + if(m_button_prev.State()) + { + m_button_prev.State(false); + if(m_curr_ord>=0) + m_label_info[1].Description(IntegerToString(--m_curr_ord)); + } + if(m_button_next.State()) + { + m_button_next.State(false); + if(m_curr_ord +#include +//--- +#include "PositionInfoSampleInit.mqh" +//+------------------------------------------------------------------+ +//| Script to testing the use of class CPositionInfo. | +//+------------------------------------------------------------------+ +//--- +//+------------------------------------------------------------------+ +//| Position Info Sample script class | +//+------------------------------------------------------------------+ +class CPositionInfoSample + { +protected: + CPositionInfo m_position; + //--- chart objects + CChartObjectButton m_button_prev; + CChartObjectButton m_button_next; + CChartObjectLabel m_label[19]; + CChartObjectLabel m_label_info[19]; + //--- + int curr_pos; + int total_pos; + +public: + CPositionInfoSample(void); + ~CPositionInfoSample(void); + //--- + bool Init(); + void Deinit(); + void Processing(); + +private: + void CheckButtons(); + void InfoToChart(); + }; +//--- +CPositionInfoSample ExtScript; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CPositionInfoSample::CPositionInfoSample(void) : curr_pos(-1), + total_pos(-1) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CPositionInfoSample::~CPositionInfoSample(void) + { + } +//+------------------------------------------------------------------+ +//| Method Init. | +//+------------------------------------------------------------------+ +bool CPositionInfoSample::Init(void) + { + int i,sy=10; + int dy=16; + color color_label; + color color_info; +//--- tuning colors + color_info =(color)(ChartGetInteger(0,CHART_COLOR_BACKGROUND)^0xFFFFFF); + color_label=(color)(color_info^0x202020); +//--- + if(ChartGetInteger(0,CHART_SHOW_OHLC)) + sy+=16; +//--- creation Buttons + m_button_prev.Create(0,"ButtonPrev",0,10,sy,100,20); + m_button_prev.Description("Prev Position"); + m_button_prev.Color(Red); + m_button_prev.FontSize(8); +//--- + m_button_next.Create(0,"ButtonNext",0,110,sy,100,20); + m_button_next.Description("Next Position"); + m_button_next.Color(Red); + m_button_next.FontSize(8); +//--- + sy+=20; +//--- creation Labels[] + for(i=0;i<13;i++) + { + m_label[i].Create(0,"Label"+IntegerToString(i),0,20,sy+dy*i); + m_label[i].Description(init_str[i]); + m_label[i].Color(color_label); + m_label[i].FontSize(8); + //--- + m_label_info[i].Create(0,"LabelInfo"+IntegerToString(i),0,120,sy+dy*i); + m_label_info[i].Description(" "); + m_label_info[i].Color(color_info); + m_label_info[i].FontSize(8); + } + InfoToChart(); +//--- redraw chart + ChartRedraw(); +//--- + return(0); + } +//+------------------------------------------------------------------+ +//| Method Deinit. | +//+------------------------------------------------------------------+ +void CPositionInfoSample::Deinit(void) + { + } +//+------------------------------------------------------------------+ +//| Method Processing. | +//+------------------------------------------------------------------+ +void CPositionInfoSample::Processing(void) + { + if(total_pos!=PositionsTotal()) + { + total_pos=PositionsTotal(); + if(total_pos==0) + { + m_label_info[0].Description("0"); + m_label_info[1].Description(""); + curr_pos=-1; + return; + } + else + { + m_label_info[0].Description(IntegerToString(total_pos)); + if(curr_pos==-1) + curr_pos=0; + if(curr_pos>=total_pos) + curr_pos=total_pos-1; + m_label_info[1].Description(IntegerToString(curr_pos)); + } + } + CheckButtons(); + PositionSelect(PositionGetSymbol(curr_pos)); + InfoToChart(); +//--- redraw chart + ChartRedraw(); + Sleep(250); + } +//+------------------------------------------------------------------+ +//| Method InfoToChart. | +//+------------------------------------------------------------------+ +void CPositionInfoSample::CheckButtons(void) + { + if(m_button_prev.State()) + { + m_button_prev.State(false); + if(curr_pos>0) + m_label_info[1].Description(IntegerToString(--curr_pos)); + } + if(m_button_next.State()) + { + m_button_next.State(false); + if(curr_pos +#include +//--- +#include "SymbolInfoSampleInit.mqh" +//+------------------------------------------------------------------+ +//| Script to sample the use of class CSymbolInfo. | +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ +//| Symbol Info Sample script class | +//+------------------------------------------------------------------+ +class CSymbolInfoSample + { +protected: + CSymbolInfo m_symbol; + //--- chart objects + CChartObjectButton m_buttons[]; + int m_num_symbols; + CChartObjectLabel m_label[40]; + CChartObjectLabel m_label_info[40]; + //--- + int m_symbol_idx; + +public: + CSymbolInfoSample(void); + ~CSymbolInfoSample(void); + //--- + bool Init(void); + void Deinit(void); + void Processing(void); + +private: + void InfoToChart(void); + }; +//--- +CSymbolInfoSample ExtScript; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CSymbolInfoSample::CSymbolInfoSample(void) : m_symbol_idx(0) + { + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CSymbolInfoSample::~CSymbolInfoSample(void) + { + } +//+------------------------------------------------------------------+ +//| Method Init. | +//+------------------------------------------------------------------+ +bool CSymbolInfoSample::Init(void) + { + int i,sy=10; + int dy=16; + color color_label; + color color_info; +//--- tuning colors + color_info =(color)(ChartGetInteger(0,CHART_COLOR_BACKGROUND)^0xFFFFFF); + color_label=(color)(color_info^0x202020); +//--- + if(ChartGetInteger(0,CHART_SHOW_OHLC)) sy+=16; +//--- + m_num_symbols=SymbolsTotal(InpMarketWatch); + ArrayResize(m_buttons,m_num_symbols); +//--- creation Button[] + for(i=0;i +#include +#include +#include +#include +#include +//+------------------------------------------------------------------+ +//| Testing class CHighQualityRand | +//+------------------------------------------------------------------+ +class CTestHQRndUnit + { +public: + CTestHQRndUnit(void); + ~CTestHQRndUnit(void); + + static bool TestHQRnd(const bool silent); + +private: + static void CalculateMV(double &x[],const int n,double &mean,double &means,double &stddev,double &stddevs); + static void UnsetState(CHighQualityRandState &state); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestHQRndUnit::CTestHQRndUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestHQRndUnit::~CTestHQRndUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CHighQualityRand | +//+------------------------------------------------------------------+ +static bool CTestHQRndUnit::TestHQRnd(const bool silent) + { + bool waserrors; + int samplesize=0; + double sigmathreshold=0; + int passcount=0; + int n=0; + int i=0; + int pass=0; + int s1=0; + int s2=0; + int i1=0; + int i2=0; + double r1=0; + double r2=0; + double mean=0; + double means=0; + double stddev=0; + double stddevs=0; + double lambdav=0; + bool seederrors; + bool urerrors; + double ursigmaerr=0; + bool uierrors; + double uisigmaerr=0; + bool normerrors; + double normsigmaerr=0; + bool experrors; + double expsigmaerr=0; +//--- create array + double x[]; +//--- object of class + CHighQualityRandState state; +//--- initialization + waserrors=false; + sigmathreshold=7; + samplesize=100000; + passcount=50; + seederrors=false; + urerrors=false; + uierrors=false; + normerrors=false; + experrors=false; +//--- allocation + ArrayResize(x,samplesize); +//--- Test seed errors + for(pass=1;pass<=passcount;pass++) + { + //--- change values + s1=1+CMath::RandomInteger(32000); + s2=1+CMath::RandomInteger(32000); + //--- function calls + UnsetState(state); + CHighQualityRand::HQRndSeed(s1,s2,state); + //--- change value + i1=CHighQualityRand::HQRndUniformI(state,100); + //--- function calls + UnsetState(state); + CHighQualityRand::HQRndSeed(s1,s2,state); + //--- change values + i2=CHighQualityRand::HQRndUniformI(state,100); + seederrors=seederrors || i1!=i2; + //--- function calls + UnsetState(state); + CHighQualityRand::HQRndSeed(s1,s2,state); + //--- change value + r1=CHighQualityRand::HQRndUniformR(state); + //--- function calls + UnsetState(state); + CHighQualityRand::HQRndSeed(s1,s2,state); + //--- change values + r2=CHighQualityRand::HQRndUniformR(state); + seederrors=seederrors || r1!=r2; + } +//--- Test HQRNDRandomize() and real uniform generator + UnsetState(state); + CHighQualityRand::HQRndRandomize(state); +//--- change values + ursigmaerr=0; + for(i=0;i<=samplesize-1;i++) + x[i]=CHighQualityRand::HQRndUniformR(state); + for(i=0;i<=samplesize-1;i++) + urerrors=(urerrors || x[i]<=0.0) || x[i]>=1.0; +//--- function call + CalculateMV(x,samplesize,mean,means,stddev,stddevs); +//--- check + if(means!=0.0) + ursigmaerr=MathMax(ursigmaerr,MathAbs((mean-0.5)/means)); + else + urerrors=true; +//--- check + if(stddevs!=0.0) + ursigmaerr=MathMax(ursigmaerr,MathAbs((stddev-MathSqrt(1.0/12.0))/stddevs)); + else + urerrors=true; +//--- change value + urerrors=urerrors || ursigmaerr>sigmathreshold; +//--- Test HQRNDRandomize() and integer uniform + UnsetState(state); + CHighQualityRand::HQRndRandomize(state); +//--- calculation + uisigmaerr=0; + for(n=2;n<=10;n++) + { + for(i=0;i<=samplesize-1;i++) + x[i]=CHighQualityRand::HQRndUniformI(state,n); + for(i=0;i<=samplesize-1;i++) + uierrors=(uierrors || x[i]<0.0) || x[i]>=n; + //--- function call + CalculateMV(x,samplesize,mean,means,stddev,stddevs); + //--- check + if(means!=0.0) + uisigmaerr=MathMax(uisigmaerr,MathAbs((mean-0.5*(n-1))/means)); + else + uierrors=true; + //--- check + if(stddevs!=0.0) + uisigmaerr=MathMax(uisigmaerr,MathAbs((stddev-MathSqrt((CMath::Sqr(n)-1)/12))/stddevs)); + else + uierrors=true; + } +//--- change values + uierrors=uierrors || 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) + UnsetState(state); + CHighQualityRand::HQRndRandomize(state); +//--- change values + uisigmaerr=0; + n=1431655708; +//--- calculation + for(i=0;i<=samplesize-1;i++) + x[i]=CHighQualityRand::HQRndUniformI(state,n); + for(i=0;i<=samplesize-1;i++) + uierrors=(uierrors || x[i]<0.0) || x[i]>=n; +//--- function call + CalculateMV(x,samplesize,mean,means,stddev,stddevs); +//--- check + if(means!=0.0) + uisigmaerr=MathMax(uisigmaerr,MathAbs((mean-0.5*(n-1))/means)); + else + uierrors=true; +//--- check + if(stddevs!=0.0) + uisigmaerr=MathMax(uisigmaerr,MathAbs((stddev-MathSqrt((CMath::Sqr(n)-1)/12))/stddevs)); + else + uierrors=true; + uierrors=uierrors || uisigmaerr>sigmathreshold; +//--- Test normal + UnsetState(state); + CHighQualityRand::HQRndRandomize(state); +//--- change values + normsigmaerr=0; + i=0; +//--- cycle + while(isigmathreshold; +//--- Test exponential + UnsetState(state); + CHighQualityRand::HQRndRandomize(state); +//--- change values + expsigmaerr=0; + lambdav=2+5*CMath::RandomReal(); +//--- calculation + for(i=0;i<=samplesize-1;i++) + x[i]=CHighQualityRand::HQRndExponential(state,lambdav); + for(i=0;i<=samplesize-1;i++) + uierrors=uierrors || x[i]<0.0; +//--- function call + CalculateMV(x,samplesize,mean,means,stddev,stddevs); +//--- check + if(means!=0.0) + expsigmaerr=MathMax(expsigmaerr,MathAbs((mean-1.0/lambdav)/means)); + else + experrors=true; +//--- check + if(stddevs!=0.0) + expsigmaerr=MathMax(expsigmaerr,MathAbs((stddev-1.0/lambdav)/stddevs)); + else + experrors=true; + experrors=experrors || expsigmaerr>sigmathreshold; +//--- Final report + waserrors=(((seederrors || urerrors) || uierrors) || normerrors) || experrors; +//--- check + if(!silent) + { + Print("RNG TEST"); + //--- check + if(!seederrors) + Print("SEED TEST: OK"); + else + Print("SEED TEST: FAILED"); + //--- check + if(!urerrors) + Print("UNIFORM CONTINUOUS: OK"); + else + Print("UNIFORM CONTINUOUS: FAILED"); + //--- check + if(!uierrors) + Print("UNIFORM INTEGER: OK"); + else + Print("UNIFORM INTEGER: FAILED"); + //--- check + if(!normerrors) + Print("NORMAL: OK"); + else + Print("NORMAL: FAILED"); + //--- check + if(!experrors) + Print("EXPONENTIAL: OK"); + else + Print("EXPONENTIAL: FAILED"); + //--- check + if(waserrors) + Print("TEST SUMMARY: FAILED"); + else + Print("TEST SUMMARY: PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestHQRndUnit::CalculateMV(double &x[],const int n,double &mean, + double &means,double &stddev, + double &stddevs) + { +//--- create variables + int i=0; + double v1=0; + double v2=0; + double variance=0; +//--- initialization + mean=0; + means=1; + stddev=0; + stddevs=1; + variance=0; +//--- check + if(n<=1) + return; +//--- Mean + for(i=0;i<=n-1;i++) + mean=mean+x[i]; + mean=mean/n; +//--- Variance (using corrected two-pass algorithm) + if(n!=1) + { + //--- change value + v1=0; + for(i=0;i<=n-1;i++) + v1=v1+CMath::Sqr(x[i]-mean); + //--- change value + v2=0; + for(i=0;i<=n-1;i++) + v2=v2+(x[i]-mean); + //--- calculation + v2=CMath::Sqr(v2)/n; + variance=(v1-v2)/(n-1); + //--- check + if(variance<0.0) + variance=0; + stddev=MathSqrt(variance); + } +//--- Errors + means=stddev/MathSqrt(n); + stddevs=stddev*MathSqrt(2)/MathSqrt(n-1); + } +//+------------------------------------------------------------------+ +//| Unsets HQRNDState structure | +//+------------------------------------------------------------------+ +static void CTestHQRndUnit::UnsetState(CHighQualityRandState &state) + { + state.m_s1=0; + state.m_s2=0; + state.m_v=0; + state.m_magicv=0; + } +//+------------------------------------------------------------------+ +//| Testing class CTSort | +//+------------------------------------------------------------------+ +class CTestTSortUnit + { +public: + CTestTSortUnit(void); + ~CTestTSortUnit(void); + + static bool TestTSort(const bool silent); + +private: + static void Unset2D(CMatrixComplex &a); + static void Unset1D(double &a[]); + static void Unset1DI(int &a[]); + static void TestSortResults(double &asorted[],int &p1[],int &p2[],double &aoriginal[],const int n,bool &waserrors); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestTSortUnit::CTestTSortUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestTSortUnit::~CTestTSortUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CTSort | +//+------------------------------------------------------------------+ +static bool CTestTSortUnit::TestTSort(const bool silent) + { +//--- create variables + bool waserrors; + int n=0; + int i=0; + int pass=0; + int passcount=0; + int maxn=0; +//--- create arrays + double a[]; + double a0[]; + double a1[]; + double a2[]; + double a3[]; + double ar[]; + int ai[]; + int p1[]; + int p2[]; + double bufr1[]; + double bufr2[]; + int bufi1[]; +//--- initialization + waserrors=false; + maxn=100; + passcount=10; +//--- Test tagsort + for(n=1;n<=maxn;n++) + { + for(pass=1;pass<=passcount;pass++) + { + //--- (probably) distinct sort: + //--- * first sort A0 using TagSort and test sort results + //--- * now we can use A0 as reference point and test other functions + Unset1DI(p1); + Unset1DI(p2); + //--- allocation + ArrayResize(a,n); + ArrayResize(a0,n); + ArrayResize(a1,n); + ArrayResize(a2,n); + ArrayResize(a3,n); + ArrayResize(ar,n); + ArrayResize(ai,n); + //--- change values + for(i=0;i<=n-1;i++) + { + a[i]=2*CMath::RandomReal()-1; + a0[i]=a[i]; + a1[i]=a[i]; + a2[i]=a[i]; + a3[i]=a[i]; + ar[i]=i; + ai[i]=i; + } + //--- function call + CTSort::TagSort(a0,n,p1,p2); + //--- function call + TestSortResults(a0,p1,p2,a,n,waserrors); + //--- function call + CTSort::TagSortFastI(a1,ai,bufr1,bufi1,n); + //--- search errors + for(i=0;i<=n-1;i++) + waserrors=(waserrors || a1[i]!=a0[i]) || ai[i]!=p1[i]; + //--- function call + CTSort::TagSortFastR(a2,ar,bufr1,bufr2,n); + //--- search errors + for(i=0;i<=n-1;i++) + waserrors=(waserrors || a2[i]!=a0[i]) || ar[i]!=p1[i]; + //--- function call + CTSort::TagSortFast(a3,bufr1,n); + //--- search errors + for(i=0;i<=n-1;i++) + waserrors=waserrors || a3[i]!=a0[i]; + //--- non-distinct sort + Unset1DI(p1); + Unset1DI(p2); + //--- allocation + ArrayResize(a,n); + ArrayResize(a0,n); + ArrayResize(a1,n); + ArrayResize(a2,n); + ArrayResize(a3,n); + ArrayResize(ar,n); + ArrayResize(ai,n); + //--- change values + for(i=0;i<=n-1;i++) + { + a[i]=i/2; + a0[i]=a[i]; + a1[i]=a[i]; + a2[i]=a[i]; + a3[i]=a[i]; + ar[i]=i; + ai[i]=i; + } + //--- function call + CTSort::TagSort(a0,n,p1,p2); + //--- function call + TestSortResults(a0,p1,p2,a,n,waserrors); + //--- function call + CTSort::TagSortFastI(a1,ai,bufr1,bufi1,n); + //--- search errors + for(i=0;i<=n-1;i++) + waserrors=(waserrors || a1[i]!=a0[i]) || ai[i]!=p1[i]; + //--- function call + CTSort::TagSortFastR(a2,ar,bufr1,bufr2,n); + //--- search errors + for(i=0;i<=n-1;i++) + waserrors=(waserrors || a2[i]!=a0[i]) || ar[i]!=p1[i]; + //--- function call + CTSort::TagSortFast(a3,bufr1,n); + //--- search errors + for(i=0;i<=n-1;i++) + waserrors=waserrors || a3[i]!=a0[i]; + //--- 'All same' sort + Unset1DI(p1); + Unset1DI(p2); + //--- allocation + ArrayResize(a,n); + ArrayResize(a0,n); + ArrayResize(a1,n); + ArrayResize(a2,n); + ArrayResize(a3,n); + ArrayResize(ar,n); + ArrayResize(ai,n); + //--- change values + for(i=0;i<=n-1;i++) + { + a[i]=0; + a0[i]=a[i]; + a1[i]=a[i]; + a2[i]=a[i]; + a3[i]=a[i]; + ar[i]=i; + ai[i]=i; + } + //--- function call + CTSort::TagSort(a0,n,p1,p2); + //--- function call + TestSortResults(a0,p1,p2,a,n,waserrors); + //--- function call + CTSort::TagSortFastI(a1,ai,bufr1,bufi1,n); + //--- search errors + for(i=0;i<=n-1;i++) + waserrors=(waserrors || a1[i]!=a0[i]) || ai[i]!=p1[i]; + //--- function call + CTSort::TagSortFastR(a2,ar,bufr1,bufr2,n); + //--- search errors + for(i=0;i<=n-1;i++) + waserrors=(waserrors || a2[i]!=a0[i]) || ar[i]!=p1[i]; + //--- function call + CTSort::TagSortFast(a3,bufr1,n); + //--- search errors + for(i=0;i<=n-1;i++) + waserrors=waserrors || a3[i]!=a0[i]; + //--- 0-1 sort + Unset1DI(p1); + Unset1DI(p2); + //--- allocation + ArrayResize(a,n); + ArrayResize(a0,n); + ArrayResize(a1,n); + ArrayResize(a2,n); + ArrayResize(a3,n); + ArrayResize(ar,n); + ArrayResize(ai,n); + //--- change values + for(i=0;i<=n-1;i++) + { + a[i]=CMath::RandomInteger(2); + a0[i]=a[i]; + a1[i]=a[i]; + a2[i]=a[i]; + a3[i]=a[i]; + ar[i]=i; + ai[i]=i; + } + //--- function call + CTSort::TagSort(a0,n,p1,p2); + //--- function call + TestSortResults(a0,p1,p2,a,n,waserrors); + //--- function call + CTSort::TagSortFastI(a1,ai,bufr1,bufi1,n); + //--- search errors + for(i=0;i<=n-1;i++) + waserrors=(waserrors || a1[i]!=a0[i]) || ai[i]!=p1[i]; + //--- function call + CTSort::TagSortFastR(a2,ar,bufr1,bufr2,n); + //--- search errors + for(i=0;i<=n-1;i++) + waserrors=(waserrors || a2[i]!=a0[i]) || ar[i]!=p1[i]; + //--- function call + CTSort::TagSortFast(a3,bufr1,n); + //--- search errors + for(i=0;i<=n-1;i++) + waserrors=waserrors || a3[i]!=a0[i]; + } + } +//--- report + if(!silent) + { + Print("TESTING TAGSORT"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Unsets 2D array. | +//+------------------------------------------------------------------+ +static void CTestTSortUnit::Unset2D(CMatrixComplex &a) + { +//--- allocation + a.Resize(1,1); +//--- change value + a[0].Set(0,2*CMath::RandomReal()-1); + } +//+------------------------------------------------------------------+ +//| Unsets 1D array. | +//+------------------------------------------------------------------+ +static void CTestTSortUnit::Unset1D(double &a[]) + { +//--- allocation + ArrayResize(a,1); +//--- change value + a[0]=2*CMath::RandomReal()-1; + } +//+------------------------------------------------------------------+ +//| Unsets 1D array. | +//+------------------------------------------------------------------+ +static void CTestTSortUnit::Unset1DI(int &a[]) + { +//--- allocation + ArrayResize(a,1); +//--- change value + a[0]=CMath::RandomInteger(3)-1; + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestTSortUnit::TestSortResults(double &asorted[],int &p1[], + int &p2[],double &aoriginal[], + const int n,bool &waserrors) + { +//--- create variables + int i=0; + double t=0; +//--- create arrays + double a2[]; + int f[]; +//--- allocation + ArrayResize(a2,n); + ArrayResize(f,n); +//--- is set ordered? + for(i=0;i<=n-2;i++) + waserrors=waserrors || asorted[i]>asorted[i+1]; +//--- P1 correctness + for(i=0;i<=n-1;i++) + waserrors=waserrors || asorted[i]!=aoriginal[p1[i]]; +//--- change values + for(i=0;i<=n-1;i++) + f[i]=0; + for(i=0;i<=n-1;i++) + f[p1[i]]=f[p1[i]]+1; +//--- search errors + for(i=0;i<=n-1;i++) + waserrors=waserrors || f[i]!=1; +//--- P2 correctness + for(i=0;i<=n-1;i++) + a2[i]=aoriginal[i]; + for(i=0;i<=n-1;i++) + { + //--- check + if(p2[i]!=i) + { + t=a2[i]; + a2[i]=a2[p2[i]]; + a2[p2[i]]=t; + } + } +//--- search errors + for(i=0;i<=n-1;i++) + waserrors=waserrors || asorted[i]!=a2[i]; + } +//+------------------------------------------------------------------+ +//| Testing class CNearestNeighbor | +//+------------------------------------------------------------------+ +class CTestNearestNeighborUnit + { +public: + CTestNearestNeighborUnit(void); + ~CTestNearestNeighborUnit(void); + + static bool TestNearestNeighbor(const bool silent); + static void Unset2D(CMatrixComplex &a); + static void Unset1D(double &a[]); + static bool KDTResultsDifferent(CMatrixDouble &refxy,const int ntotal,CMatrixDouble &qx,CMatrixDouble &qxy,int &qt[],const int n,const int nx,const int ny); + static double VNorm(double &x[],const int n,const int normtype); + static void TestKDTUniform(CMatrixDouble &xy,const int n,const int nx,const int ny,const int normtype,bool &kdterrors); + +private: + static void TestKDTreeSerialization(bool &err); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestNearestNeighborUnit::CTestNearestNeighborUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestNearestNeighborUnit::~CTestNearestNeighborUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CNearestNeighbor | +//+------------------------------------------------------------------+ +static bool CTestNearestNeighborUnit::TestNearestNeighbor(const bool silent) + { +//--- create variables + int i=0; + int j=0; + double v=0; + int normtype=0; + int nx=0; + int ny=0; + int n=0; + int smalln=0; + int largen=0; + int passcount=0; + int pass=0; + bool waserrors; + bool kdterrors; +//--- create matrix + CMatrixDouble xy; +//--- initialization + kdterrors=false; + passcount=2; + smalln=256; + largen=2048; + ny=3; +//--- function call + TestKDTreeSerialization(kdterrors); +//--- calculation + for(pass=1;pass<=passcount;pass++) + { + for(normtype=0;normtype<=2;normtype++) + { + for(nx=1;nx<=3;nx++) + { + //--- Test in hypercube + xy.Resize(largen,nx+ny); + for(i=0;i<=largen-1;i++) + { + for(j=0;j<=nx+ny-1;j++) + xy[i].Set(j,10*CMath::RandomReal()-5); + } + //--- function calls + for(n=1;n<=10;n++) + TestKDTUniform(xy,n,nx,CMath::RandomInteger(ny+1),normtype,kdterrors); + TestKDTUniform(xy,largen,nx,CMath::RandomInteger(ny+1),normtype,kdterrors); + //--- Test clustered (2*N points,pairs of equal points) + xy.Resize(2*smalln,nx+ny); + for(i=0;i<=smalln-1;i++) + { + for(j=0;j<=nx+ny-1;j++) + { + xy[2*i].Set(j,10*CMath::RandomReal()-5); + xy[2*i+1].Set(j,xy[2*i][j]); + } + } + //--- function call + TestKDTUniform(xy,2*smalln,nx,CMath::RandomInteger(ny+1),normtype,kdterrors); + //--- Test degenerate case: all points are same except for one + xy.Resize(smalln,nx+ny); + v=CMath::RandomReal(); + //--- change values + for(i=0;i<=smalln-2;i++) + { + for(j=0;j<=nx+ny-1;j++) + xy[i].Set(j,v); + } + for(j=0;j<=nx+ny-1;j++) + xy[smalln-1].Set(j,10*CMath::RandomReal()-5); + //--- function call + TestKDTUniform(xy,smalln,nx,CMath::RandomInteger(ny+1),normtype,kdterrors); + } + } + } +//--- report + waserrors=kdterrors; +//--- check + if(!silent) + { + Print("TESTING NEAREST NEIGHBOR SEARCH"); + //--- check + if(!kdterrors) + Print("KD TREES: OK"); + else + Print("KD TREES: FAILED"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Unsets 2D array. | +//+------------------------------------------------------------------+ +static void CTestNearestNeighborUnit::Unset2D(CMatrixComplex &a) + { +//--- allocation + a.Resize(1,1); +//--- change value + a[0].Set(0,2*CMath::RandomReal()-1); + } +//+------------------------------------------------------------------+ +//| Unsets 1D array. | +//+------------------------------------------------------------------+ +static void CTestNearestNeighborUnit::Unset1D(double &a[]) + { +//--- allocation + ArrayResize(a,1); +//--- change value + a[0]=2*CMath::RandomReal()-1; + } +//+------------------------------------------------------------------+ +//| Compare results from different queries: | +//| * X just X-values | +//| * XY X-values and Y-values | +//| * XT X-values and tag values | +//+------------------------------------------------------------------+ +static bool CTestNearestNeighborUnit::KDTResultsDifferent(CMatrixDouble &refxy, + const int ntotal, + CMatrixDouble &qx, + CMatrixDouble &qxy, + int &qt[],const int n, + const int nx,const int ny) + { +//--- create variables + bool result; + int i=0; + int j=0; +//--- initialization + result=false; + for(i=0;i<=n-1;i++) + { + //--- check + if(qt[i]<0 || qt[i]>=ntotal) + { + //--- return result + return(true); + } + //--- search errors + for(j=0;j<=nx-1;j++) + { + result=result || qx[i][j]!=refxy[qt[i]][j]; + result=result || qxy[i][j]!=refxy[qt[i]][j]; + } + for(j=0;j<=ny-1;j++) + result=result || qxy[i][nx+j]!=refxy[qt[i]][nx+j]; + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Returns norm | +//+------------------------------------------------------------------+ +static double CTestNearestNeighborUnit::VNorm(double &x[],const int n, + const int normtype) + { +//--- create variables + double result=0; + int i=0; +//--- initialization + result=CMath::RandomReal(); +//--- check + if(normtype==0) + { + //--- calculation + result=0; + for(i=0;i<=n-1;i++) + result=MathMax(result,MathAbs(x[i])); + //--- return result + return(result); + } +//--- check + if(normtype==1) + { + //--- calculation + result=0; + for(i=0;i<=n-1;i++) + result=result+MathAbs(x[i]); + //--- return result + return(result); + } +//--- check + if(normtype==2) + { + //--- calculation + result=0; + for(i=0;i<=n-1;i++) + result=result+CMath::Sqr(x[i]); + result=MathSqrt(result); + //--- return result + return(result); + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Testing Nearest Neighbor Search on uniformly distributed | +//| hypercube | +//| NormType: 0,1,2 | +//| D: space dimension | +//| N: points count | +//+------------------------------------------------------------------+ +static void CTestNearestNeighborUnit::TestKDTUniform(CMatrixDouble &xy, + const int n,const int nx, + const int ny,const int normtype, + bool &kdterrors) + { +//--- create variables + double errtol=0; + int kx=0; + int kxy=0; + int kt=0; + double eps=0; + int i=0; + int j=0; + int k=0; + int task=0; + bool isequal; + double r=0; + int q=0; + int qcount=0; + int i_=0; +//--- create arrays + int tags[]; + double ptx[]; + double tmpx[]; + bool tmpb[]; + int qtags[]; + double qr[]; +//--- objects of classes + CKDTree treex; + CKDTree treexy; + CKDTree treext; +//--- create matrix + CMatrixDouble qx; + CMatrixDouble qxy; +//--- initialization + qcount=10; +//--- Tol - roundoff error tolerance (for '>=' comparisons) + errtol=100000*CMath::m_machineepsilon; +//--- fill tags + ArrayResize(tags,n); + for(i=0;i<=n-1;i++) + tags[i]=i; +//--- build trees + CNearestNeighbor::KDTreeBuild(xy,n,nx,0,normtype,treex); + CNearestNeighbor::KDTreeBuild(xy,n,nx,ny,normtype,treexy); + CNearestNeighbor::KDTreeBuildTagged(xy,tags,n,nx,0,normtype,treext); +//--- allocate arrays + ArrayResize(tmpx,nx); + ArrayResize(tmpb,n); + qx.Resize(n,nx); + qxy.Resize(n,nx+ny); + ArrayResize(qtags,n); + ArrayResize(qr,n); + ArrayResize(ptx,nx); +//--- 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(CMath::RandomReal()>0.5) + k=1+CMath::RandomInteger(n); + else + k=1; + //--- Select point (either one of the points,or random) + if(CMath::RandomReal()>0.5) + { + i=CMath::RandomInteger(n); + for(i_=0;i_<=nx-1;i_++) + ptx[i_]=xy[i][i_]; + } + else + { + for(i=0;i<=nx-1;i++) + ptx[i]=2*CMath::RandomReal()-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=CNearestNeighbor::KDTreeQueryKNN(treex,ptx,k,true); + kxy=CNearestNeighbor::KDTreeQueryKNN(treexy,ptx,k,true); + kt=CNearestNeighbor::KDTreeQueryKNN(treext,ptx,k,true); + //--- check + if((kx!=k || kxy!=k) || kt!=k) + { + kdterrors=true; + return; + } + //--- function calls + CNearestNeighbor::KDTreeQueryResultsXI(treex,qx); + CNearestNeighbor::KDTreeQueryResultsXYI(treexy,qxy); + CNearestNeighbor::KDTreeQueryResultsTagsI(treext,qtags); + CNearestNeighbor::KDTreeQueryResultsDistancesI(treext,qr); + //--- search errors + kdterrors=kdterrors || KDTResultsDifferent(xy,n,qx,qxy,qtags,k,nx,ny); + //--- function calls + CNearestNeighbor::KDTreeQueryResultsX(treex,qx); + CNearestNeighbor::KDTreeQueryResultsXY(treexy,qxy); + CNearestNeighbor::KDTreeQueryResultsTags(treext,qtags); + CNearestNeighbor::KDTreeQueryResultsDistances(treext,qr); + //--- search errors + kdterrors=kdterrors || KDTResultsDifferent(xy,n,qx,qxy,qtags,k,nx,ny); + //--- change values + for(i=0;i<=n-1;i++) + tmpb[i]=true; + r=0; + //--- calculation + for(i=0;i<=k-1;i++) + { + tmpb[qtags[i]]=false; + for(i_=0;i_<=nx-1;i_++) + tmpx[i_]=ptx[i_]; + for(i_=0;i_<=nx-1;i_++) + tmpx[i_]=tmpx[i_]-qx[i][i_]; + r=MathMax(r,VNorm(tmpx,nx,normtype)); + } + for(i=0;i<=n-1;i++) + { + //--- check + if(tmpb[i]) + { + for(i_=0;i_<=nx-1;i_++) + tmpx[i_]=ptx[i_]; + for(i_=0;i_<=nx-1;i_++) + tmpx[i_]=tmpx[i_]-xy[i][i_]; + //--- search errors + kdterrors=kdterrors || VNorm(tmpx,nx,normtype)qr[i+1]; + } + for(i=0;i<=k-1;i++) + { + for(i_=0;i_<=nx-1;i_++) + tmpx[i_]=ptx[i_]; + for(i_=0;i_<=nx-1;i_++) + tmpx[i_]=tmpx[i_]-xy[qtags[i]][i_]; + //--- search errors + kdterrors=kdterrors || MathAbs(VNorm(tmpx,nx,normtype)-qr[i])>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=CNearestNeighbor::KDTreeQueryKNN(treex,ptx,k,true); + kxy=CNearestNeighbor::KDTreeQueryKNN(treexy,ptx,k,true); + kt=CNearestNeighbor::KDTreeQueryKNN(treext,ptx,k,true); + //--- check + if((kx!=k || kxy!=k) || kt!=k) + { + kdterrors=true; + return; + } + //--- allocation + qx.Resize(1,1); + qxy.Resize(1,1); + ArrayResize(qtags,1); + ArrayResize(qr,1); + //--- function calls + CNearestNeighbor::KDTreeQueryResultsX(treex,qx); + CNearestNeighbor::KDTreeQueryResultsXY(treexy,qxy); + CNearestNeighbor::KDTreeQueryResultsTags(treext,qtags); + CNearestNeighbor::KDTreeQueryResultsDistances(treext,qr); + //--- search errors + kdterrors=kdterrors || KDTResultsDifferent(xy,n,qx,qxy,qtags,k,nx,ny); + //--- Second step: array is one row larger than needed,so only first + //--- row is overwritten. Test it. + k=1; + kx=CNearestNeighbor::KDTreeQueryKNN(treex,ptx,k,true); + kxy=CNearestNeighbor::KDTreeQueryKNN(treexy,ptx,k,true); + kt=CNearestNeighbor::KDTreeQueryKNN(treext,ptx,k,true); + //--- check + if((kx!=k || kxy!=k) || kt!=k) + { + kdterrors=true; + return; + } + //--- change values + for(i=0;i<=nx-1;i++) + qx[1].Set(i,CInfOrNaN::NaN()); + for(i=0;i<=nx+ny-1;i++) + qxy[1].Set(i,CInfOrNaN::NaN()); + qtags[1]=999; + qr[1]=CInfOrNaN::NaN(); + //--- function calls + CNearestNeighbor::KDTreeQueryResultsX(treex,qx); + CNearestNeighbor::KDTreeQueryResultsXY(treexy,qxy); + CNearestNeighbor::KDTreeQueryResultsTags(treext,qtags); + CNearestNeighbor::KDTreeQueryResultsDistances(treext,qr); + //--- search errors + kdterrors=kdterrors || KDTResultsDifferent(xy,n,qx,qxy,qtags,k,nx,ny); + for(i=0;i<=nx-1;i++) + { + //--- search errors + kdterrors=kdterrors || !CInfOrNaN::IsNaN(qx[1][i]); + } + for(i=0;i<=nx+ny-1;i++) + { + //--- search errors + kdterrors=kdterrors || !CInfOrNaN::IsNaN(qxy[1][i]); + } + //--- search errors + kdterrors=kdterrors || !(qtags[1]==999); + kdterrors=kdterrors || !CInfOrNaN::IsNaN(qr[1]); + } + //--- 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++) + { + //--- check + if(!CAp::Assert(k==1 || k==2,"KNN: internal error (unexpected K)!")) + return; + //--- change values + kx=CNearestNeighbor::KDTreeQueryKNN(treex,ptx,k,true); + kxy=CNearestNeighbor::KDTreeQueryKNN(treexy,ptx,k,true); + kt=CNearestNeighbor::KDTreeQueryKNN(treext,ptx,k,true); + //--- check + if((kx!=k || kxy!=k) || kt!=k) + { + kdterrors=true; + return; + } + //--- allocation + qx.Resize(3-k,3-k); + qxy.Resize(3-k,3-k); + ArrayResize(qtags,3-k); + ArrayResize(qr,3-k); + //--- function calls + CNearestNeighbor::KDTreeQueryResultsXI(treex,qx); + CNearestNeighbor::KDTreeQueryResultsXYI(treexy,qxy); + CNearestNeighbor::KDTreeQueryResultsTagsI(treext,qtags); + CNearestNeighbor::KDTreeQueryResultsDistancesI(treext,qr); + //--- search errors + kdterrors=kdterrors || KDTResultsDifferent(xy,n,qx,qxy,qtags,k,nx,ny); + kdterrors=(kdterrors || CAp::Rows(qx)!=k) || CAp::Cols(qx)!=nx; + kdterrors=(kdterrors || CAp::Rows(qxy)!=k) || CAp::Cols(qxy)!=nx+ny; + kdterrors=kdterrors || CAp::Len(qtags)!=k; + kdterrors=kdterrors || CAp::Len(qr)!=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(CMath::RandomReal()>0.5) + k=1+CMath::RandomInteger(n); + else + k=1; + //--- Select Eps + eps=0.5+CMath::RandomReal(); + //--- Select point (either one of the points,or random) + if(CMath::RandomReal()>0.5) + { + i=CMath::RandomInteger(n); + for(i_=0;i_<=nx-1;i_++) + ptx[i_]=xy[i][i_]; + } + else + { + for(i=0;i<=nx-1;i++) + ptx[i]=2*CMath::RandomReal()-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=CNearestNeighbor::KDTreeQueryAKNN(treex,ptx,k,true,eps); + kxy=CNearestNeighbor::KDTreeQueryAKNN(treexy,ptx,k,true,eps); + kt=CNearestNeighbor::KDTreeQueryAKNN(treext,ptx,k,true,eps); + //--- check + if((kx!=k || kxy!=k) || kt!=k) + { + kdterrors=true; + return; + } + //--- function calls + CNearestNeighbor::KDTreeQueryResultsXI(treex,qx); + CNearestNeighbor::KDTreeQueryResultsXYI(treexy,qxy); + CNearestNeighbor::KDTreeQueryResultsTagsI(treext,qtags); + CNearestNeighbor::KDTreeQueryResultsDistancesI(treext,qr); + //--- search errors + kdterrors=kdterrors || KDTResultsDifferent(xy,n,qx,qxy,qtags,k,nx,ny); + //--- function calls + CNearestNeighbor::KDTreeQueryResultsX(treex,qx); + CNearestNeighbor::KDTreeQueryResultsXY(treexy,qxy); + CNearestNeighbor::KDTreeQueryResultsTags(treext,qtags); + CNearestNeighbor::KDTreeQueryResultsDistances(treext,qr); + //--- search errors + kdterrors=kdterrors || KDTResultsDifferent(xy,n,qx,qxy,qtags,k,nx,ny); + //--- change values + for(i=0;i<=n-1;i++) + tmpb[i]=true; + r=0; + //--- calculation + for(i=0;i<=k-1;i++) + { + tmpb[qtags[i]]=false; + for(i_=0;i_<=nx-1;i_++) + tmpx[i_]=ptx[i_]; + for(i_=0;i_<=nx-1;i_++) + tmpx[i_]=tmpx[i_]-qx[i][i_]; + r=MathMax(r,VNorm(tmpx,nx,normtype)); + } + //--- calculation + for(i=0;i<=n-1;i++) + { + //--- check + if(tmpb[i]) + { + for(i_=0;i_<=nx-1;i_++) + tmpx[i_]=ptx[i_]; + for(i_=0;i_<=nx-1;i_++) + tmpx[i_]=tmpx[i_]-xy[i][i_]; + //--- search errors + kdterrors=kdterrors || VNorm(tmpx,nx,normtype)qr[i+1]; + } + //--- calculation + for(i=0;i<=k-1;i++) + { + for(i_=0;i_<=nx-1;i_++) + tmpx[i_]=ptx[i_]; + for(i_=0;i_<=nx-1;i_++) + tmpx[i_]=tmpx[i_]-xy[qtags[i]][i_]; + //--- search errors + kdterrors=kdterrors || MathAbs(VNorm(tmpx,nx,normtype)-qr[i])>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(CMath::RandomReal()>0.3) + r=MathMax(CMath::RandomReal(),CMath::m_machineepsilon); + else + r=CMath::m_machineepsilon; + //--- Select point (either one of the points,or random) + if(CMath::RandomReal()>0.5) + { + i=CMath::RandomInteger(n); + for(i_=0;i_<=nx-1;i_++) + ptx[i_]=xy[i][i_]; + } + else + { + for(i=0;i<=nx-1;i++) + ptx[i]=2*CMath::RandomReal()-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=CNearestNeighbor::KDTreeQueryRNN(treex,ptx,r,true); + kxy=CNearestNeighbor::KDTreeQueryRNN(treexy,ptx,r,true); + kt=CNearestNeighbor::KDTreeQueryRNN(treext,ptx,r,true); + //--- check + if(kxy!=kx || kt!=kx) + { + kdterrors=true; + return; + } + //--- function calls + CNearestNeighbor::KDTreeQueryResultsXI(treex,qx); + CNearestNeighbor::KDTreeQueryResultsXYI(treexy,qxy); + CNearestNeighbor::KDTreeQueryResultsTagsI(treext,qtags); + CNearestNeighbor::KDTreeQueryResultsDistancesI(treext,qr); + //--- search errors + kdterrors=kdterrors || KDTResultsDifferent(xy,n,qx,qxy,qtags,kx,nx,ny); + //--- function calls + CNearestNeighbor::KDTreeQueryResultsX(treex,qx); + CNearestNeighbor::KDTreeQueryResultsXY(treexy,qxy); + CNearestNeighbor::KDTreeQueryResultsTags(treext,qtags); + CNearestNeighbor::KDTreeQueryResultsDistances(treext,qr); + //--- search errors + kdterrors=kdterrors || KDTResultsDifferent(xy,n,qx,qxy,qtags,kx,nx,ny); + //--- change values + for(i=0;i<=n-1;i++) + tmpb[i]=true; + for(i=0;i<=kx-1;i++) + tmpb[qtags[i]]=false; + //--- calculation + for(i=0;i<=n-1;i++) + { + for(i_=0;i_<=nx-1;i_++) + tmpx[i_]=ptx[i_]; + for(i_=0;i_<=nx-1;i_++) + tmpx[i_]=tmpx[i_]-xy[i][i_]; + //--- check + if(tmpb[i]) + { + //--- search errors + kdterrors=kdterrors || VNorm(tmpx,nx,normtype)r*(1+errtol); + } + } + for(i=0;i<=kx-2;i++) + { + //--- search errors + kdterrors=kdterrors || qr[i]>qr[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++) + { + for(i_=0;i_<=nx-1;i_++) + ptx[i_]=xy[i][i_]; + //--- function calls + kx=CNearestNeighbor::KDTreeQueryKNN(treex,ptx,1,task==0); + CNearestNeighbor::KDTreeQueryResultsXI(treex,qx); + //--- check + if(kx!=1) + { + kdterrors=true; + return; + } + //--- change value + isequal=true; + for(j=0;j<=nx-1;j++) + isequal=isequal && qx[0][j]==ptx[j]; + //--- check + if(task==0) + kdterrors=kdterrors || !isequal; + else + kdterrors=kdterrors || isequal; + } + } + } + } +//+------------------------------------------------------------------+ +//| Testing serialization of KD trees | +//| This function sets Err to True on errors, but leaves it unchanged| +//| on success | +//+------------------------------------------------------------------+ +static void CTestNearestNeighborUnit::TestKDTreeSerialization(bool &err) + { +//--- create variables + int n=0; + int nx=0; + int ny=0; + int normtype=0; + int i=0; + int j=0; + int k=0; + int q=0; + double threshold=0; + int k0=0; + int k1=0; +//--- objects of classes + CKDTree tree0; + CKDTree tree1; +//--- create matrix + CMatrixDouble xy; + CMatrixDouble xy0; + CMatrixDouble xy1; +//--- create arrays + double x[]; + int tags[]; + int qsizes[]; + int tags0[]; + int tags1[]; + int i_=0; +//--- initialization + threshold=100*CMath::m_machineepsilon; +//--- different N,NX,NY,NormType + n=1; + while(n<=51) + { + //--- prepare array with query sizes + ArrayResize(qsizes,4); + qsizes[0]=1; + qsizes[1]=(int)(MathMin(2,n)); + qsizes[2]=(int)(MathMin(4,n)); + qsizes[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 + xy.Resize(n,nx+ny); + ArrayResize(tags,n); + //--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=nx+ny-1;j++) + xy[i].Set(j,CMath::RandomReal()); + tags[i]=CMath::RandomInteger(100); + } + //--- Build tree,pass it through serializer + CNearestNeighbor::KDTreeBuildTagged(xy,tags,n,nx,ny,normtype,tree0); + { + //--- This code passes data structure through serializers + //--- (serializes it to string and loads back) + CSerializer _local_serializer; + string _local_str; + //--- serialization + _local_serializer.Reset(); + _local_serializer.Alloc_Start(); + CNearestNeighbor::KDTreeAlloc(_local_serializer,tree0); + _local_serializer.SStart_Str(); + CNearestNeighbor::KDTreeSerialize(_local_serializer,tree0); + _local_serializer.Stop(); + _local_str=_local_serializer.Get_String(); + //--- unserialization + _local_serializer.Reset(); + _local_serializer.UStart_Str(_local_str); + CNearestNeighbor::KDTreeUnserialize(_local_serializer,tree1); + _local_serializer.Stop(); + } + //--- For each point of XY we make queries with different sizes + ArrayResize(x,nx); + for(k=0;k<=n-1;k++) + { + for(q=0;q<=CAp::Len(qsizes)-1;q++) + { + for(i_=0;i_<=nx-1;i_++) + x[i_]=xy[k][i_]; + //--- change values + k0=CNearestNeighbor::KDTreeQueryKNN(tree0,x,qsizes[q],true); + k1=CNearestNeighbor::KDTreeQueryKNN(tree1,x,qsizes[q],true); + //--- check + if(k0!=k1) + { + err=true; + return; + } + //--- function call + CNearestNeighbor::KDTreeQueryResultsXY(tree0,xy0); + //--- function call + CNearestNeighbor::KDTreeQueryResultsXY(tree1,xy1); + for(i=0;i<=k0-1;i++) + { + for(j=0;j<=nx+ny-1;j++) + { + //--- check + if(MathAbs(xy0[i][j]-xy1[i][j])>threshold) + { + err=true; + return; + } + } + } + //--- function call + CNearestNeighbor::KDTreeQueryResultsTags(tree0,tags0); + //--- function call + CNearestNeighbor::KDTreeQueryResultsTags(tree1,tags1); + for(i=0;i<=k0-1;i++) + { + //--- check + if(tags0[i]!=tags1[i]) + { + err=true; + return; + } + } + } + } + } + } + } + //--- Next N + n=n+25; + } + } +//+------------------------------------------------------------------+ +//| Testing class CAblas | +//+------------------------------------------------------------------+ +class CTestAblasUnit + { +public: + CTestAblasUnit(void); + ~CTestAblasUnit(void); + static bool TestAblas(const bool silent); + +private: + static void NaiveMatrixMatrixMultiply(CMatrixDouble &a,const int ai1,const int ai2,const int aj1,const int aj2,const bool transa,CMatrixDouble &b,const int bi1,const int bi2,const int bj1,const int bj2,const bool transb,const double alpha,CMatrixDouble &c,const int ci1,const int ci2,const int cj1,const int cj2,const double beta); + static bool TestTrsM(const int minn,const int maxn); + static bool TestSyrk(const int minn,const int maxn); + static bool TestGemm(const int minn,const int maxn); + static bool TestTrans(const int minn,const int maxn); + static bool TestRank1(const int minn,const int maxn); + static bool TestMV(const int minn,const int maxn); + static bool TestCopy(const int minn,const int maxn); + static void RefCMatrixRightTrsM(const int m,const int n,CMatrixComplex &a,const int i1,const int j1,const bool isupper,const bool isunit,const int optype,CMatrixComplex &x,const int i2,const int j2); + static void RefCMatrixLeftTrsM(const int m,const int n,CMatrixComplex &a,const int i1,const int j1,const bool isupper,const bool isunit,const int optype,CMatrixComplex &x,const int i2,const int j2); + static void RefRMatrixRightTrsM(const int m,const int n,CMatrixDouble &a,const int i1,const int j1,const bool isupper,const bool isunit,const int optype,CMatrixDouble &x,const int i2,const int j2); + static void RefRMatrixLeftTrsM(const int m,const int n,CMatrixDouble &a,const int i1,const int j1,const bool isupper,const bool isunit,const int optype,CMatrixDouble &x,const int i2,const int j2); + static bool InternalCMatrixTrInverse(CMatrixComplex &a,const int n,const bool isupper,const bool isunittriangular); + static bool InternalRMatrixTrInverse(CMatrixDouble &a,const int n,const bool isupper,const bool isunittriangular); + static void RefCMatrixSyrk(const int n,const int k,const double alpha,CMatrixComplex &a,const int ia,const int ja,const int optypea,const double beta,CMatrixComplex &c,const int ic,const int jc,const bool isupper); + static void RefRMatrixSyrk(const int n,const int k,const double alpha,CMatrixDouble &a,const int ia,const int ja,const int optypea,const double beta,CMatrixDouble &c,const int ic,const int jc,const bool isupper); + static void RefCMatrixGemm(const int m,const int n,const int k,complex &alpha,CMatrixComplex &a,const int ia,const int ja,const int optypea,CMatrixComplex &b,const int ib,const int jb,const int optypeb,complex &beta,CMatrixComplex &c,const int ic,const int jc); + static void RefRMatrixGemm(const int m,const int n,const int k,const double alpha,CMatrixDouble &a,const int ia,const int ja,const int optypea,CMatrixDouble &b,const int ib,const int jb,const int optypeb,const double beta,CMatrixDouble &c,const int ic,const int jc); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestAblasUnit::CTestAblasUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestAblasUnit::~CTestAblasUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CAblas | +//+------------------------------------------------------------------+ +static bool CTestAblasUnit::TestAblas(const bool silent) + { +//--- create variables + double threshold=0; + bool trsmerrors; + bool syrkerrors; + bool gemmerrors; + bool transerrors; + bool rank1errors; + bool mverrors; + bool copyerrors; + bool waserrors; +//--- create array + CMatrixDouble ra; +//--- initialization + trsmerrors=false; + syrkerrors=false; + gemmerrors=false; + transerrors=false; + rank1errors=false; + mverrors=false; + copyerrors=false; + waserrors=false; + threshold=10000*CMath::m_machineepsilon; +//--- search errors + trsmerrors=trsmerrors || TestTrsM(1,3*CAblas::AblasBlockSize()+1); + syrkerrors=syrkerrors || TestSyrk(1,3*CAblas::AblasBlockSize()+1); + gemmerrors=gemmerrors || TestGemm(1,3*CAblas::AblasBlockSize()+1); + transerrors=transerrors || TestTrans(1,3*CAblas::AblasBlockSize()+1); + rank1errors=rank1errors || TestRank1(1,3*CAblas::AblasBlockSize()+1); + mverrors=mverrors || TestMV(1,3*CAblas::AblasBlockSize()+1); + copyerrors=copyerrors || TestCopy(1,3*CAblas::AblasBlockSize()+1); +//--- report + waserrors=(((((trsmerrors || syrkerrors) || gemmerrors) || transerrors) || rank1errors) || mverrors) || copyerrors; +//--- check + if(!silent) + { + Print("TESTING ABLAS"); + Print("* TRSM: "); + //--- check + if(trsmerrors) + Print("FAILED"); + else + Print("OK"); + Print("* SYRK: "); + //--- check + if(syrkerrors) + Print("FAILED"); + else + Print("OK"); + Print("* GEMM: "); + //--- check + if(gemmerrors) + Print("FAILED"); + else + Print("OK"); + Print("* TRANS: "); + //--- check + if(transerrors) + Print("FAILED"); + else + Print("OK"); + Print("* RANK1: "); + //--- check + if(rank1errors) + Print("FAILED"); + else + Print("OK"); + Print("* MV: "); + //--- check + if(mverrors) + Print("FAILED"); + else + Print("OK"); + Print("* COPY: "); + //--- check + if(copyerrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestAblasUnit::NaiveMatrixMatrixMultiply(CMatrixDouble &a, + const int ai1, + const int ai2, + const int aj1, + const int aj2, + const bool transa, + CMatrixDouble &b, + const int bi1, + const int bi2, + const int bj1, + const int bj2, + const bool transb, + const double alpha, + CMatrixDouble &c, + const int ci1, + const int ci2, + const int cj1, + const int cj2, + const double beta) + { +//--- create variables + int arows=0; + int acols=0; + int brows=0; + int bcols=0; + int i=0; + int j=0; + int k=0; + int l=0; + int r=0; + double v=0; + int i_=0; + int i1_=0; +//--- create arrays + double x1[]; + double x2[]; +//--- Setup + if(!transa) + { + arows=ai2-ai1+1; + acols=aj2-aj1+1; + } + else + { + arows=aj2-aj1+1; + acols=ai2-ai1+1; + } +//--- check + if(!transb) + { + brows=bi2-bi1+1; + bcols=bj2-bj1+1; + } + else + { + brows=bj2-bj1+1; + bcols=bi2-bi1+1; + } +//--- check + if(!CAp::Assert(acols==brows,"NaiveMatrixMatrixMultiply: incorrect matrix sizes!")) + return; +//--- check + if(((arows<=0 || acols<=0) || brows<=0) || bcols<=0) + return; +//--- change values + l=arows; + r=bcols; + k=acols; +//--- allocation + ArrayResize(x1,k+1); + ArrayResize(x2,k+1); +//--- calculation + for(i=1;i<=l;i++) + { + for(j=1;j<=r;j++) + { + //--- check + if(!transa) + { + //--- check + if(!transb) + { + //--- change values + i1_=aj1-bi1; + v=0.0; + for(i_=bi1;i_<=bi2;i_++) + v+=b[i_][bj1+j-1]*a[ai1+i-1][i_+i1_]; + } + else + { + //--- change values + i1_=aj1-bj1; + v=0.0; + for(i_=bj1;i_<=bj2;i_++) + v+=b[bi1+j-1][i_]*a[ai1+i-1][i_+i1_]; + } + } + else + { + //--- check + if(!transb) + { + //--- change values + i1_=ai1-bi1; + v=0.0; + for(i_=bi1;i_<=bi2;i_++) + v+=b[i_][bj1+j-1]*a[i_+i1_][aj1+i-1]; + } + else + { + //--- change values + i1_=ai1-bj1; + v=0.0; + for(i_=bj1;i_<=bj2;i_++) + v+=b[bi1+j-1][i_]*a[i_+i1_][aj1+i-1]; + } + } + //--- check + if(beta==0.0) + c[ci1+i-1].Set(cj1+j-1,alpha*v); + else + c[ci1+i-1].Set(cj1+j-1,beta*c[ci1+i-1][cj1+j-1]+alpha*v); + } + } + } +//+------------------------------------------------------------------+ +//| ?Matrix????TRSM tests | +//| Returns False for passed test,True - for failed | +//+------------------------------------------------------------------+ +static bool CTestAblasUnit::TestTrsM(const int minn,const int maxn) + { +//--- create variables + bool result; + int n=0; + int m=0; + int mx=0; + int i=0; + int j=0; + int optype=0; + int uppertype=0; + int unittype=0; + int xoffsi=0; + int xoffsj=0; + int aoffsitype=0; + int aoffsjtype=0; + int aoffsi=0; + int aoffsj=0; + double threshold=0; +//--- create matrix + CMatrixDouble refra; + CMatrixDouble refrxl; + CMatrixDouble refrxr; + CMatrixComplex refca; + CMatrixComplex refcxl; + CMatrixComplex refcxr; + CMatrixDouble ra; + CMatrixComplex ca; + CMatrixDouble rxr1; + CMatrixDouble rxl1; + CMatrixComplex cxr1; + CMatrixComplex cxl1; + CMatrixDouble rxr2; + CMatrixDouble rxl2; + CMatrixComplex cxr2; + CMatrixComplex cxl2; +//--- initialization + threshold=CMath::Sqr(maxn)*100*CMath::m_machineepsilon; + result=false; +//--- calculation + for(mx=minn;mx<=maxn;mx++) + { + //--- Select random M/N in [1,MX] such that max(M,N)=MX + m=1+CMath::RandomInteger(mx); + n=1+CMath::RandomInteger(mx); + //--- check + if(CMath::RandomReal()>0.5) + m=mx; + else + n=mx; + //--- Initialize RefRA/RefCA by random matrices whose upper + //--- and lower triangle submatrices are non-degenerate + //--- well-conditioned matrices. + //--- Matrix size is 2Mx2M (four copies of same MxM matrix + //--- to test different offsets) + refra.Resize(2*m,2*m); + for(i=0;i<=m-1;i++) + { + for(j=0;j<=m-1;j++) + refra[i].Set(j,0.2*CMath::RandomReal()-0.1); + } + for(i=0;i<=m-1;i++) + refra[i].Set(i,(2*CMath::RandomInteger(1)-1)*(2*m+CMath::RandomReal())); + for(i=0;i<=m-1;i++) + { + for(j=0;j<=m-1;j++) + { + refra[i+m].Set(j,refra[i][j]); + refra[i].Set(j+m,refra[i][j]); + refra[i+m].Set(j+m,refra[i][j]); + } + } + //--- allocation + refca.Resize(2*m,2*m); + //--- change values + for(i=0;i<=m-1;i++) + { + for(j=0;j<=m-1;j++) + { + refca[i].SetRe(j,0.2*CMath::RandomReal()-0.1); + refca[i].SetIm(j,0.2*CMath::RandomReal()-0.1); + } + } + //--- change values + for(i=0;i<=m-1;i++) + { + refca[i].SetRe(i,(2*CMath::RandomInteger(2)-1)*(2*m+CMath::RandomReal())); + refca[i].SetIm(i,(2*CMath::RandomInteger(2)-1)*(2*m+CMath::RandomReal())); + } + //--- change values + for(i=0;i<=m-1;i++) + { + for(j=0;j<=m-1;j++) + { + refca[i+m].Set(j,refca[i][j]); + refca[i].Set(j+m,refca[i][j]); + refca[i+m].Set(j+m,refca[i][j]); + } + } + //--- Generate random XL/XR. + //--- XR is NxM matrix (matrix for 'Right' subroutines) + //--- XL is MxN matrix (matrix for 'Left' subroutines) + refrxr.Resize(n,m); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + refrxr[i].Set(j,2*CMath::RandomReal()-1); + } + //--- allocation + refrxl.Resize(m,n); + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + refrxl[i].Set(j,2*CMath::RandomReal()-1); + } + //--- allocation + refcxr.Resize(n,m); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + { + refcxr[i].SetRe(j,2*CMath::RandomReal()-1); + refcxr[i].SetIm(j,2*CMath::RandomReal()-1); + } + } + //--- allocation + refcxl.Resize(m,n); + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + refcxl[i].SetRe(j,2*CMath::RandomReal()-1); + refcxl[i].SetIm(j,2*CMath::RandomReal()-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. + ra.Resize(2*m,2*m); + rxr1.Resize(n,m); + rxr2.Resize(n,m); + rxl1.Resize(m,n); + rxl2.Resize(m,n); + ca.Resize(2*m,2*m); + cxr1.Resize(n,m); + cxr2.Resize(n,m); + cxl1.Resize(m,n); + cxl2.Resize(m,n); + //--- initialization + optype=CMath::RandomInteger(3); + uppertype=CMath::RandomInteger(2); + unittype=CMath::RandomInteger(2); + xoffsi=CMath::RandomInteger(2); + xoffsj=CMath::RandomInteger(2); + aoffsitype=CMath::RandomInteger(2); + aoffsjtype=CMath::RandomInteger(2); + aoffsi=m*aoffsitype; + aoffsj=m*aoffsjtype; + //--- copy A,XR,XL (fill unused parts with random garbage) + for(i=0;i<=2*m-1;i++) + { + for(j=0;j<=2*m-1;j++) + { + //--- check + if(((i>=aoffsi && i=aoffsj) && j=xoffsi && j>=xoffsj) + { + cxr1[i].Set(j,refcxr[i][j]); + cxr2[i].Set(j,refcxr[i][j]); + rxr1[i].Set(j,refrxr[i][j]); + rxr2[i].Set(j,refrxr[i][j]); + } + else + { + cxr1[i].Set(j,CMath::RandomReal()); + cxr2[i].Set(j,cxr1[i][j]); + rxr1[i].Set(j,CMath::RandomReal()); + rxr2[i].Set(j,rxr1[i][j]); + } + } + } + //--- change values + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(i>=xoffsi && j>=xoffsj) + { + cxl1[i].Set(j,refcxl[i][j]); + cxl2[i].Set(j,refcxl[i][j]); + rxl1[i].Set(j,refrxl[i][j]); + rxl2[i].Set(j,refrxl[i][j]); + } + else + { + cxl1[i].Set(j,CMath::RandomReal()); + cxl2[i].Set(j,cxl1[i][j]); + rxl1[i].Set(j,CMath::RandomReal()); + rxl2[i].Set(j,rxl1[i][j]); + } + } + } + //--- Test CXR + CAblas::CMatrixRightTrsM(n-xoffsi,m-xoffsj,ca,aoffsi,aoffsj,uppertype==0,unittype==0,optype,cxr1,xoffsi,xoffsj); + RefCMatrixRightTrsM(n-xoffsi,m-xoffsj,ca,aoffsi,aoffsj,uppertype==0,unittype==0,optype,cxr2,xoffsi,xoffsj); + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + result=result || CMath::AbsComplex(cxr1[i][j]-cxr2[i][j])>threshold; + } + //--- Test CXL + CAblas::CMatrixLeftTrsM(m-xoffsi,n-xoffsj,ca,aoffsi,aoffsj,uppertype==0,unittype==0,optype,cxl1,xoffsi,xoffsj); + RefCMatrixLeftTrsM(m-xoffsi,n-xoffsj,ca,aoffsi,aoffsj,uppertype==0,unittype==0,optype,cxl2,xoffsi,xoffsj); + //--- search errors + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + result=result || CMath::AbsComplex(cxl1[i][j]-cxl2[i][j])>threshold; + } + //--- check + if(optype<2) + { + //--- Test RXR + CAblas::RMatrixRightTrsM(n-xoffsi,m-xoffsj,ra,aoffsi,aoffsj,uppertype==0,unittype==0,optype,rxr1,xoffsi,xoffsj); + RefRMatrixRightTrsM(n-xoffsi,m-xoffsj,ra,aoffsi,aoffsj,uppertype==0,unittype==0,optype,rxr2,xoffsi,xoffsj); + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + result=result || MathAbs(rxr1[i][j]-rxr2[i][j])>threshold; + } + //--- Test RXL + CAblas::RMatrixLeftTrsM(m-xoffsi,n-xoffsj,ra,aoffsi,aoffsj,uppertype==0,unittype==0,optype,rxl1,xoffsi,xoffsj); + RefRMatrixLeftTrsM(m-xoffsi,n-xoffsj,ra,aoffsi,aoffsj,uppertype==0,unittype==0,optype,rxl2,xoffsi,xoffsj); + //--- search errors + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + result=result || MathAbs(rxl1[i][j]-rxl2[i][j])>threshold; + } + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| SYRK tests | +//| Returns False for passed test,True - for failed | +//+------------------------------------------------------------------+ +static bool CTestAblasUnit::TestSyrk(const int minn,const int maxn) + { +//--- create variables + bool result; + int n=0; + int k=0; + int mx=0; + int i=0; + int j=0; + int uppertype=0; + int xoffsi=0; + int xoffsj=0; + int aoffsitype=0; + int aoffsjtype=0; + int aoffsi=0; + int aoffsj=0; + int alphatype=0; + int betatype=0; + double alpha=0; + double beta=0; + double threshold=0; +//--- create matrix + CMatrixDouble refra; + CMatrixDouble refrc; + CMatrixComplex refca; + CMatrixComplex refcc; + CMatrixDouble ra1; + CMatrixDouble ra2; + CMatrixComplex ca1; + CMatrixComplex ca2; + CMatrixDouble rc; + CMatrixDouble rct; + CMatrixComplex cc; + CMatrixComplex cct; +//--- initialization + threshold=maxn*100*CMath::m_machineepsilon; + result=false; + for(mx=minn;mx<=maxn;mx++) + { + //--- Select random M/N in [1,MX] such that max(M,N)=MX + k=1+CMath::RandomInteger(mx); + n=1+CMath::RandomInteger(mx); + //--- check + if(CMath::RandomReal()>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) + refra.Resize(2*n,2*n); + refca.Resize(2*n,2*n); + for(i=0;i<=n-1;i++) + { + refra[i].Set(i,2*CMath::RandomReal()-1); + refca[i].Set(i,2*CMath::RandomReal()-1); + for(j=i+1;j<=n-1;j++) + { + refra[i].Set(j,2*CMath::RandomReal()-1); + refca[i].SetRe(j,2*CMath::RandomReal()-1); + refca[i].SetIm(j,2*CMath::RandomReal()-1); + refra[j].Set(i,refra[i][j]); + refca[j].Set(i,CMath::Conj(refca[i][j])); + } + } + //--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + refra[i+n].Set(j,refra[i][j]); + refra[i].Set(j+n,refra[i][j]); + refra[i+n].Set(j+n,refra[i][j]); + refca[i+n].Set(j,refca[i][j]); + refca[i].Set(j+n,refca[i][j]); + refca[i+n].Set(j+n,refca[i][j]); + } + } + //--- allocation + refrc.Resize(n,k); + refcc.Resize(n,k); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=k-1;j++) + { + refrc[i].Set(j,2*CMath::RandomReal()-1); + refcc[i].SetRe(j,2*CMath::RandomReal()-1); + refcc[i].SetIm(j,2*CMath::RandomReal()-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. + ra1.Resize(2*n,2*n); + ra2.Resize(2*n,2*n); + ca1.Resize(2*n,2*n); + ca2.Resize(2*n,2*n); + rc.Resize(n,k); + rct.Resize(k,n); + cc.Resize(n,k); + cct.Resize(k,n); + //--- initialization + uppertype=CMath::RandomInteger(2); + xoffsi=CMath::RandomInteger(2); + xoffsj=CMath::RandomInteger(2); + aoffsitype=CMath::RandomInteger(2); + aoffsjtype=CMath::RandomInteger(2); + alphatype=CMath::RandomInteger(2); + betatype=CMath::RandomInteger(2); + aoffsi=n*aoffsitype; + aoffsj=n*aoffsjtype; + alpha=alphatype*(2*CMath::RandomReal()-1); + beta=betatype*(2*CMath::RandomReal()-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++) + { + //--- check + if(((i>=aoffsi && i=aoffsj) && j=xoffsi && j>=xoffsj) + { + rc[i].Set(j,refrc[i][j]); + rct[j].Set(i,refrc[i][j]); + cc[i].Set(j,refcc[i][j]); + cct[j].Set(i,refcc[i][j]); + } + else + { + rc[i].Set(j,CMath::RandomReal()); + rct[j].Set(i,rc[i][j]); + cc[i].Set(j,CMath::RandomReal()); + cct[j].Set(i,cct[j][i]); + } + } + } + //--- Test complex + //--- Only one of transform types is selected and tested + if(CMath::RandomReal()>0.5) + { + CAblas::CMatrixSyrk(n-xoffsi,k-xoffsj,alpha,cc,xoffsi,xoffsj,0,beta,ca1,aoffsi,aoffsj,uppertype==0); + RefCMatrixSyrk(n-xoffsi,k-xoffsj,alpha,cc,xoffsi,xoffsj,0,beta,ca2,aoffsi,aoffsj,uppertype==0); + } + else + { + CAblas::CMatrixSyrk(n-xoffsi,k-xoffsj,alpha,cct,xoffsj,xoffsi,2,beta,ca1,aoffsi,aoffsj,uppertype==0); + RefCMatrixSyrk(n-xoffsi,k-xoffsj,alpha,cct,xoffsj,xoffsi,2,beta,ca2,aoffsi,aoffsj,uppertype==0); + } + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + result=result || CMath::AbsComplex(ca1[i][j]-ca2[i][j])>threshold; + } + //--- Test real + //--- Only one of transform types is selected and tested + if(CMath::RandomReal()>0.5) + { + CAblas::RMatrixSyrk(n-xoffsi,k-xoffsj,alpha,rc,xoffsi,xoffsj,0,beta,ra1,aoffsi,aoffsj,uppertype==0); + RefRMatrixSyrk(n-xoffsi,k-xoffsj,alpha,rc,xoffsi,xoffsj,0,beta,ra2,aoffsi,aoffsj,uppertype==0); + } + else + { + CAblas::RMatrixSyrk(n-xoffsi,k-xoffsj,alpha,rct,xoffsj,xoffsi,1,beta,ra1,aoffsi,aoffsj,uppertype==0); + RefRMatrixSyrk(n-xoffsi,k-xoffsj,alpha,rct,xoffsj,xoffsi,1,beta,ra2,aoffsi,aoffsj,uppertype==0); + } + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + result=result || MathAbs(ra1[i][j]-ra2[i][j])>threshold; + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| GEMM tests | +//| Returns False for passed test,True - for failed | +//+------------------------------------------------------------------+ +static bool CTestAblasUnit::TestGemm(const int minn,const int maxn) + { +//--- create variables + bool result; + int m=0; + int n=0; + int k=0; + int mx=0; + int i=0; + int j=0; + int aoffsi=0; + int aoffsj=0; + int aoptype=0; + int aoptyper=0; + int boffsi=0; + int boffsj=0; + int boptype=0; + int boptyper=0; + int coffsi=0; + int coffsj=0; + double alphar=0; + double betar=0; + complex alphac=0; + complex betac=0; + double threshold=0; +//--- create matrix + CMatrixDouble refra; + CMatrixDouble refrb; + CMatrixDouble refrc; + CMatrixComplex refca; + CMatrixComplex refcb; + CMatrixComplex refcc; + CMatrixDouble rc1; + CMatrixDouble rc2; + CMatrixComplex cc1; + CMatrixComplex cc2; +//--- initialization + threshold=maxn*100*CMath::m_machineepsilon; + result=false; +//--- calculation + for(mx=minn;mx<=maxn;mx++) + { + //--- Select random M/N/K in [1,MX] such that max(M,N,K)=MX + m=1+CMath::RandomInteger(mx); + n=1+CMath::RandomInteger(mx); + k=1+CMath::RandomInteger(mx); + i=CMath::RandomInteger(3); + //--- check + if(i==0) + m=mx; + //--- check + if(i==1) + n=mx; + //--- check + if(i==2) + k=mx; + //--- Initialize A/B/C by random matrices with size (MaxN+1)*(MaxN+1) + refra.Resize(maxn+1,maxn+1); + refrb.Resize(maxn+1,maxn+1); + refrc.Resize(maxn+1,maxn+1); + refca.Resize(maxn+1,maxn+1); + refcb.Resize(maxn+1,maxn+1); + refcc.Resize(maxn+1,maxn+1); + //--- change values + for(i=0;i<=maxn;i++) + { + for(j=0;j<=maxn;j++) + { + refra[i].Set(j,2*CMath::RandomReal()-1); + refrb[i].Set(j,2*CMath::RandomReal()-1); + refrc[i].Set(j,2*CMath::RandomReal()-1); + refca[i].SetRe(j,2*CMath::RandomReal()-1); + refca[i].SetIm(j,2*CMath::RandomReal()-1); + refcb[i].SetRe(j,2*CMath::RandomReal()-1); + refcb[i].SetIm(j,2*CMath::RandomReal()-1); + refcc[i].SetRe(j,2*CMath::RandomReal()-1); + refcc[i].SetIm(j,2*CMath::RandomReal()-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. + rc1.Resize(maxn+1,maxn+1); + rc2.Resize(maxn+1,maxn+1); + cc1.Resize(maxn+1,maxn+1); + cc2.Resize(maxn+1,maxn+1); + //--- initialization + aoffsi=CMath::RandomInteger(2); + aoffsj=CMath::RandomInteger(2); + aoptype=CMath::RandomInteger(3); + aoptyper=CMath::RandomInteger(2); + boffsi=CMath::RandomInteger(2); + boffsj=CMath::RandomInteger(2); + boptype=CMath::RandomInteger(3); + boptyper=CMath::RandomInteger(2); + coffsi=CMath::RandomInteger(2); + coffsj=CMath::RandomInteger(2); + alphar=CMath::RandomInteger(2)*(2*CMath::RandomReal()-1); + betar=CMath::RandomInteger(2)*(2*CMath::RandomReal()-1); + //--- check + if(CMath::RandomReal()>0.5) + { + alphac.re=2*CMath::RandomReal()-1; + alphac.im=2*CMath::RandomReal()-1; + } + else + alphac=0; + //--- check + if(CMath::RandomReal()>0.5) + { + betac.re=2*CMath::RandomReal()-1; + betac.im=2*CMath::RandomReal()-1; + } + else + betac=0; + //--- copy C + for(i=0;i<=maxn;i++) + { + for(j=0;j<=maxn;j++) + { + rc1[i].Set(j,refrc[i][j]); + rc2[i].Set(j,refrc[i][j]); + cc1[i].Set(j,refcc[i][j]); + cc2[i].Set(j,refcc[i][j]); + } + } + //--- Test complex + CAblas::CMatrixGemm(m,n,k,alphac,refca,aoffsi,aoffsj,aoptype,refcb,boffsi,boffsj,boptype,betac,cc1,coffsi,coffsj); + RefCMatrixGemm(m,n,k,alphac,refca,aoffsi,aoffsj,aoptype,refcb,boffsi,boffsj,boptype,betac,cc2,coffsi,coffsj); + //--- search errors + for(i=0;i<=maxn;i++) + { + for(j=0;j<=maxn;j++) + result=result || CMath::AbsComplex(cc1[i][j]-cc2[i][j])>threshold; + } + //--- Test real + CAblas::RMatrixGemm(m,n,k,alphar,refra,aoffsi,aoffsj,aoptyper,refrb,boffsi,boffsj,boptyper,betar,rc1,coffsi,coffsj); + RefRMatrixGemm(m,n,k,alphar,refra,aoffsi,aoffsj,aoptyper,refrb,boffsi,boffsj,boptyper,betar,rc2,coffsi,coffsj); + //--- search errors + for(i=0;i<=maxn;i++) + { + for(j=0;j<=maxn;j++) + result=result || MathAbs(rc1[i][j]-rc2[i][j])>threshold; + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| transpose tests | +//| Returns False for passed test,True - for failed | +//+------------------------------------------------------------------+ +static bool CTestAblasUnit::TestTrans(const int minn,const int maxn) + { +//--- create variables + bool result; + int m=0; + int n=0; + int mx=0; + int i=0; + int j=0; + int aoffsi=0; + int aoffsj=0; + int boffsi=0; + int boffsj=0; + double v1=0; + double v2=0; + double threshold=0; +//--- create matrix + CMatrixDouble refra; + CMatrixDouble refrb; + CMatrixComplex refca; + CMatrixComplex refcb; +//--- initialization + result=false; + threshold=1000*CMath::m_machineepsilon; +//--- calculation + 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+CMath::RandomInteger(mx); + n=1+CMath::RandomInteger(mx); + //--- check + if(CMath::RandomInteger(2)==0) + m=mx; + else + n=mx; + //--- change values + v1=CMath::RandomReal(); + v2=CMath::RandomReal(); + //--- Initialize A by random matrix with size (MaxN+1)*(MaxN+1) + //--- Fill B with control values + refra.Resize(maxn+1,maxn+1); + refrb.Resize(maxn+1,maxn+1); + refca.Resize(maxn+1,maxn+1); + refcb.Resize(maxn+1,maxn+1); + //--- change values + for(i=0;i<=maxn;i++) + { + for(j=0;j<=maxn;j++) + { + refra[i].Set(j,2*CMath::RandomReal()-1); + refca[i].SetRe(j,2*CMath::RandomReal()-1); + refca[i].SetIm(j,2*CMath::RandomReal()-1); + refrb[i].Set(j,i*v1+j*v2); + refcb[i].Set(j,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=CMath::RandomInteger(2); + aoffsj=CMath::RandomInteger(2); + boffsi=CMath::RandomInteger(2); + boffsj=CMath::RandomInteger(2); + //--- function call + CAblas::RMatrixTranspose(m,n,refra,aoffsi,aoffsj,refrb,boffsi,boffsj); + //--- search errors + for(i=0;i<=maxn;i++) + { + for(j=0;j<=maxn;j++) + { + //--- check + if(((i=boffsi+n) || j=boffsj+m) + result=result || MathAbs(refrb[i][j]-(v1*i+v2*j))>threshold; + else + result=result || MathAbs(refrb[i][j]-refra[aoffsi+j-boffsj][aoffsj+i-boffsi])>threshold; + } + } + //--- function call + CAblas::CMatrixTranspose(m,n,refca,aoffsi,aoffsj,refcb,boffsi,boffsj); + //--- search errors + for(i=0;i<=maxn;i++) + { + for(j=0;j<=maxn;j++) + { + //--- check + if(((i=boffsi+n) || j=boffsj+m) + result=result || CMath::AbsComplex(refcb[i][j]-(v1*i+v2*j))>threshold; + else + result=result || CMath::AbsComplex(refcb[i][j]-refca[aoffsi+j-boffsj][aoffsj+i-boffsi])>threshold; + } + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| rank-1tests | +//| Returns False for passed test,True - for failed | +//+------------------------------------------------------------------+ +static bool CTestAblasUnit::TestRank1(const int minn,const int maxn) + { +//--- create variables + bool result; + int m=0; + int n=0; + int mx=0; + int i=0; + int j=0; + int aoffsi=0; + int aoffsj=0; + int uoffs=0; + int voffs=0; + double threshold=0; +//--- create arrays + double ru[]; + double rv[]; + complex cu[]; + complex cv[]; +//--- create matrix + CMatrixDouble refra; + CMatrixDouble refrb; + CMatrixComplex refca; + CMatrixComplex refcb; +//--- initialization + result=false; + threshold=1000*CMath::m_machineepsilon; +//--- calculation + for(mx=minn;mx<=maxn;mx++) + { + //--- Select random M/N in [1,MX] such that max(M,N)=MX + m=1+CMath::RandomInteger(mx); + n=1+CMath::RandomInteger(mx); + //--- check + if(CMath::RandomInteger(2)==0) + m=mx; + else + n=mx; + //--- Initialize A by random matrix with size (MaxN+1)*(MaxN+1) + //--- Fill B with control values + refra.Resize(maxn+maxn,maxn+maxn); + refrb.Resize(maxn+maxn,maxn+maxn); + refca.Resize(maxn+maxn,maxn+maxn); + refcb.Resize(maxn+maxn,maxn+maxn); + //--- change values + for(i=0;i<=2*maxn-1;i++) + { + for(j=0;j<=2*maxn-1;j++) + { + refra[i].Set(j,2*CMath::RandomReal()-1); + refca[i].SetRe(j,2*CMath::RandomReal()-1); + refca[i].SetIm(j,2*CMath::RandomReal()-1); + refrb[i].Set(j,refra[i][j]); + refcb[i].Set(j,refca[i][j]); + } + } + //--- allocation + ArrayResize(ru,2*m); + ArrayResize(cu,2*m); + //--- change values + for(i=0;i<=2*m-1;i++) + { + ru[i]=2*CMath::RandomReal()-1; + cu[i].re=2*CMath::RandomReal()-1; + cu[i].im=2*CMath::RandomReal()-1; + } + //--- allocation + ArrayResize(rv,2*n); + ArrayResize(cv,2*n); + //--- change values + for(i=0;i<=2*n-1;i++) + { + rv[i]=2*CMath::RandomReal()-1; + cv[i].re=2*CMath::RandomReal()-1; + cv[i].im=2*CMath::RandomReal()-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=CMath::RandomInteger(maxn); + aoffsj=CMath::RandomInteger(maxn); + uoffs=CMath::RandomInteger(m); + voffs=CMath::RandomInteger(n); + //--- function call + CAblas::CMatrixRank1(m,n,refca,aoffsi,aoffsj,cu,uoffs,cv,voffs); + //--- search errors + for(i=0;i<=2*maxn-1;i++) + { + for(j=0;j<=2*maxn-1;j++) + { + //--- check + if(((i=aoffsi+m) || j=aoffsj+n) + result=result || CMath::AbsComplex(refca[i][j]-refcb[i][j])>threshold; + else + result=result || CMath::AbsComplex(refca[i][j]-(refcb[i][j]+cu[i-aoffsi+uoffs]*cv[j-aoffsj+voffs]))>threshold; + } + } + //--- function call + CAblas::RMatrixRank1(m,n,refra,aoffsi,aoffsj,ru,uoffs,rv,voffs); + //--- search errors + for(i=0;i<=2*maxn-1;i++) + { + for(j=0;j<=2*maxn-1;j++) + { + //--- check + if(((i=aoffsi+m) || j=aoffsj+n) + result=result || MathAbs(refra[i][j]-refrb[i][j])>threshold; + else + result=result || MathAbs(refra[i][j]-(refrb[i][j]+ru[i-aoffsi+uoffs]*rv[j-aoffsj+voffs]))>threshold; + } + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| MV tests | +//| Returns False for passed test,True - for failed | +//+------------------------------------------------------------------+ +static bool CTestAblasUnit::TestMV(const int minn,const int maxn) + { +//--- create variables + bool result; + int m=0; + int n=0; + int mx=0; + int i=0; + int j=0; + int aoffsi=0; + int aoffsj=0; + int xoffs=0; + int yoffs=0; + int opca=0; + int opra=0; + double threshold=0; + double rv1=0; + double rv2=0; + complex cv1=0; + complex cv2=0; + int i_=0; + int i1_=0; +//--- create arrays + double rx[]; + double ry[]; + complex cx[]; + complex cy[]; +//--- create matrix + CMatrixDouble refra; + CMatrixComplex refca; +//--- initialization + result=false; + threshold=1000*CMath::m_machineepsilon; +//--- calculation + for(mx=minn;mx<=maxn;mx++) + { + //--- Select random M/N in [1,MX] such that max(M,N)=MX + m=1+CMath::RandomInteger(mx); + n=1+CMath::RandomInteger(mx); + //--- check + if(CMath::RandomInteger(2)==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 + refra.Resize(maxn+maxn,maxn+maxn); + refca.Resize(maxn+maxn,maxn+maxn); + //--- change values + for(i=0;i<=2*maxn-1;i++) + { + for(j=0;j<=2*maxn-1;j++) + { + refra[i].Set(j,2*CMath::RandomReal()-1); + refca[i].SetRe(j,2*CMath::RandomReal()-1); + refca[i].SetIm(j,2*CMath::RandomReal()-1); + } + } + //--- allocation + ArrayResize(rx,2*maxn); + ArrayResize(cx,2*maxn); + ArrayResize(ry,2*maxn); + ArrayResize(cy,2*maxn); + //--- change values + for(i=0;i<=2*maxn-1;i++) + { + rx[i]=2*CMath::RandomReal()-1; + cx[i].re=2*CMath::RandomReal()-1; + cx[i].im=2*CMath::RandomReal()-1; + ry[i]=i; + cy[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=CMath::RandomInteger(maxn); + aoffsj=CMath::RandomInteger(maxn); + xoffs=CMath::RandomInteger(maxn); + yoffs=CMath::RandomInteger(maxn); + opca=CMath::RandomInteger(3); + opra=CMath::RandomInteger(2); + //--- function call + CAblas::CMatrixMVect(m,n,refca,aoffsi,aoffsj,opca,cx,xoffs,cy,yoffs); + //--- search errors + for(i=0;i<=2*maxn-1;i++) + { + //--- check + if(i=yoffs+m) + result=result || cy[i]!=i; + else + { + cv1=cy[i]; + cv2=0.0; + //--- check + if(opca==0) + { + //--- change values + i1_=xoffs-aoffsj; + cv2=0.0; + for(i_=aoffsj;i_<=aoffsj+n-1;i_++) + cv2+=refca[aoffsi+i-yoffs][i_]*cx[i_+i1_]; + } + //--- check + if(opca==1) + { + //--- change values + i1_=xoffs-aoffsi; + cv2=0.0; + for(i_=aoffsi;i_<=aoffsi+n-1;i_++) + cv2+=refca[i_][aoffsj+i-yoffs]*cx[i_+i1_]; + } + //--- check + if(opca==2) + { + //--- change values + i1_=xoffs-aoffsi; + cv2=0.0; + for(i_=aoffsi;i_<=aoffsi+n-1;i_++) + cv2+=CMath::Conj(refca[i_][aoffsj+i-yoffs])*cx[i_+i1_]; + } + result=result || CMath::AbsComplex(cv1-cv2)>threshold; + } + } + //--- function call + CAblas::RMatrixMVect(m,n,refra,aoffsi,aoffsj,opra,rx,xoffs,ry,yoffs); + //--- function call + for(i=0;i<=2*maxn-1;i++) + { + //--- check + if(i=yoffs+m) + result=result || ry[i]!=i; + else + { + rv1=ry[i]; + rv2=0; + //--- check + if(opra==0) + { + //--- change values + i1_=xoffs-aoffsj; + rv2=0.0; + for(i_=aoffsj;i_<=aoffsj+n-1;i_++) + rv2+=refra[aoffsi+i-yoffs][i_]*rx[i_+i1_]; + } + //--- check + if(opra==1) + { + //--- change values + i1_=xoffs-aoffsi; + rv2=0.0; + for(i_=aoffsi;i_<=aoffsi+n-1;i_++) + rv2+=refra[i_][aoffsj+i-yoffs]*rx[i_+i1_]; + } + result=result || MathAbs(rv1-rv2)>threshold; + } + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| COPY tests | +//| Returns False for passed test,True - for failed | +//+------------------------------------------------------------------+ +static bool CTestAblasUnit::TestCopy(const int minn,const int maxn) + { +//--- create variables + bool result; + int m=0; + int n=0; + int mx=0; + int i=0; + int j=0; + int aoffsi=0; + int aoffsj=0; + int boffsi=0; + int boffsj=0; + double threshold=0; +//--- create matrix + CMatrixDouble ra; + CMatrixDouble rb; + CMatrixComplex ca; + CMatrixComplex cb; +//--- initialization + result=false; + threshold=1000*CMath::m_machineepsilon; +//--- calculation + for(mx=minn;mx<=maxn;mx++) + { + //--- Select random M/N in [1,MX] such that max(M,N)=MX + m=1+CMath::RandomInteger(mx); + n=1+CMath::RandomInteger(mx); + //--- check + if(CMath::RandomInteger(2)==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 + ra.Resize(maxn+maxn,maxn+maxn); + ca.Resize(maxn+maxn,maxn+maxn); + rb.Resize(maxn+maxn,maxn+maxn); + cb.Resize(maxn+maxn,maxn+maxn); + //--- change values + for(i=0;i<=2*maxn-1;i++) + { + for(j=0;j<=2*maxn-1;j++) + { + ra[i].Set(j,2*CMath::RandomReal()-1); + ca[i].SetRe(j,2*CMath::RandomReal()-1); + ca[i].SetIm(j,2*CMath::RandomReal()-1); + rb[i].Set(j,1+2*i+3*j); + cb[i].Set(j,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=CMath::RandomInteger(maxn); + aoffsj=CMath::RandomInteger(maxn); + boffsi=CMath::RandomInteger(maxn); + boffsj=CMath::RandomInteger(maxn); + //--- function call + CAblas::CMatrixCopy(m,n,ca,aoffsi,aoffsj,cb,boffsi,boffsj); + //--- search errors + for(i=0;i<=2*maxn-1;i++) + { + for(j=0;j<=2*maxn-1;j++) + { + //--- check + if(((i=boffsi+m) || j=boffsj+n) + result=result || cb[i][j]!=1+2*i+3*j; + else + result=result || CMath::AbsComplex(ca[aoffsi+i-boffsi][aoffsj+j-boffsj]-cb[i][j])>threshold; + } + } + //--- function call + CAblas::RMatrixCopy(m,n,ra,aoffsi,aoffsj,rb,boffsi,boffsj); + //--- search errors + for(i=0;i<=2*maxn-1;i++) + { + for(j=0;j<=2*maxn-1;j++) + { + //--- check + if(((i=boffsi+m) || j=boffsj+n) + result=result || rb[i][j]!=1+2*i+3*j; + else + result=result || MathAbs(ra[aoffsi+i-boffsi][aoffsj+j-boffsj]-rb[i][j])>threshold; + } + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Reference implementation | +//+------------------------------------------------------------------+ +static void CTestAblasUnit::RefCMatrixRightTrsM(const int m,const int n, + CMatrixComplex &a, + const int i1,const int j1, + const bool isupper, + const bool isunit, + const int optype, + CMatrixComplex &x, + const int i2,const int j2) + { +//--- create variables + int i=0; + int j=0; + complex vc=0; + bool rupper; + int i_=0; + int i1_=0; +//--- create array + complex tx[]; +//--- create matrix + CMatrixComplex a1; + CMatrixComplex a2; +//--- check + if(n*m==0) + return; +//--- allocation + a1.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a1[i].Set(j,0); + } +//--- check + if(isupper) + { + for(i=0;i<=n-1;i++) + { + for(j=i;j<=n-1;j++) + a1[i].Set(j,a[i1+i][j1+j]); + } + } + else + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=i;j++) + a1[i].Set(j,a[i1+i][j1+j]); + } + } +//--- change value + rupper=isupper; +//--- check + if(isunit) + { + for(i=0;i<=n-1;i++) + { + a1[i].Set(i,1); + } + } +//--- allocation + a2.Resize(n,n); +//--- check + if(optype==0) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a2[i].Set(j,a1[i][j]); + } + } +//--- check + if(optype==1) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a2[i].Set(j,a1[j][i]); + } + //--- change value + rupper=!rupper; + } +//--- check + if(optype==2) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + a2[i].Set(j,CMath::Conj(a1[j][i])); + } + } + //--- change value + rupper=!rupper; + } +//--- function call + InternalCMatrixTrInverse(a2,n,rupper,false); +//--- allocation + ArrayResize(tx,n); +//--- calculation + for(i=0;i<=m-1;i++) + { + i1_=j2; + for(i_=0;i_<=n-1;i_++) + tx[i_]=x[i2+i][i_+i1_]; + //--- change values + for(j=0;j<=n-1;j++) + { + vc=0.0; + for(i_=0;i_<=n-1;i_++) + vc+=tx[i_]*a2[i_][j]; + x[i2+i].Set(j2+j,vc); + } + } + } +//+------------------------------------------------------------------+ +//| Reference implementation | +//+------------------------------------------------------------------+ +static void CTestAblasUnit::RefCMatrixLeftTrsM(const int m,const int n, + CMatrixComplex &a, + const int i1,const int j1, + const bool isupper, + const bool isunit, + const int optype, + CMatrixComplex &x, + const int i2,const int j2) + { +//--- create variables + int i=0; + int j=0; + complex vc=0; + bool rupper; + int i_=0; + int i1_=0; +//--- create array + complex tx[]; +//--- create matrix + CMatrixComplex a1; + CMatrixComplex a2; +//--- check + if(n*m==0) + return; +//--- allocation + a1.Resize(m,m); + for(i=0;i<=m-1;i++) + { + for(j=0;j<=m-1;j++) + a1[i].Set(j,0); + } +//--- check + if(isupper) + { + for(i=0;i<=m-1;i++) + { + for(j=i;j<=m-1;j++) + a1[i].Set(j,a[i1+i][j1+j]); + } + } + else + { + for(i=0;i<=m-1;i++) + { + for(j=0;j<=i;j++) + a1[i].Set(j,a[i1+i][j1+j]); + } + } +//--- change value + rupper=isupper; +//--- check + if(isunit) + { + for(i=0;i<=m-1;i++) + a1[i].Set(i,1); + } +//--- allocation + a2.Resize(m,m); +//--- check + if(optype==0) + { + for(i=0;i<=m-1;i++) + { + for(j=0;j<=m-1;j++) + a2[i].Set(j,a1[i][j]); + } + } +//--- check + if(optype==1) + { + for(i=0;i<=m-1;i++) + { + for(j=0;j<=m-1;j++) + a2[i].Set(j,a1[j][i]); + } + //--- change value + rupper=!rupper; + } +//--- check + if(optype==2) + { + for(i=0;i<=m-1;i++) + { + for(j=0;j<=m-1;j++) + a2[i].Set(j,CMath::Conj(a1[j][i])); + } + //--- change value + rupper=!rupper; + } +//--- function call + InternalCMatrixTrInverse(a2,m,rupper,false); +//--- allocation + ArrayResize(tx,m); + for(j=0;j<=n-1;j++) + { + i1_=i2; + for(i_=0;i_<=m-1;i_++) + tx[i_]=x[i_+i1_][j2+j]; + //--- change values + for(i=0;i<=m-1;i++) + { + vc=0.0; + for(i_=0;i_<=m-1;i_++) + vc+=a2[i][i_]*tx[i_]; + x[i2+i].Set(j2+j,vc); + } + } + } +//+------------------------------------------------------------------+ +//| Reference implementation | +//+------------------------------------------------------------------+ +static void CTestAblasUnit::RefRMatrixRightTrsM(const int m,const int n, + CMatrixDouble &a, + const int i1,const int j1, + const bool isupper, + const bool isunit, + const int optype, + CMatrixDouble &x, + const int i2,const int j2) + { +//--- create variables + int i=0; + int j=0; + double vr=0; + bool rupper; + int i_=0; + int i1_=0; +//--- create array + double tx[]; +//--- create matrix + CMatrixDouble a1; + CMatrixDouble a2; +//--- check + if(n*m==0) + return; +//--- allocation + a1.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a1[i].Set(j,0); + } +//--- check + if(isupper) + { + for(i=0;i<=n-1;i++) + { + for(j=i;j<=n-1;j++) + a1[i].Set(j,a[i1+i][j1+j]); + } + } + else + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=i;j++) + a1[i].Set(j,a[i1+i][j1+j]); + } + } +//--- change value + rupper=isupper; +//--- check + if(isunit) + { + for(i=0;i<=n-1;i++) + a1[i].Set(i,1); + } +//--- allocation + a2.Resize(n,n); +//--- check + if(optype==0) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a2[i].Set(j,a1[i][j]); + } + } +//--- check + if(optype==1) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a2[i].Set(j,a1[j][i]); + } + //--- change value + rupper=!rupper; + } +//--- function call + InternalRMatrixTrInverse(a2,n,rupper,false); +//--- allocation + ArrayResize(tx,n); + for(i=0;i<=m-1;i++) + { + i1_=j2; + for(i_=0;i_<=n-1;i_++) + tx[i_]=x[i2+i][i_+i1_]; + //--- change values + for(j=0;j<=n-1;j++) + { + vr=0.0; + for(i_=0;i_<=n-1;i_++) + vr+=tx[i_]*a2[i_][j]; + x[i2+i].Set(j2+j,vr); + } + } + } +//+------------------------------------------------------------------+ +//| Reference implementation | +//+------------------------------------------------------------------+ +static void CTestAblasUnit::RefRMatrixLeftTrsM(const int m,const int n, + CMatrixDouble &a, + const int i1,const int j1, + const bool isupper, + const bool isunit, + const int optype, + CMatrixDouble &x, + const int i2,const int j2) + { +//--- create variables + int i=0; + int j=0; + double vr=0; + bool rupper; + int i_=0; + int i1_=0; +//--- create array + double tx[]; +//--- create matrix + CMatrixDouble a1; + CMatrixDouble a2; +//--- check + if(n*m==0) + return; +//--- allocation + a1.Resize(m,m); + for(i=0;i<=m-1;i++) + { + for(j=0;j<=m-1;j++) + a1[i].Set(j,0); + } +//--- check + if(isupper) + { + for(i=0;i<=m-1;i++) + { + for(j=i;j<=m-1;j++) + a1[i].Set(j,a[i1+i][j1+j]); + } + } + else + { + for(i=0;i<=m-1;i++) + { + for(j=0;j<=i;j++) + a1[i].Set(j,a[i1+i][j1+j]); + } + } +//--- change value + rupper=isupper; +//--- check + if(isunit) + { + for(i=0;i<=m-1;i++) + a1[i].Set(i,1); + } +//--- allocation + a2.Resize(m,m); +//--- check + if(optype==0) + { + for(i=0;i<=m-1;i++) + { + for(j=0;j<=m-1;j++) + a2[i].Set(j,a1[i][j]); + } + } +//--- check + if(optype==1) + { + for(i=0;i<=m-1;i++) + { + for(j=0;j<=m-1;j++) + a2[i].Set(j,a1[j][i]); + } + //--- change value + rupper=!rupper; + } +//--- function call + InternalRMatrixTrInverse(a2,m,rupper,false); +//--- allocation + ArrayResize(tx,m); + for(j=0;j<=n-1;j++) + { + i1_=i2; + for(i_=0;i_<=m-1;i_++) + tx[i_]=x[i_+i1_][j2+j]; + //--- change values + for(i=0;i<=m-1;i++) + { + vr=0.0; + for(i_=0;i_<=m-1;i_++) + vr+=a2[i][i_]*tx[i_]; + x[i2+i].Set(j2+j,vr); + } + } + } +//+------------------------------------------------------------------+ +//| 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 bool CTestAblasUnit::InternalCMatrixTrInverse(CMatrixComplex &a, + const int n, + const bool isupper, + const bool isunittriangular) + { +//--- create variables + bool result; + bool nounit; + int i=0; + int j=0; + complex v=0; + complex ajj=0; + complex one=1; + int i_=0; +//--- create array + complex t[]; +//--- initialization + result=true; +//--- allocation + ArrayResize(t,n); +//--- Test the input parameters. + nounit=!isunittriangular; +//--- check + if(isupper) + { + //--- Compute inverse of upper triangular matrix. + for(j=0;j<=n-1;j++) + { + //--- check + if(nounit) + { + //--- check + if(a[j][j]==0) + { + //--- return result + return(false); + } + //--- change values + a[j].Set(j,one/a[j][j]); + ajj=-a[j][j]; + } + else + ajj=-1; + //--- Compute elements 1:j-1 of j-th column. + if(j>0) + { + for(i_=0;i_<=j-1;i_++) + t[i_]=a[i_][j]; + for(i=0;i<=j-1;i++) + { + //--- check + if(i+1=0;j--) + { + //--- check + if(nounit) + { + //--- check + if(a[j][j]==0) + { + //--- return result + return(false); + } + //--- change values + a[j].Set(j,one/a[j][j]); + ajj=-a[j][j]; + } + else + ajj=-1; + //--- check + if(j+1j+1) + { + v=0.0; + for(i_=j+1;i_<=i-1;i_++) + v+=a[i][i_]*t[i_]; + } + else + v=0; + //--- check + if(nounit) + a[i].Set(j,v+a[i][i]*t[i]); + else + a[i].Set(j,v+t[i]); + } + //--- change values + for(i_=j+1;i_<=n-1;i_++) + a[i_].Set(j,ajj*a[i_][j]); + } + } + } +//--- return result + 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 bool CTestAblasUnit::InternalRMatrixTrInverse(CMatrixDouble &a, + const int n, + const bool isupper, + const bool isunittriangular) + { +//--- create variables + bool result; + bool nounit; + int i=0; + int j=0; + double v=0; + double ajj=0; + int i_=0; +//--- create array + double t[]; +//--- initialization + result=true; +//--- allocation + ArrayResize(t,n); +//--- Test the input parameters. + nounit=!isunittriangular; +//--- check + if(isupper) + { + //--- Compute inverse of upper triangular matrix. + for(j=0;j<=n-1;j++) + { + //--- check + if(nounit) + { + //--- check + if(a[j][j]==0.0) + { + //--- return result + return(false); + } + //--- change values + a[j].Set(j,1/a[j][j]); + ajj=-a[j][j]; + } + else + ajj=-1; + //--- Compute elements 1:j-1 of j-th column. + if(j>0) + { + for(i_=0;i_<=j-1;i_++) + t[i_]=a[i_][j]; + for(i=0;i<=j-1;i++) + { + //--- check + if(i=0;j--) + { + //--- check + if(nounit) + { + //--- check + if(a[j][j]==0.0) + { + //--- return result + return(false); + } + //--- change values + a[j].Set(j,1/a[j][j]); + ajj=-a[j][j]; + } + else + ajj=-1; + //--- check + if(jj+1) + { + v=0.0; + for(i_=j+1;i_<=i-1;i_++) + v+=a[i][i_]*t[i_]; + } + else + v=0; + //--- check + if(nounit) + a[i].Set(j,v+a[i][i]*t[i]); + else + a[i].Set(j,v+t[i]); + } + //--- change values + for(i_=j+1;i_<=n-1;i_++) + a[i_].Set(j,ajj*a[i_][j]); + } + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Reference SYRK subroutine. | +//+------------------------------------------------------------------+ +static void CTestAblasUnit::RefCMatrixSyrk(const int n,const int k, + const double alpha,CMatrixComplex &a, + const int ia,const int ja, + const int optypea,const double beta, + CMatrixComplex &c,const int ic, + const int jc,const bool isupper) + { +//--- create variables + int i=0; + int j=0; + complex vc=0; + int i_=0; +//--- create matrix + CMatrixComplex ae; +//--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if((isupper && j>=i) || (!isupper && j<=i)) + { + //--- check + if(beta==0.0) + c[i+ic].Set(j+jc,0); + else + c[i+ic].Set(j+jc,c[i+ic][j+jc]*beta); + } + } + } +//--- check + if(alpha==0.0) + return; +//--- check + if(n*k>0) + ae.Resize(n,k); +//--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=k-1;j++) + { + //--- check + if(optypea==0) + ae[i].Set(j,a[ia+i][ja+j]); + //--- check + if(optypea==2) + ae[i].Set(j,CMath::Conj(a[ia+j][ja+i])); + } + } +//--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + vc=0; + //--- check + if(k>0) + { + vc=0.0; + for(i_=0;i_<=k-1;i_++) + vc+=ae[i][i_]*CMath::Conj(ae[j][i_]); + } + vc=vc*alpha; + //--- check + if(isupper && j>=i) + c[ic+i].Set(jc+j,vc+c[ic+i][jc+j]); + //--- check + if(!isupper && j<=i) + c[ic+i].Set(jc+j,vc+c[ic+i][jc+j]); + } + } + } +//+------------------------------------------------------------------+ +//| Reference SYRK subroutine. | +//+------------------------------------------------------------------+ +static void CTestAblasUnit::RefRMatrixSyrk(const int n,const int k, + const double alpha,CMatrixDouble &a, + const int ia,const int ja, + const int optypea,const double beta, + CMatrixDouble &c,const int ic, + const int jc,const bool isupper) + { +//--- create variables + int i=0; + int j=0; + double vr=0; + int i_=0; +//--- create matrix + CMatrixDouble ae; +//--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if((isupper && j>=i) || (!isupper && j<=i)) + { + //--- check + if(beta==0.0) + c[i+ic].Set(j+jc,0); + else + c[i+ic].Set(j+jc,c[i+ic][j+jc]*beta); + } + } + } +//--- check + if(alpha==0.0) + return; +//--- check + if(n*k>0) + ae.Resize(n,k); +//--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=k-1;j++) + { + //--- check + if(optypea==0) + ae[i].Set(j,a[ia+i][ja+j]); + //--- check + if(optypea==1) + ae[i].Set(j,a[ia+j][ja+i]); + } + } +//--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + vr=0; + //--- check + if(k>0) + { + vr=0.0; + for(i_=0;i_<=k-1;i_++) + vr+=ae[i][i_]*ae[j][i_]; + } + vr=alpha*vr; + //--- check + if(isupper && j>=i) + c[ic+i].Set(jc+j,vr+c[ic+i][jc+j]); + //--- check + if(!isupper && j<=i) + c[ic+i].Set(jc+j,vr+c[ic+i][jc+j]); + } + } + } +//+------------------------------------------------------------------+ +//| Reference GEMM, | +//| ALGLIB subroutine | +//+------------------------------------------------------------------+ +static void CTestAblasUnit::RefCMatrixGemm(const int m,const int n, + const int k,complex &alpha, + CMatrixComplex &a,const int ia, + const int ja,const int optypea, + CMatrixComplex &b,const int ib, + const int jb,const int optypeb, + complex &beta,CMatrixComplex &c, + const int ic,const int jc) + { +//--- create variables + int i=0; + int j=0; + complex vc=0; + int i_=0; +//--- create matrix + CMatrixComplex ae; + CMatrixComplex be; +//--- allocation + ae.Resize(m,k); +//--- change values + for(i=0;i<=m-1;i++) + { + for(j=0;j<=k-1;j++) + { + //--- check + if(optypea==0) + ae[i].Set(j,a[ia+i][ja+j]); + //--- check + if(optypea==1) + ae[i].Set(j,a[ia+j][ja+i]); + //--- check + if(optypea==2) + ae[i].Set(j,CMath::Conj(a[ia+j][ja+i])); + } + } +//--- allocation + be.Resize(k,n); +//--- change values + for(i=0;i<=k-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(optypeb==0) + be[i].Set(j,b[ib+i][jb+j]); + //--- check + if(optypeb==1) + be[i].Set(j,b[ib+j][jb+i]); + //--- check + if(optypeb==2) + be[i].Set(j,CMath::Conj(b[ib+j][jb+i])); + } + } +//--- calculation + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + vc=0.0; + for(i_=0;i_<=k-1;i_++) + vc+=ae[i][i_]*be[i_][j]; + vc=alpha*vc; + //--- check + if(beta!=0) + vc=vc+beta*c[ic+i][jc+j]; + c[ic+i].Set(jc+j,vc); + } + } + } +//+------------------------------------------------------------------+ +//| Reference GEMM, | +//| ALGLIB subroutine | +//+------------------------------------------------------------------+ +static void CTestAblasUnit::RefRMatrixGemm(const int m,const int n, + const int k,const double alpha, + CMatrixDouble &a,const int ia, + const int ja,const int optypea, + CMatrixDouble &b,const int ib, + const int jb,const int optypeb, + const double beta,CMatrixDouble &c, + const int ic,const int jc) + { +//--- create variables + int i=0; + int j=0; + double vc=0; + int i_=0; +//--- create matrix + CMatrixDouble ae; + CMatrixDouble be; +//--- allocation + ae.Resize(m,k); +//--- change values + for(i=0;i<=m-1;i++) + { + for(j=0;j<=k-1;j++) + { + //--- check + if(optypea==0) + ae[i].Set(j,a[ia+i][ja+j]); + //--- check + if(optypea==1) + ae[i].Set(j,a[ia+j][ja+i]); + } + } +//--- allocation + be.Resize(k,n); +//--- change values + for(i=0;i<=k-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(optypeb==0) + be[i].Set(j,b[ib+i][jb+j]); + //--- check + if(optypeb==1) + be[i].Set(j,b[ib+j][jb+i]); + } + } +//--- calculation + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + vc=0.0; + for(i_=0;i_<=k-1;i_++) + vc+=ae[i][i_]*be[i_][j]; + vc=alpha*vc; + //--- check + if(beta!=0.0) + vc=vc+beta*c[ic+i][jc+j]; + c[ic+i].Set(jc+j,vc); + } + } + } +//+------------------------------------------------------------------+ +//| Testing class CBaseStat | +//+------------------------------------------------------------------+ +class CTestBaseStatUnit + { +public: + //--- constructor, destructor + CTestBaseStatUnit(void); + ~CTestBaseStatUnit(void); + //--- public method + static bool TestBaseStat(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestBaseStatUnit::CTestBaseStatUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestBaseStatUnit::~CTestBaseStatUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CBaseStat | +//+------------------------------------------------------------------+ +static bool CTestBaseStatUnit::TestBaseStat(const bool silent) + { +//--- create variables + bool waserrors; + bool s1errors; + bool covcorrerrors; + double threshold=0; + int i=0; + int j=0; + int n=0; + int kx=0; + int ky=0; + int ctype=0; + int cidxx=0; + int cidxy=0; + double mean=0; + double variance=0; + double skewness=0; + double kurtosis=0; + double adev=0; + double median=0; + double pv=0; + double v=0; + int i_=0; +//--- create arrays + double x[]; + double y[]; +//--- create matrix + CMatrixDouble mx; + CMatrixDouble my; + CMatrixDouble cc; + CMatrixDouble cp; + CMatrixDouble cs; +//--- Primary settings + waserrors=false; + s1errors=false; + covcorrerrors=false; + threshold=1000*CMath::m_machineepsilon; +//--- * prepare X and Y - two test samples +//--- * test 1-sample coefficients + n=10; +//--- allocation + ArrayResize(x,n); + for(i=0;i<=n-1;i++) + x[i]=CMath::Sqr(i); +//--- function call + CBaseStat::SampleMoments(x,n,mean,variance,skewness,kurtosis); +//--- search errors + s1errors=s1errors || MathAbs(mean-28.5)>0.001; + s1errors=s1errors || MathAbs(variance-801.1667)>0.001; + s1errors=s1errors || MathAbs(skewness-0.5751)>0.001; + s1errors=s1errors || MathAbs(kurtosis+1.2666)>0.001; +//--- function call + CBaseStat::SampleAdev(x,n,adev); +//--- search errors + s1errors=s1errors || MathAbs(adev-23.2000)>0.001; +//--- function call + CBaseStat::SampleMedian(x,n,median); +//--- search errors + s1errors=s1errors || MathAbs(median-0.5*(16+25))>0.001; + for(i=0;i<=n-1;i++) + { + //--- function call + CBaseStat::SamplePercentile(x,n,(double)i/(double)(n-1),pv); + //--- search errors + s1errors=s1errors || MathAbs(pv-x[i])>0.001; + } +//--- function call + CBaseStat::SamplePercentile(x,n,0.5,pv); +//--- search errors + s1errors=s1errors || MathAbs(pv-0.5*(16+25))>0.001; +//--- test covariance/correlation: +//--- * 2-sample coefficients +//--- We generate random matrices MX and MY + n=10; + ArrayResize(x,n); + ArrayResize(y,n); + for(i=0;i<=n-1;i++) + { + x[i]=CMath::Sqr(i); + y[i]=i; + } +//--- search errors + covcorrerrors=covcorrerrors || MathAbs(CBaseStat::PearsonCorr2(x,y,n)-0.9627)>0.0001; + covcorrerrors=covcorrerrors || MathAbs(CBaseStat::SpearmanCorr2(x,y,n)-1.0000)>0.0001; + covcorrerrors=covcorrerrors || MathAbs(CBaseStat::Cov2(x,y,n)-82.5000)>0.0001; + for(i=0;i<=n-1;i++) + { + x[i]=CMath::Sqr(i-0.5*n); + y[i]=i; + } +//--- search errors + covcorrerrors=covcorrerrors || MathAbs(CBaseStat::PearsonCorr2(x,y,n)+0.3676)>0.0001; + covcorrerrors=covcorrerrors || MathAbs(CBaseStat::SpearmanCorr2(x,y,n)+0.2761)>0.0001; + covcorrerrors=covcorrerrors || MathAbs(CBaseStat::Cov2(x,y,n)+9.1667)>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++) + { + //--- check + if(n>0) + { + //--- allocation + ArrayResize(x,n); + ArrayResize(y,n); + } + //--- calculation + 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; + //--- check + if(n>0) + { + //--- allocation + mx.Resize(n,kx); + my.Resize(n,ky); + //--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=kx-1;j++) + mx[i].Set(j,2*CMath::RandomReal()-1); + for(j=0;j<=ky-1;j++) + my[i].Set(j,2*CMath::RandomReal()-1); + } + //--- check + if(ctype==1) + { + cidxx=CMath::RandomInteger(kx); + cidxy=CMath::RandomInteger(ky); + //--- change values + for(i=0;i<=n-1;i++) + { + mx[i].Set(cidxx,0.0); + my[i].Set(cidxy,0.0); + } + } + //--- check + if(ctype==2) + { + cidxx=CMath::RandomInteger(kx); + cidxy=CMath::RandomInteger(ky); + //--- change values + v=MathSqrt((CMath::RandomInteger(kx)+1)/(double)kx); + for(i=0;i<=n-1;i++) + { + mx[i].Set(cidxx,v); + my[i].Set(cidxy,v); + } + } + } + //--- test covariance/correlation matrix using + //--- 2-sample functions as reference point. + //--- We also test that coefficients for constant variables + //--- are exactly zero. + CBaseStat::CovM(mx,n,kx,cc); + CBaseStat::PearsonCorrM(mx,n,kx,cp); + CBaseStat::SpearmanCorrM(mx,n,kx,cs); + for(i=0;i<=kx-1;i++) + { + for(j=0;j<=kx-1;j++) + { + //--- check + if(n>0) + { + for(i_=0;i_<=n-1;i_++) + { + x[i_]=mx[i_][i]; + } + for(i_=0;i_<=n-1;i_++) + { + y[i_]=mx[i_][j]; + } + } + //--- search errors + covcorrerrors=covcorrerrors || MathAbs(CBaseStat::Cov2(x,y,n)-cc[i][j])>threshold; + covcorrerrors=covcorrerrors || MathAbs(CBaseStat::PearsonCorr2(x,y,n)-cp[i][j])>threshold; + covcorrerrors=covcorrerrors || MathAbs(CBaseStat::SpearmanCorr2(x,y,n)-cs[i][j])>threshold; + } + } + //--- check + if(ctype!=0 && n>0) + { + for(i=0;i<=kx-1;i++) + { + //--- search errors + covcorrerrors=covcorrerrors || cc[i][cidxx]!=0.0; + covcorrerrors=covcorrerrors || cc[cidxx][i]!=0.0; + covcorrerrors=covcorrerrors || cp[i][cidxx]!=0.0; + covcorrerrors=covcorrerrors || cp[cidxx][i]!=0.0; + covcorrerrors=covcorrerrors || cs[i][cidxx]!=0.0; + covcorrerrors=covcorrerrors || cs[cidxx][i]!=0.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. + CBaseStat::CovM2(mx,my,n,kx,ky,cc); + CBaseStat::PearsonCorrM2(mx,my,n,kx,ky,cp); + CBaseStat::SpearmanCorrM2(mx,my,n,kx,ky,cs); + for(i=0;i<=kx-1;i++) + { + for(j=0;j<=ky-1;j++) + { + //--- check + if(n>0) + { + for(i_=0;i_<=n-1;i_++) + x[i_]=mx[i_][i]; + for(i_=0;i_<=n-1;i_++) + y[i_]=my[i_][j]; + } + //--- search errors + covcorrerrors=covcorrerrors || MathAbs(CBaseStat::Cov2(x,y,n)-cc[i][j])>threshold; + covcorrerrors=covcorrerrors || MathAbs(CBaseStat::PearsonCorr2(x,y,n)-cp[i][j])>threshold; + covcorrerrors=covcorrerrors || MathAbs(CBaseStat::SpearmanCorr2(x,y,n)-cs[i][j])>threshold; + } + } + //--- check + if(ctype!=0 && n>0) + { + for(i=0;i<=kx-1;i++) + { + //--- search errors + covcorrerrors=covcorrerrors || cc[i][cidxy]!=0.0; + covcorrerrors=covcorrerrors || cp[i][cidxy]!=0.0; + covcorrerrors=covcorrerrors || cs[i][cidxy]!=0.0; + } + for(j=0;j<=ky-1;j++) + { + //--- search errors + covcorrerrors=covcorrerrors || cc[cidxx][j]!=0.0; + covcorrerrors=covcorrerrors || cp[cidxx][j]!=0.0; + covcorrerrors=covcorrerrors || cs[cidxx][j]!=0.0; + } + } + } + } + } + } +//--- Final report + waserrors=s1errors || covcorrerrors; +//--- check + if(!silent) + { + Print("DESC.STAT TEST"); + Print("TOTAL RESULTS: "); + //--- check + if(!waserrors) + Print("OK"); + else + Print("FAILED"); + Print("* 1-SAMPLE FUNCTIONALITY: "); + //--- check + if(!s1errors) + Print("OK"); + else + Print("FAILED"); + Print("* CORRELATION/COVARIATION: "); + //--- check + if(!covcorrerrors) + Print("OK"); + else + Print("FAILED"); + //--- check + if(waserrors) + Print("TEST SUMMARY: FAILED"); + else + Print("TEST SUMMARY: PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Testing class CBdSS | +//+------------------------------------------------------------------+ +class CTestBdSSUnit + { +public: + CTestBdSSUnit(void); + ~CTestBdSSUnit(void); + + static bool TestBdSS(const bool silent); + +private: + static void Unset2D(CMatrixComplex &a); + static void Unset1D(double &a[]); + static void Unset1DI(int &a[]); + static void TestSortResults(double &asorted[],int &p1[],int &p2[],double &aoriginal[],const int n,bool &waserrors); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestBdSSUnit::CTestBdSSUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestBdSSUnit::~CTestBdSSUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CBdSS | +//+------------------------------------------------------------------+ +static bool CTestBdSSUnit::TestBdSS(const bool silent) + { +//--- create variables + int n=0; + int i=0; + int j=0; + int pass=0; + int passcount=0; + int maxn=0; + int maxnq=0; + int tiecount=0; + int c1=0; + int c0=0; + int ni=0; + int nc=0; + double pal=0; + double pbl=0; + double par=0; + double pbr=0; + double cve=0; + double cvr=0; + int info=0; + double threshold=0; + double rms=0; + double cvrms=0; + bool waserrors; + bool tieserrors; + bool split2errors; + bool optimalsplitkerrors; + bool splitkerrors; +//--- create arrays + double a[]; + double a0[]; + double at[]; + double thresholds[]; + int c[]; + int p1[]; + int p2[]; + int ties[]; + int pt1[]; + int pt2[]; + double tmp[]; + double sortrbuf[]; + double sortrbuf2[]; + int sortibuf[]; + int tiebuf[]; + int cntbuf[]; +//--- create matrix + CMatrixDouble p; +//--- initialization + waserrors=false; + tieserrors=false; + split2errors=false; + splitkerrors=false; + optimalsplitkerrors=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 + Unset1DI(p1); + Unset1DI(p2); + Unset1DI(pt1); + Unset1DI(pt2); + //--- allocation + ArrayResize(a,n); + ArrayResize(a0,n); + ArrayResize(at,n); + ArrayResize(tmp,n); + //--- change values + a[0]=2*CMath::RandomReal()-1; + tmp[0]=CMath::RandomReal(); + for(i=1;i<=n-1;i++) + { + //--- A is randomly permuted + a[i]=a[i-1]+0.1*CMath::RandomReal()+0.1; + tmp[i]=CMath::RandomReal(); + } + //--- function call + CTSort::TagSortFastR(tmp,a,sortrbuf,sortrbuf2,n); + for(i=0;i<=n-1;i++) + { + a0[i]=a[i]; + at[i]=a[i]; + } + //--- function call + CBdSS::DSTie(a0,n,ties,tiecount,p1,p2); + //--- function call + CTSort::TagSort(at,n,pt1,pt2); + //--- search errors + for(i=0;i<=n-1;i++) + { + tieserrors=tieserrors || p1[i]!=pt1[i]; + tieserrors=tieserrors || p2[i]!=pt2[i]; + } + tieserrors=tieserrors || tiecount!=n; + //--- check + if(tiecount==n) + { + for(i=0;i<=n;i++) + tieserrors=tieserrors || ties[i]!=i; + } + //--- tied data,test DSTie + Unset1DI(p1); + Unset1DI(p2); + Unset1DI(pt1); + Unset1DI(pt2); + //--- allocation + ArrayResize(a,n); + ArrayResize(a0,n); + ArrayResize(at,n); + //--- change values + c1=0; + c0=0; + for(i=0;i<=n-1;i++) + { + a[i]=CMath::RandomInteger(2); + //--- check + if(a[i]==0.0) + c0=c0+1; + else + c1=c1+1; + a0[i]=a[i]; + at[i]=a[i]; + } + //--- function call + CBdSS::DSTie(a0,n,ties,tiecount,p1,p2); + //--- function call + CTSort::TagSort(at,n,pt1,pt2); + //--- search errors + for(i=0;i<=n-1;i++) + { + tieserrors=tieserrors || p1[i]!=pt1[i]; + tieserrors=tieserrors || p2[i]!=pt2[i]; + } + //--- check + if(c0==0 || c1==0) + { + //--- search errors + tieserrors=tieserrors || tiecount!=1; + //--- check + if(tiecount==1) + { + tieserrors=tieserrors || ties[0]!=0; + tieserrors=tieserrors || ties[1]!=n; + } + } + else + { + //--- search errors + tieserrors=tieserrors || tiecount!=2; + //--- check + if(tiecount==2) + { + tieserrors=tieserrors || ties[0]!=0; + tieserrors=tieserrors || ties[1]!=c0; + tieserrors=tieserrors || ties[2]!=n; + } + } + } + } +//--- split-2 +//--- General tests for different N's + for(n=1;n<=maxn;n++) + { + //--- allocation + ArrayResize(a,n); + ArrayResize(c,n); + //--- one-tie test + if(n%2==0) + { + for(i=0;i<=n-1;i++) + { + a[i]=n; + c[i]=i%2; + } + //--- function call + CBdSS::DSOptimalSplit2(a,c,n,info,threshold,pal,pbl,par,pbr,cve); + //--- check + if(info!=-3) + { + split2errors=true; + continue; + } + } + //--- two-tie test + //--- test #1 + if(n>1) + { + for(i=0;i<=n-1;i++) + { + a[i]=i/((n+1)/2); + c[i]=i/((n+1)/2); + } + //--- function call + CBdSS::DSOptimalSplit2(a,c,n,info,threshold,pal,pbl,par,pbr,cve); + //--- check + if(info!=1) + { + split2errors=true; + continue; + } + //--- search errors + split2errors=split2errors || MathAbs(threshold-0.5)>100*CMath::m_machineepsilon; + split2errors=split2errors || MathAbs(pal-1)>100*CMath::m_machineepsilon; + split2errors=split2errors || MathAbs(pbl-0)>100*CMath::m_machineepsilon; + split2errors=split2errors || MathAbs(par-0)>100*CMath::m_machineepsilon; + split2errors=split2errors || MathAbs(pbr-1)>100*CMath::m_machineepsilon; + } + } +//--- Special "CREDIT"-test (transparency coefficient) + n=110; +//--- allocation + ArrayResize(a,n); + ArrayResize(c,n); +//--- initialization + a[0]=0.000; + c[0]=0; + a[1]=0.000; + c[1]=0; + a[2]=0.000; + c[2]=0; + a[3]=0.000; + c[3]=0; + a[4]=0.000; + c[4]=0; + a[5]=0.000; + c[5]=0; + a[6]=0.000; + c[6]=0; + a[7]=0.000; + c[7]=1; + a[8]=0.000; + c[8]=0; + a[9]=0.000; + c[9]=1; + a[10]=0.000; + c[10]=0; + a[11]=0.000; + c[11]=0; + a[12]=0.000; + c[12]=0; + a[13]=0.000; + c[13]=0; + a[14]=0.000; + c[14]=0; + a[15]=0.000; + c[15]=0; + a[16]=0.000; + c[16]=0; + a[17]=0.000; + c[17]=0; + a[18]=0.000; + c[18]=0; + a[19]=0.000; + c[19]=0; + a[20]=0.000; + c[20]=0; + a[21]=0.000; + c[21]=0; + a[22]=0.000; + c[22]=1; + a[23]=0.000; + c[23]=0; + a[24]=0.000; + c[24]=0; + a[25]=0.000; + c[25]=0; + a[26]=0.000; + c[26]=0; + a[27]=0.000; + c[27]=1; + a[28]=0.000; + c[28]=0; + a[29]=0.000; + c[29]=1; + a[30]=0.000; + c[30]=0; + a[31]=0.000; + c[31]=1; + a[32]=0.000; + c[32]=0; + a[33]=0.000; + c[33]=1; + a[34]=0.000; + c[34]=0; + a[35]=0.030; + c[35]=0; + a[36]=0.030; + c[36]=0; + a[37]=0.050; + c[37]=0; + a[38]=0.070; + c[38]=1; + a[39]=0.110; + c[39]=0; + a[40]=0.110; + c[40]=1; + a[41]=0.120; + c[41]=0; + a[42]=0.130; + c[42]=0; + a[43]=0.140; + c[43]=0; + a[44]=0.140; + c[44]=0; + a[45]=0.140; + c[45]=0; + a[46]=0.150; + c[46]=0; + a[47]=0.150; + c[47]=0; + a[48]=0.170; + c[48]=0; + a[49]=0.190; + c[49]=1; + a[50]=0.200; + c[50]=0; + a[51]=0.200; + c[51]=0; + a[52]=0.250; + c[52]=0; + a[53]=0.250; + c[53]=0; + a[54]=0.260; + c[54]=0; + a[55]=0.270; + c[55]=0; + a[56]=0.280; + c[56]=0; + a[57]=0.310; + c[57]=0; + a[58]=0.310; + c[58]=0; + a[59]=0.330; + c[59]=0; + a[60]=0.330; + c[60]=0; + a[61]=0.340; + c[61]=0; + a[62]=0.340; + c[62]=0; + a[63]=0.370; + c[63]=0; + a[64]=0.380; + c[64]=1; + a[65]=0.380; + c[65]=0; + a[66]=0.410; + c[66]=0; + a[67]=0.460; + c[67]=0; + a[68]=0.520; + c[68]=0; + a[69]=0.530; + c[69]=0; + a[70]=0.540; + c[70]=0; + a[71]=0.560; + c[71]=0; + a[72]=0.560; + c[72]=0; + a[73]=0.570; + c[73]=0; + a[74]=0.600; + c[74]=0; + a[75]=0.600; + c[75]=0; + a[76]=0.620; + c[76]=0; + a[77]=0.650; + c[77]=0; + a[78]=0.660; + c[78]=0; + a[79]=0.680; + c[79]=0; + a[80]=0.700; + c[80]=0; + a[81]=0.750; + c[81]=0; + a[82]=0.770; + c[82]=0; + a[83]=0.770; + c[83]=0; + a[84]=0.770; + c[84]=0; + a[85]=0.790; + c[85]=0; + a[86]=0.810; + c[86]=0; + a[87]=0.840; + c[87]=0; + a[88]=0.860; + c[88]=0; + a[89]=0.870; + c[89]=0; + a[90]=0.890; + c[90]=0; + a[91]=0.900; + c[91]=1; + a[92]=0.900; + c[92]=0; + a[93]=0.910; + c[93]=0; + a[94]=0.940; + c[94]=0; + a[95]=0.950; + c[95]=0; + a[96]=0.952; + c[96]=0; + a[97]=0.970; + c[97]=0; + a[98]=0.970; + c[98]=0; + a[99]=0.980; + c[99]=0; + a[100]=1.000; + c[100]=0; + a[101]=1.000; + c[101]=0; + a[102]=1.000; + c[102]=0; + a[103]=1.000; + c[103]=0; + a[104]=1.000; + c[104]=0; + a[105]=1.020; + c[105]=0; + a[106]=1.090; + c[106]=0; + a[107]=1.130; + c[107]=0; + a[108]=1.840; + c[108]=0; + a[109]=2.470; + c[109]=0; +//--- function call + CBdSS::DSOptimalSplit2(a,c,n,info,threshold,pal,pbl,par,pbr,cve); +//--- check + if(info!=1) + split2errors=true; + else + { + //--- search errors + split2errors=split2errors || MathAbs(threshold-0.195)>100*CMath::m_machineepsilon; + split2errors=split2errors || MathAbs(pal-0.80)>0.02; + split2errors=split2errors || MathAbs(pbl-0.20)>0.02; + split2errors=split2errors || MathAbs(par-0.97)>0.02; + split2errors=split2errors || MathAbs(pbr-0.03)>0.02; + } +//--- split-2 fast +//--- General tests for different N's + for(n=1;n<=maxn;n++) + { + //--- allocation + ArrayResize(a,n); + ArrayResize(c,n); + ArrayResize(tiebuf,n+1); + ArrayResize(cntbuf,4); + //--- one-tie test + if(n%2==0) + { + for(i=0;i<=n-1;i++) + { + a[i]=n; + c[i]=i%2; + } + //--- function call + CBdSS::DSOptimalSplit2Fast(a,c,tiebuf,cntbuf,sortrbuf,sortibuf,n,2,0.00,info,threshold,rms,cvrms); + //--- check + if(info!=-3) + { + split2errors=true; + continue; + } + } + //--- two-tie test + //--- test #1 + if(n>1) + { + for(i=0;i<=n-1;i++) + { + a[i]=i/((n+1)/2); + c[i]=i/((n+1)/2); + } + //--- function call + CBdSS::DSOptimalSplit2Fast(a,c,tiebuf,cntbuf,sortrbuf,sortibuf,n,2,0.00,info,threshold,rms,cvrms); + //--- check + if(info!=1) + { + split2errors=true; + continue; + } + //--- search errors + split2errors=split2errors || MathAbs(threshold-0.5)>100*CMath::m_machineepsilon; + split2errors=split2errors || MathAbs(rms-0)>100*CMath::m_machineepsilon; + //--- check + if(n==2) + split2errors=split2errors || MathAbs(cvrms-0.5)>100*CMath::m_machineepsilon; + else + { + //--- check + if(n==3) + split2errors=split2errors || MathAbs(cvrms-MathSqrt((2*0+2*0+2*0.25)/6))>100*CMath::m_machineepsilon; + else + split2errors=split2errors || MathAbs(cvrms)>100*CMath::m_machineepsilon; + } + } + } +//--- special tests + n=10; +//--- allocation + ArrayResize(a,n); + ArrayResize(c,n); + ArrayResize(tiebuf,n+1); + ArrayResize(cntbuf,2*3); +//--- change values + for(i=0;i<=n-1;i++) + { + a[i]=i; + //--- check + if(i<=n-3) + c[i]=0; + else + c[i]=i-(n-3); + } +//--- function call + CBdSS::DSOptimalSplit2Fast(a,c,tiebuf,cntbuf,sortrbuf,sortibuf,n,3,0.00,info,threshold,rms,cvrms); +//--- check + if(info!=1) + split2errors=true; + else + { + //--- search errors + split2errors=split2errors || MathAbs(threshold-(n-2.5))>100*CMath::m_machineepsilon; + split2errors=split2errors || MathAbs(rms-MathSqrt((0.25+0.25+0.25+0.25)/(3*n)))>100*CMath::m_machineepsilon; + split2errors=split2errors || MathAbs(cvrms-MathSqrt((double)(1+1+1+1)/(double)(3*n)))>100*CMath::m_machineepsilon; + } +//--- Optimal split-K +//--- General tests for different N's + for(n=1;n<=maxnq;n++) + { + //--- allocation + ArrayResize(a,n); + ArrayResize(c,n); + //--- one-tie test + if(n%2==0) + { + for(i=0;i<=n-1;i++) + { + a[i]=n; + c[i]=i%2; + } + //--- function call + CBdSS::DSOptimalSplitK(a,c,n,2,2+CMath::RandomInteger(5),info,thresholds,ni,cve); + //--- check + if(info!=-3) + { + optimalsplitkerrors=true; + continue; + } + } + //--- two-tie test + //--- test #1 + if(n>1) + { + c0=0; + c1=0; + for(i=0;i<=n-1;i++) + { + a[i]=i/((n+1)/2); + c[i]=i/((n+1)/2); + //--- check + if(c[i]==0) + c0=c0+1; + //--- check + if(c[i]==1) + c1=c1+1; + } + //--- function call + CBdSS::DSOptimalSplitK(a,c,n,2,2+CMath::RandomInteger(5),info,thresholds,ni,cve); + //--- check + if(info!=1) + { + optimalsplitkerrors=true; + continue; + } + //--- search errors + optimalsplitkerrors=optimalsplitkerrors || ni!=2; + optimalsplitkerrors=optimalsplitkerrors || MathAbs(thresholds[0]-0.5)>100*CMath::m_machineepsilon; + optimalsplitkerrors=optimalsplitkerrors || MathAbs(cve-(-(c0*MathLog((double)c0/(double)(c0+1)))-c1*MathLog((double)c1/(double)(c1+1))))>100*CMath::m_machineepsilon; + } + //--- test #2 + if(n>2) + { + c0=1+CMath::RandomInteger(n-1); + c1=n-c0; + for(i=0;i<=n-1;i++) + { + //--- check + if(i100*CMath::m_machineepsilon; + optimalsplitkerrors=optimalsplitkerrors || MathAbs(cve-(-(c0*MathLog((double)c0/(double)(c0+1)))-c1*MathLog((double)c1/(double)(c1+1))))>100*CMath::m_machineepsilon; + } + //--- multi-tie test + if(n>=16) + { + //--- Multi-tie test. + //--- First NC-1 ties have C0 entries,remaining NC-th tie + //--- have C1 entries. + nc=(int)MathRound(MathSqrt(n)); + 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[j]=j; + c[j]=i; + } + } + //--- change values + for(j=c0*(nc-1);j<=n-1;j++) + { + a[j]=j; + c[j]=nc-1; + } + //--- function call + CBdSS::DSOptimalSplitK(a,c,n,nc,nc+CMath::RandomInteger(nc),info,thresholds,ni,cve); + //--- check + if(info!=1) + { + optimalsplitkerrors=true; + continue; + } + //--- search errors + optimalsplitkerrors=optimalsplitkerrors || ni!=nc; + //--- check + if(ni==nc) + { + for(i=0;i<=nc-2;i++) + optimalsplitkerrors=optimalsplitkerrors || MathAbs(thresholds[i]-(c0*(i+1)-1+0.5))>100*CMath::m_machineepsilon; + cvr=-((nc-1)*c0*MathLog((double)c0/(double)(c0+nc-1))+c1*MathLog((double)c1/(double)(c1+nc-1))); + optimalsplitkerrors=optimalsplitkerrors || MathAbs(cve-cvr)>100*CMath::m_machineepsilon; + } + } + } +//--- Non-optimal split-K +//--- General tests for different N's + for(n=1;n<=maxnq;n++) + { + //--- allocation + ArrayResize(a,n); + ArrayResize(c,n); + //--- one-tie test + if(n%2==0) + { + for(i=0;i<=n-1;i++) + { + a[i]=pass; + c[i]=i%2; + } + //--- function call + CBdSS::DSSplitK(a,c,n,2,2+CMath::RandomInteger(5),info,thresholds,ni,cve); + //--- check + if(info!=-3) + { + splitkerrors=true; + continue; + } + } + //--- two-tie test + //--- test #1 + if(n>1) + { + c0=0; + c1=0; + for(i=0;i<=n-1;i++) + { + a[i]=i/((n+1)/2); + c[i]=i/((n+1)/2); + //--- check + if(c[i]==0) + c0=c0+1; + //--- check + if(c[i]==1) + c1=c1+1; + } + //--- function call + CBdSS::DSSplitK(a,c,n,2,2+CMath::RandomInteger(5),info,thresholds,ni,cve); + //--- check + if(info!=1) + { + splitkerrors=true; + continue; + } + //--- search errors + splitkerrors=splitkerrors || ni!=2; + //--- check + if(ni==2) + { + splitkerrors=splitkerrors || MathAbs(thresholds[0]-0.5)>100*CMath::m_machineepsilon; + splitkerrors=splitkerrors || MathAbs(cve-(-(c0*MathLog((double)c0/(double)(c0+1)))-c1*MathLog((double)c1/(double)(c1+1))))>100*CMath::m_machineepsilon; + } + } + //--- test #2 + if(n>2) + { + c0=1+CMath::RandomInteger(n-1); + c1=n-c0; + for(i=0;i<=n-1;i++) + { + //--- check + if(i100*CMath::m_machineepsilon; + splitkerrors=splitkerrors || MathAbs(cve-(-(c0*MathLog((double)c0/(double)(c0+1)))-c1*MathLog((double)c1/(double)(c1+1))))>100*CMath::m_machineepsilon; + } + } + //--- multi-tie test + for(c0=4;c0<=n;c0++) + { + //--- check + if((n%c0==0 && n/c0<=c0) && n/c0>1) + { + nc=n/c0; + for(i=0;i<=nc-1;i++) + { + for(j=c0*i;j<=c0*(i+1)-1;j++) + { + a[j]=j; + c[j]=i; + } + } + //--- function call + CBdSS::DSSplitK(a,c,n,nc,nc+CMath::RandomInteger(nc),info,thresholds,ni,cve); + //--- check + if(info!=1) + { + splitkerrors=true; + continue; + } + splitkerrors=splitkerrors || ni!=nc; + //--- check + if(ni==nc) + { + for(i=0;i<=nc-2;i++) + { + splitkerrors=splitkerrors || MathAbs(thresholds[i]-(c0*(i+1)-1+0.5))>100*CMath::m_machineepsilon; + } + cvr=-(nc*c0*MathLog((double)c0/(double)(c0+nc-1))); + splitkerrors=splitkerrors || MathAbs(cve-cvr)>100*CMath::m_machineepsilon; + } + } + } + } +//--- report + waserrors=((tieserrors || split2errors) || optimalsplitkerrors) || splitkerrors; +//--- check + if(!silent) + { + Print("TESTING BASIC DATASET SUBROUTINES"); + Print("TIES: "); + //--- check + if(!tieserrors) + Print("OK"); + else + Print("FAILED"); + Print("SPLIT-2: "); + //--- check + if(!split2errors) + Print("OK"); + else + Print("FAILED"); + Print("OPTIMAL SPLIT-K: "); + //--- check + if(!optimalsplitkerrors) + Print("OK"); + else + Print("FAILED"); + Print("SPLIT-K: "); + //--- check + if(!splitkerrors) + Print("OK"); + else + Print("FAILED"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Unsets 2D array. | +//+------------------------------------------------------------------+ +static void CTestBdSSUnit::Unset2D(CMatrixComplex &a) + { +//--- allocation + a.Resize(1,1); +//--- change value + a[0].Set(0,2*CMath::RandomReal()-1); + } +//+------------------------------------------------------------------+ +//| Unsets 1D array. | +//+------------------------------------------------------------------+ +static void CTestBdSSUnit::Unset1D(double &a[]) + { +//--- allocation + ArrayResize(a,1); +//--- change value + a[0]=2*CMath::RandomReal()-1; + } +//+------------------------------------------------------------------+ +//| Unsets 1D array. | +//+------------------------------------------------------------------+ +static void CTestBdSSUnit::Unset1DI(int &a[]) + { +//--- allocation + ArrayResize(a,1); +//--- change value + a[0]=CMath::RandomInteger(3)-1; + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestBdSSUnit::TestSortResults(double &asorted[],int &p1[], + int &p2[],double &aoriginal[], + const int n,bool &waserrors) + { +//--- create variables + int i=0; + double t=0; +//--- create arrays + double a2[]; + int f[]; +//--- allocation + ArrayResize(a2,n); + ArrayResize(f,n); +//--- is set ordered? + for(i=0;i<=n-2;i++) + waserrors=waserrors || asorted[i]>asorted[i+1]; +//--- P1 correctness + for(i=0;i<=n-1;i++) + waserrors=waserrors || asorted[i]!=aoriginal[p1[i]]; +//--- change values + for(i=0;i<=n-1;i++) + f[i]=0; + for(i=0;i<=n-1;i++) + f[p1[i]]=f[p1[i]]+1; +//--- search errors + for(i=0;i<=n-1;i++) + waserrors=waserrors || f[i]!=1; +//--- P2 correctness + for(i=0;i<=n-1;i++) + a2[i]=aoriginal[i]; + for(i=0;i<=n-1;i++) + { + //--- check + if(p2[i]!=i) + { + t=a2[i]; + a2[i]=a2[p2[i]]; + a2[p2[i]]=t; + } + } +//--- search errors + for(i=0;i<=n-1;i++) + waserrors=waserrors || asorted[i]!=a2[i]; + } +//+------------------------------------------------------------------+ +//| Testing class CDForest | +//+------------------------------------------------------------------+ +class CTestDForestUnit + { +public: + CTestDForestUnit(void); + ~CTestDForestUnit(void); + + static bool TestDForest(const bool silent); + +private: + static void TestProcessing(bool &err); + static void BasicTest1(const int nvars,const int nclasses,const int passcount,bool &err); + static void BasicTest2(bool &err); + static void BasicTest3(bool &err); + static void BasicTest4(bool &err); + static void BasicTest5(bool &err); + static double RNormal(void); + static void RSphere(CMatrixDouble &xy,const int n,const int i); + static void UnsetDF(CDecisionForest &df); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestDForestUnit::CTestDForestUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestDForestUnit::~CTestDForestUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CDForest | +//+------------------------------------------------------------------+ +static bool CTestDForestUnit::TestDForest(const bool silent) + { +//--- create variables + int ncmax=0; + int nvmax=0; + int passcount=0; + int nvars=0; + int nclasses=0; + bool waserrors; + bool basicerrors; + bool procerrors; +//--- Primary settings + nvmax=4; + ncmax=3; + passcount=10; + basicerrors=false; + procerrors=false; + waserrors=false; +//--- Tests + TestProcessing(procerrors); + for(nvars=1;nvars<=nvmax;nvars++) + { + for(nclasses=1;nclasses<=ncmax;nclasses++) + BasicTest1(nvars,nclasses,passcount,basicerrors); + } +//--- function calls + BasicTest2(basicerrors); + BasicTest3(basicerrors); + BasicTest4(basicerrors); + BasicTest5(basicerrors); +//--- Final report + waserrors=basicerrors || procerrors; +//--- check + if(!silent) + { + Print("RANDOM FOREST TEST"); + Print(""); + Print("TOTAL RESULTS: "); + //--- check + if(!waserrors) + Print("OK"); + else + Print("FAILED"); + Print("* PROCESSING FUNCTIONS: "); + //--- check + if(!procerrors) + Print("OK"); + else + Print("FAILED"); + Print("* BASIC TESTS: "); + //--- check + if(!basicerrors) + Print("OK"); + else + Print("FAILED"); + //--- check + if(waserrors) + Print("TEST SUMMARY: FAILED"); + else + Print("TEST SUMMARY: PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Processing functions test | +//+------------------------------------------------------------------+ +static void CTestDForestUnit::TestProcessing(bool &err) + { +//--- create variables + int nvars=0; + int nclasses=0; + int nsample=0; + int ntrees=0; + int nfeatures=0; + int flags=0; + int npoints=0; + int pass=0; + int passcount=0; + int i=0; + int j=0; + bool allsame; + int info=0; + double v=0; +//--- create matrix + CMatrixDouble xy; +//--- create arrays + double x1[]; + double x2[]; + double y1[]; + double y2[]; +//--- objects of classes + CDecisionForest df1; + CDecisionForest df2; + CDFReport rep; +//--- initialization + passcount=100; +//--- Main cycle + for(pass=1;pass<=passcount;pass++) + { + //--- initialize parameters + nvars=1+CMath::RandomInteger(5); + nclasses=1+CMath::RandomInteger(3); + ntrees=1+CMath::RandomInteger(4); + nfeatures=1+CMath::RandomInteger(nvars); + flags=0; + //--- check + if(CMath::RandomReal()>0.5) + flags=flags+2; + //--- Initialize arrays and data + npoints=10+CMath::RandomInteger(50); + nsample=(int)(MathMax(10,CMath::RandomInteger(npoints))); + //--- allocation + ArrayResize(x1,nvars); + ArrayResize(x2,nvars); + ArrayResize(y1,nclasses); + ArrayResize(y2,nclasses); + xy.Resize(npoints,nvars+1); + //--- change values + for(i=0;i<=npoints-1;i++) + { + for(j=0;j<=nvars-1;j++) + { + //--- check + if(j%2==0) + xy[i].Set(j,2*CMath::RandomReal()-1); + else + xy[i].Set(j,CMath::RandomInteger(2)); + } + //--- check + if(nclasses==1) + xy[i].Set(nvars,2*CMath::RandomReal()-1); + else + xy[i].Set(nvars,CMath::RandomInteger(nclasses)); + } + //--- create forest + CDForest::DFBuildInternal(xy,npoints,nvars,nclasses,ntrees,nsample,nfeatures,flags,info,df1,rep); + //--- check + if(info<=0) + { + err=true; + return; + } + //--- Same inputs leads to same outputs + for(i=0;i<=nvars-1;i++) + { + x1[i]=2*CMath::RandomReal()-1; + x2[i]=x1[i]; + } + for(i=0;i<=nclasses-1;i++) + { + y1[i]=2*CMath::RandomReal()-1; + y2[i]=2*CMath::RandomReal()-1; + } + //--- function call + CDForest::DFProcess(df1,x1,y1); + //--- function call + CDForest::DFProcess(df1,x2,y2); + allsame=true; + //--- search errors + for(i=0;i<=nclasses-1;i++) + allsame=allsame && y1[i]==y2[i]; + err=err || !allsame; + //--- Same inputs on original forest leads to same outputs + //--- on copy created using DFCopy + UnsetDF(df2); + //--- function call + CDForest::DFCopy(df1,df2); + for(i=0;i<=nvars-1;i++) + { + x1[i]=2*CMath::RandomReal()-1; + x2[i]=x1[i]; + } + for(i=0;i<=nclasses-1;i++) + { + y1[i]=2*CMath::RandomReal()-1; + y2[i]=2*CMath::RandomReal()-1; + } + //--- function call + CDForest::DFProcess(df1,x1,y1); + //--- function call + CDForest::DFProcess(df2,x2,y2); + allsame=true; + //--- search errors + for(i=0;i<=nclasses-1;i++) + allsame=allsame && y1[i]==y2[i]; + err=err || !allsame; + //--- Same inputs on original forest leads to same outputs + //--- on copy created using DFSerialize + UnsetDF(df2); + { + //--- This code passes data structure through serializers + //--- (serializes it to string and loads back) + CSerializer _local_serializer; + string _local_str; + //--- serialization + _local_serializer.Reset(); + _local_serializer.Alloc_Start(); + CDForest::DFAlloc(_local_serializer,df1); + _local_serializer.SStart_Str(); + CDForest::DFSerialize(_local_serializer,df1); + _local_serializer.Stop(); + _local_str=_local_serializer.Get_String(); + //--- unserialization + _local_serializer.Reset(); + _local_serializer.UStart_Str(_local_str); + CDForest::DFUnserialize(_local_serializer,df2); + _local_serializer.Stop(); + } + for(i=0;i<=nvars-1;i++) + { + x1[i]=2*CMath::RandomReal()-1; + x2[i]=x1[i]; + } + for(i=0;i<=nclasses-1;i++) + { + y1[i]=2*CMath::RandomReal()-1; + y2[i]=2*CMath::RandomReal()-1; + } + //--- function call + CDForest::DFProcess(df1,x1,y1); + //--- function call + CDForest::DFProcess(df2,x2,y2); + allsame=true; + //--- search errors + for(i=0;i<=nclasses-1;i++) + allsame=allsame && y1[i]==y2[i]; + err=err || !allsame; + //--- Normalization properties + if(nclasses>1) + { + for(i=0;i<=nvars-1;i++) + x1[i]=2*CMath::RandomReal()-1; + //--- function call + CDForest::DFProcess(df1,x1,y1); + v=0; + //--- search errors + for(i=0;i<=nclasses-1;i++) + { + v=v+y1[i]; + err=err || y1[i]<0.0; + } + err=err || MathAbs(v-1)>1000*CMath::m_machineepsilon; + } + } + } +//+------------------------------------------------------------------+ +//| Basic test: one-tree forest built using full sample must | +//| remember all the training cases | +//+------------------------------------------------------------------+ +static void CTestDForestUnit::BasicTest1(const int nvars,const int nclasses, + const int passcount,bool &err) + { +//--- create variables + int pass=0; + int npoints=0; + int i=0; + int j=0; + int k=0; + double s=0; + int info=0; + bool hassame; + int i_=0; +//--- create arrays + double x[]; + double y[]; +//--- create matrix + CMatrixDouble xy; +//--- objects of classes + CDecisionForest df; + CDFReport rep; +//--- check + if(nclasses==1) + { + //--- only classification tasks + return; + } +//--- calculation + for(pass=1;pass<=passcount;pass++) + { + //--- select number of points + if(pass<=3 && passcount>3) + npoints=pass; + else + npoints=100+CMath::RandomInteger(100); + //--- Prepare task + xy.Resize(npoints,nvars+1); + ArrayResize(x,nvars); + ArrayResize(y,nclasses); + //--- change values + for(i=0;i<=npoints-1;i++) + { + for(j=0;j<=nvars-1;j++) + xy[i].Set(j,2*CMath::RandomReal()-1); + xy[i].Set(nvars,CMath::RandomInteger(nclasses)); + } + //--- Test + CDForest::DFBuildInternal(xy,npoints,nvars,nclasses,1,npoints,1,1,info,df,rep); + //--- check + if(info<=0) + { + err=true; + return; + } + //--- calculation + for(i=0;i<=npoints-1;i++) + { + for(i_=0;i_<=nvars-1;i_++) + x[i_]=xy[i][i_]; + //--- function call + CDForest::DFProcess(df,x,y); + s=0; + for(j=0;j<=nclasses-1;j++) + { + //--- check + if(y[j]<0.0) + { + err=true; + return; + } + s=s+y[j]; + } + //--- check + if(MathAbs(s-1)>1000*CMath::m_machineepsilon) + { + err=true; + return; + } + //--- check + if(MathAbs(y[(int)MathRound(xy[i][nvars])]-1)>1000*CMath::m_machineepsilon) + { + //--- not an error if there exists such K,J that XY[k].Set(j,XY[I,J] + //--- (may be we just can't distinguish two tied values). + //--- definitely error otherwise. + hassame=false; + for(k=0;k<=npoints-1;k++) + { + //--- check + if(k!=i) + { + for(j=0;j<=nvars-1;j++) + { + //--- check + if(xy[k][j]==xy[i][j]) + hassame=true; + } + } + } + //--- check + if(!hassame) + { + err=true; + return; + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Basic test: tests generalization ability on a simple noisy | +//| classification task: | +//| * 01000*CMath::m_machineepsilon) + { + err=true; + return; + } + //--- test for good correlation with results + if(x[0]<1.0) + err=err || y[0]<0.8; + //--- check + if(x[0]>=1.0 && x[0]<=2.0) + err=err || MathAbs(y[1]-(x[0]-1))>0.5; + //--- check + if(x[0]>2.0) + err=err || y[1]<0.8; + x[0]=x[0]+0.01; + } + } + } +//+------------------------------------------------------------------+ +//| Basic test: tests generalization ability on a simple | +//| classification task (no noise): | +//| * ||x||<1,||y||<1 | +//| * x^2+y^2<=0.25 - P(class=0)=1 | +//| * x^2+y^2>0.25 - P(class=0)=0 | +//+------------------------------------------------------------------+ +static void CTestDForestUnit::BasicTest3(bool &err) + { +//--- create variables + int pass=0; + int passcount=0; + int npoints=0; + int ntrees=0; + int i=0; + int j=0; + int k=0; + double s=0; + int info=0; + int testgridsize=0; + double r=0; +//--- create arrays + double x[]; + double y[]; +//--- create matrix + CMatrixDouble xy; +//--- objects of classes + CDecisionForest df; + CDFReport rep; +//--- initialization + passcount=1; + testgridsize=50; +//--- calculation + for(pass=1;pass<=passcount;pass++) + { + //--- select npoints and ntrees + npoints=2000; + ntrees=100; + //--- Prepare task + xy.Resize(npoints,3); + ArrayResize(x,2); + ArrayResize(y,2); + //--- change values + for(i=0;i<=npoints-1;i++) + { + xy[i].Set(0,2*CMath::RandomReal()-1); + xy[i].Set(1,2*CMath::RandomReal()-1); + //--- check + if(CMath::Sqr(xy[i][0])+CMath::Sqr(xy[i][1])<=0.25) + xy[i].Set(2,0); + else + xy[i].Set(2,1); + } + //--- Test + CDForest::DFBuildInternal(xy,npoints,2,2,ntrees,(int)MathRound(0.1*npoints),1,0,info,df,rep); + //--- check + if(info<=0) + { + err=true; + return; + } + //--- calculation + for(i=-(testgridsize/2);i<=testgridsize/2;i++) + { + for(j=-(testgridsize/2);j<=testgridsize/2;j++) + { + x[0]=(double)i/(double)(testgridsize/2); + x[1]=(double)j/(double)(testgridsize/2); + //--- function call + CDForest::DFProcess(df,x,y); + //--- Test for basic properties + s=0; + for(k=0;k<=1;k++) + { + //--- check + if(y[k]<0.0) + { + err=true; + return; + } + s=s+y[k]; + } + //--- check + if(MathAbs(s-1)>1000*CMath::m_machineepsilon) + { + err=true; + return; + } + //--- test for good correlation with results + r=MathSqrt(CMath::Sqr(x[0])+CMath::Sqr(x[1])); + //--- check + if(r<0.5*0.5) + err=err || y[0]<0.6; + //--- check + if(r>0.5*1.5) + err=err || y[1]<0.6; + } + } + } + } +//+------------------------------------------------------------------+ +//| Basic test: simple regression task without noise: | +//| * ||x||<1,||y||<1 | +//| * F(x,y)=x^2+y | +//+------------------------------------------------------------------+ +static void CTestDForestUnit::BasicTest4(bool &err) + { +//--- create variables + int pass=0; + int passcount=0; + int npoints=0; + int ntrees=0; + int ns=0; + int strongc=0; + int i=0; + int j=0; + int info=0; + int testgridsize=0; + double maxerr=0; + double maxerr2=0; + double avgerr=0; + double avgerr2=0; + int cnt=0; + double ey=0; +//--- create arrays + double x[]; + double y[]; +//--- create matrix + CMatrixDouble xy; +//--- objects of classes + CDecisionForest df; + CDecisionForest df2; + CDFReport rep; + CDFReport rep2; +//--- initialization + passcount=1; + testgridsize=50; +//--- calculation + for(pass=1;pass<=passcount;pass++) + { + //--- select npoints and ntrees + npoints=5000; + ntrees=100; + ns=(int)MathRound(0.1*npoints); + strongc=1; + //--- Prepare task + xy.Resize(npoints,3); + ArrayResize(x,2); + ArrayResize(y,1); + //--- change values + for(i=0;i<=npoints-1;i++) + { + xy[i].Set(0,2*CMath::RandomReal()-1); + xy[i].Set(1,2*CMath::RandomReal()-1); + xy[i].Set(2,CMath::Sqr(xy[i][0])+xy[i][1]); + } + //--- Test + CDForest::DFBuildInternal(xy,npoints,2,1,ntrees,ns,1,0,info,df,rep); + //--- check + if(info<=0) + { + err=true; + return; + } + //--- function call + CDForest::DFBuildInternal(xy,npoints,2,1,ntrees,ns,1,strongc,info,df2,rep2); + //--- check + if(info<=0) + { + err=true; + return; + } + //--- change values + maxerr=0; + maxerr2=0; + avgerr=0; + avgerr2=0; + cnt=0; + //--- calculation + for(i=(int)MathRound(-(0.7*testgridsize/2));i<=(int)MathRound(0.7*testgridsize/2);i++) + { + for(j=(int)MathRound(-(0.7*testgridsize/2));j<=(int)MathRound(0.7*testgridsize/2);j++) + { + x[0]=(double)i/(double)(testgridsize/2); + x[1]=(double)j/(double)(testgridsize/2); + ey=CMath::Sqr(x[0])+x[1]; + //--- function call + CDForest::DFProcess(df,x,y); + maxerr=MathMax(maxerr,MathAbs(y[0]-ey)); + avgerr=avgerr+MathAbs(y[0]-ey); + //--- function call + CDForest::DFProcess(df2,x,y); + maxerr2=MathMax(maxerr2,MathAbs(y[0]-ey)); + avgerr2=avgerr2+MathAbs(y[0]-ey); + cnt=cnt+1; + } + } + //--- search errors + avgerr=avgerr/cnt; + avgerr2=avgerr2/cnt; + err=err || maxerr>0.2; + err=err || maxerr2>0.2; + err=err || avgerr>0.1; + err=err || avgerr2>0.1; + } + } +//+------------------------------------------------------------------+ +//| 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 CTestDForestUnit::BasicTest5(bool &err) + { +//--- create variables + int nvars=0; + int npoints=0; + int nfeatures=0; + int nsample=0; + int ntrees=0; + int evs=0; + int i=0; + int j=0; + bool eflag; + int info=0; + int i_=0; +//--- create arrays + double x[]; + double y[]; +//--- create matrix + CMatrixDouble xy; +//--- objects of classes + CDecisionForest df; + CDFReport rep; +//--- select npoints and ntrees + npoints=50; + nvars=npoints; + ntrees=1; + nsample=npoints; + evs=2; + nfeatures=1; +//--- Prepare task + xy.Resize(npoints,nvars+1); + ArrayResize(x,nvars); + ArrayResize(y,1); + for(i=0;i<=npoints-1;i++) + { + for(j=0;j<=nvars-1;j++) + { + xy[i].Set(j,0); + } + xy[i].Set(i,1); + xy[i].Set(nvars,i); + } +//--- Without EVS + CDForest::DFBuildInternal(xy,npoints,nvars,1,ntrees,nsample,nfeatures,0,info,df,rep); +//--- check + if(info<=0) + { + err=true; + return; + } +//--- calculation + eflag=false; + for(i=0;i<=npoints-1;i++) + { + for(i_=0;i_<=nvars-1;i_++) + x[i_]=xy[i][i_]; + //--- function call + CDForest::DFProcess(df,x,y); + //--- check + if(MathAbs(y[0]-xy[i][nvars])>1000*CMath::m_machineepsilon) + eflag=true; + } +//--- check + if(!eflag) + { + err=true; + return; + } +//--- With EVS + CDForest::DFBuildInternal(xy,npoints,nvars,1,ntrees,nsample,nfeatures,evs,info,df,rep); +//--- check + if(info<=0) + { + err=true; + return; + } +//--- calculation + eflag=false; + for(i=0;i<=npoints-1;i++) + { + for(i_=0;i_<=nvars-1;i_++) + { + x[i_]=xy[i][i_]; + } + //--- function call + CDForest::DFProcess(df,x,y); + //--- check + if(MathAbs(y[0]-xy[i][nvars])>1000*CMath::m_machineepsilon) + { + eflag=true; + } + } +//--- check + if(eflag) + { + err=true; + return; + } + } +//+------------------------------------------------------------------+ +//| Random normal number | +//+------------------------------------------------------------------+ +static double CTestDForestUnit::RNormal(void) + { +//--- create variables + double result=0; + double u=0; + double v=0; + double s=0; + double x1=0; + double x2=0; +//--- calculation + while(true) + { + u=2*CMath::RandomReal()-1; + v=2*CMath::RandomReal()-1; + s=CMath::Sqr(u)+CMath::Sqr(v); + //--- check + if(s>0.0 && s<1.0) + { + s=MathSqrt(-(2*MathLog(s)/s)); + x1=u*s; + x2=v*s; + //--- break the cycle + break; + } + } +//--- check + if(x1!=0) + result=x1; + else + result=x2; +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Random point from sphere | +//+------------------------------------------------------------------+ +static void CTestDForestUnit::RSphere(CMatrixDouble &xy,const int n, + const int i) + { +//--- create variables + int j=0; + double v=0; + int i_=0; +//--- change values + for(j=0;j<=n-1;j++) + xy[i].Set(j,RNormal()); + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=xy[i][i_]*xy[i][i_]; +//--- calculation + v=CMath::RandomReal()/MathSqrt(v); + for(i_=0;i_<=n-1;i_++) + xy[i].Set(i_,v*xy[i][i_]); + } +//+------------------------------------------------------------------+ +//| Unsets DF | +//+------------------------------------------------------------------+ +static void CTestDForestUnit::UnsetDF(CDecisionForest &df) + { +//--- create a variable + int info=0; +//--- create matrix + CMatrixDouble xy; +//--- object of class + CDFReport rep; +//--- allocation + xy.Resize(1,2); +//--- change values + xy[0].Set(0,0); + xy[0].Set(1,0); +//--- function call + CDForest::DFBuildInternal(xy,1,1,1,1,1,1,0,info,df,rep); + } +//+------------------------------------------------------------------+ +//| Testing class CBlas | +//+------------------------------------------------------------------+ +class CTestBlasUnit + { +private: + //--- private method + static void NaiveMatrixMatrixMultiply(CMatrixDouble &a,const int ai1,const int ai2,const int aj1,const int aj2,const bool transa,CMatrixDouble &b,const int bi1,const int bi2,const int bj1,const int bj2,const bool transb,const double alpha,CMatrixDouble &c,const int ci1,const int ci2,const int cj1,const int cj2,const double beta); +public: + //--- constructor, destructor + CTestBlasUnit(void); + ~CTestBlasUnit(void); + //--- public method + static bool TestBlas(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestBlasUnit::CTestBlasUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestBlasUnit::~CTestBlasUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CBlas | +//+------------------------------------------------------------------+ +static bool CTestBlasUnit::TestBlas(const bool silent) + { +//--- create variables + int pass=0; + int passcount=0; + int n=0; + int i=0; + int i1=0; + int i2=0; + int j=0; + int j1=0; + int j2=0; + int l=0; + int k=0; + int r=0; + int i3=0; + int j3=0; + int col1=0; + int col2=0; + int row1=0; + int row2=0; + double err=0; + double e1=0; + double e2=0; + double e3=0; + double v=0; + double scl1=0; + double scl2=0; + double scl3=0; + bool was1; + bool was2; + bool trans1; + bool trans2; + double threshold=0; + bool n2errors; + bool hsnerrors; + bool amaxerrors; + bool mverrors; + bool iterrors; + bool cterrors; + bool mmerrors; + bool waserrors; + int i_=0; +//--- create arrays + double x1[]; + double x2[]; +//--- create matrix + CMatrixDouble a; + CMatrixDouble b; + CMatrixDouble c1; + CMatrixDouble c2; +//--- initialization + n2errors=false; + amaxerrors=false; + hsnerrors=false; + mverrors=false; + iterrors=false; + cterrors=false; + mmerrors=false; + waserrors=false; + threshold=10000*CMath::m_machineepsilon; +//--- Test Norm2 + passcount=1000; + e1=0; + e2=0; + e3=0; + scl2=0.5*CMath::m_maxrealnumber; + scl3=2*CMath::m_minrealnumber; +//--- calculation + for(pass=1;pass<=passcount;pass++) + { + n=1+CMath::RandomInteger(1000); + i1=CMath::RandomInteger(10); + i2=n+i1-1; + //--- allocation + ArrayResize(x1,i2+1); + ArrayResize(x2,i2+1); + //--- change values + for(i=i1;i<=i2;i++) + x1[i]=2*CMath::RandomReal()-1; + v=0; + for(i=i1;i<=i2;i++) + v=v+CMath::Sqr(x1[i]); + v=MathSqrt(v); + //--- calculation + e1=MathMax(e1,MathAbs(v-CBlas::VectorNorm2(x1,i1,i2))); + for(i=i1;i<=i2;i++) + x2[i]=scl2*x1[i]; + //--- calculation + e2=MathMax(e2,MathAbs(v*scl2-CBlas::VectorNorm2(x2,i1,i2))); + for(i=i1;i<=i2;i++) + x2[i]=scl3*x1[i]; + //--- calculation + e3=MathMax(e3,MathAbs(v*scl3-CBlas::VectorNorm2(x2,i1,i2))); + } + e2=e2/scl2; + e3=e3/scl3; +//--- search errors + n2errors=(e1>=threshold || e2>=threshold) || e3>=threshold; +//--- Testing VectorAbsMax,Column/Row AbsMax + ArrayResize(x1,6); + x1[1]=2.0; + x1[2]=0.2; + x1[3]=-1.3; + x1[4]=0.7; + x1[5]=-3.0; +//--- search errors + amaxerrors=(CBlas::VectorIdxAbsMax(x1,1,5)!=5 || CBlas::VectorIdxAbsMax(x1,1,4)!=1) || CBlas::VectorIdxAbsMax(x1,2,4)!=3; + n=30; +//--- allocation + ArrayResize(x1,n+1); + a.Resize(n+1,n+1); + for(i=1;i<=n;i++) + { + for(j=1;j<=n;j++) + a[i].Set(j,2*CMath::RandomReal()-1); + } +//--- calculation + was1=false; + was2=false; + for(pass=1;pass<=1000;pass++) + { + //--- change values + j=1+CMath::RandomInteger(n); + i1=1+CMath::RandomInteger(n); + i2=i1+CMath::RandomInteger(n+1-i1); + for(i_=i1;i_<=i2;i_++) + x1[i_]=a[i_][j]; + //--- check + if(CBlas::VectorIdxAbsMax(x1,i1,i2)!=CBlas::ColumnIdxAbsMax(a,i1,i2,j)) + was1=true; + //--- change values + i=1+CMath::RandomInteger(n); + j1=1+CMath::RandomInteger(n); + j2=j1+CMath::RandomInteger(n+1-j1); + for(i_=j1;i_<=j2;i_++) + x1[i_]=a[i][i_]; + //--- check + if(CBlas::VectorIdxAbsMax(x1,j1,j2)!=CBlas::RowIdxAbsMax(a,j1,j2,i)) + was2=true; + } +//--- search errors + amaxerrors=(amaxerrors || was1) || was2; +//--- Testing upper Hessenberg 1-norm + a.Resize(4,4); + ArrayResize(x1,4); + a[1].Set(1,2); + a[1].Set(2,3); + a[1].Set(3,1); + a[2].Set(1,4); + a[2].Set(2,-5); + a[2].Set(3,8); + a[3].Set(1,99); + a[3].Set(2,3); + a[3].Set(3,1); +//--- search errors + hsnerrors=MathAbs(CBlas::UpperHessenberg1Norm(a,1,3,1,3,x1)-11)>threshold; +//--- Testing MatrixVectorMultiply + a.Resize(4,6); + ArrayResize(x1,4); + ArrayResize(x2,3); + a[2].Set(3,2); + a[2].Set(4,-1); + a[2].Set(5,-1); + a[3].Set(3,1); + a[3].Set(4,-2); + a[3].Set(5,2); + x1[1]=1; + x1[2]=2; + x1[3]=1; + x2[1]=-1; + x2[2]=-1; +//--- function calls + CBlas::MatrixVectorMultiply(a,2,3,3,5,false,x1,1,3,1.0,x2,1,2,1.0); + CBlas::MatrixVectorMultiply(a,2,3,3,5,true,x2,1,2,1.0,x1,1,3,1.0); +//--- calculation + e1=MathAbs(x1[1]+5)+MathAbs(x1[2]-8)+MathAbs(x1[3]+1)+MathAbs(x2[1]+2)+MathAbs(x2[2]+2); + x1[1]=1; + x1[2]=2; + x1[3]=1; + x2[1]=-1; + x2[2]=-1; +//--- function calls + CBlas::MatrixVectorMultiply(a,2,3,3,5,false,x1,1,3,1.0,x2,1,2,0.0); + CBlas::MatrixVectorMultiply(a,2,3,3,5,true,x2,1,2,1.0,x1,1,3,0.0); +//--- calculation + e2=MathAbs(x1[1]+3)+MathAbs(x1[2]-3)+MathAbs(x1[3]+1)+MathAbs(x2[1]+1)+MathAbs(x2[2]+1); + mverrors=e1+e2>=threshold; +//--- testing inplace transpose + n=10; + a.Resize(n+1,n+1); + b.Resize(n+1,n+1); + ArrayResize(x1,n); + for(i=1;i<=n;i++) + { + for(j=1;j<=n;j++) + a[i].Set(j,CMath::RandomReal()); + } +//--- calculation + passcount=10000; + was1=false; + for(pass=1;pass<=passcount;pass++) + { + //--- change values + i1=1+CMath::RandomInteger(n); + i2=i1+CMath::RandomInteger(n-i1+1); + j1=1+CMath::RandomInteger(n-(i2-i1)); + j2=j1+(i2-i1); + //--- function calls + CBlas::CopyMatrix(a,i1,i2,j1,j2,b,i1,i2,j1,j2); + CBlas::InplaceTranspose(b,i1,i2,j1,j2,x1); + for(i=i1;i<=i2;i++) + { + for(j=j1;j<=j2;j++) + { + //--- check + if(a[i][j]!=b[i1+(j-j1)][j1+(i-i1)]) + was1=true; + } + } + } +//--- change value + iterrors=was1; +//--- testing copy and transpose + n=10; + a.Resize(n+1,n+1); + b.Resize(n+1,n+1); + for(i=1;i<=n;i++) + { + for(j=1;j<=n;j++) + a[i].Set(j,CMath::RandomReal()); + } +//--- calculation + passcount=10000; + was1=false; + for(pass=1;pass<=passcount;pass++) + { + //--- change values + i1=1+CMath::RandomInteger(n); + i2=i1+CMath::RandomInteger(n-i1+1); + j1=1+CMath::RandomInteger(n); + j2=j1+CMath::RandomInteger(n-j1+1); + //--- function call + CBlas::CopyAndTranspose(a,i1,i2,j1,j2,b,j1,j2,i1,i2); + for(i=i1;i<=i2;i++) + { + for(j=j1;j<=j2;j++) + { + //--- check + if(a[i][j]!=b[j][i]) + was1=true; + } + } + } +//--- change values + cterrors=was1; +//--- Testing MatrixMatrixMultiply + n=10; + a.Resize(2*n+1,2*n+1); + b.Resize(2*n+1,2*n+1); + c1.Resize(2*n+1,2*n+1); + c2.Resize(2*n+1,2*n+1); + ArrayResize(x1,n+1); + ArrayResize(x2,n+1); + for(i=1;i<=2*n;i++) + { + for(j=1;j<=2*n;j++) + { + a[i].Set(j,CMath::RandomReal()); + b[i].Set(j,CMath::RandomReal()); + } + } +//--- calculation + passcount=1000; + was1=false; + for(pass=1;pass<=passcount;pass++) + { + for(i=1;i<=2*n;i++) + { + for(j=1;j<=2*n;j++) + { + c1[i].Set(j,2.1*i+3.1*j); + c2[i].Set(j,c1[i][j]); + } + } + //--- change values + l=1+CMath::RandomInteger(n); + k=1+CMath::RandomInteger(n); + r=1+CMath::RandomInteger(n); + i1=1+CMath::RandomInteger(n); + j1=1+CMath::RandomInteger(n); + i2=1+CMath::RandomInteger(n); + j2=1+CMath::RandomInteger(n); + i3=1+CMath::RandomInteger(n); + j3=1+CMath::RandomInteger(n); + trans1=CMath::RandomReal()>0.5; + trans2=CMath::RandomReal()>0.5; + //--- check + if(trans1) + { + col1=l; + row1=k; + } + else + { + col1=k; + row1=l; + } + //--- check + if(trans2) + { + col2=k; + row2=r; + } + else + { + col2=r; + row2=k; + } + //--- change values + scl1=CMath::RandomReal(); + scl2=CMath::RandomReal(); + //--- function calls + CBlas::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); + 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); + //--- search errors + err=0; + for(i=1;i<=l;i++) + { + for(j=1;j<=r;j++) + err=MathMax(err,MathAbs(c1[i3+i-1][j3+j-1]-c2[i3+i-1][j3+j-1])); + } + //--- check + if(err>threshold) + { + was1=true; + break; + } + } +//--- change value + mmerrors=was1; +//--- report + waserrors=(((((n2errors || amaxerrors) || hsnerrors) || mverrors) || iterrors) || cterrors) || mmerrors; +//--- check + if(!silent) + { + Print("TESTING BLAS"); + Print("VectorNorm2: "); + //--- check + if(n2errors) + Print("FAILED"); + else + Print("OK"); + Print("AbsMax (vector/row/column): "); + //--- check + if(amaxerrors) + Print("FAILED"); + else + Print("OK"); + Print("UpperHessenberg1Norm: "); + //--- check + if(hsnerrors) + Print("FAILED"); + else + Print("OK"); + Print("MatrixVectorMultiply: "); + //--- check + if(mverrors) + Print("FAILED"); + else + Print("OK"); + Print("InplaceTranspose: "); + //--- check + if(iterrors) + Print("FAILED"); + else + Print("OK"); + Print("CopyAndTranspose: "); + //--- check + if(cterrors) + Print("FAILED"); + else + Print("OK"); + Print("MatrixMatrixMultiply: "); + //--- check + if(mmerrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestBlasUnit::NaiveMatrixMatrixMultiply(CMatrixDouble &a, + const int ai1, + const int ai2, + const int aj1, + const int aj2, + const bool transa, + CMatrixDouble &b, + const int bi1, + const int bi2, + const int bj1, + const int bj2, + const bool transb, + const double alpha, + CMatrixDouble &c, + const int ci1, + const int ci2, + const int cj1, + const int cj2, + const double beta) + { +//--- create variables + int arows=0; + int acols=0; + int brows=0; + int bcols=0; + int i=0; + int j=0; + int k=0; + int l=0; + int r=0; + double v=0; + int i_=0; + int i1_=0; +//--- create arrays + double x1[]; + double x2[]; +//--- Setup + if(!transa) + { + arows=ai2-ai1+1; + acols=aj2-aj1+1; + } + else + { + arows=aj2-aj1+1; + acols=ai2-ai1+1; + } +//--- check + if(!transb) + { + brows=bi2-bi1+1; + bcols=bj2-bj1+1; + } + else + { + brows=bj2-bj1+1; + bcols=bi2-bi1+1; + } +//--- check + if(!CAp::Assert(acols==brows,"NaiveMatrixMatrixMultiply: incorrect matrix sizes!")) + return; +//--- check + if(((arows<=0 || acols<=0) || brows<=0) || bcols<=0) + return; +//--- change values + l=arows; + r=bcols; + k=acols; +//--- allocation + ArrayResize(x1,k+1); + ArrayResize(x2,k+1); +//--- calculation + for(i=1;i<=l;i++) + { + for(j=1;j<=r;j++) + { + //--- check + if(!transa) + { + //--- check + if(!transb) + { + //--- change values + i1_=aj1-bi1; + v=0.0; + for(i_=bi1;i_<=bi2;i_++) + v+=b[i_][bj1+j-1]*a[ai1+i-1][i_+i1_]; + } + else + { + //--- change values + i1_=aj1-bj1; + v=0.0; + for(i_=bj1;i_<=bj2;i_++) + v+=b[bi1+j-1][i_]*a[ai1+i-1][i_+i1_]; + } + } + else + { + //--- check + if(!transb) + { + //--- change values + i1_=ai1-bi1; + v=0.0; + for(i_=bi1;i_<=bi2;i_++) + v+=b[i_][bj1+j-1]*a[i_+i1_][aj1+i-1]; + } + else + { + //--- change values + i1_=ai1-bj1; + v=0.0; + for(i_=bj1;i_<=bj2;i_++) + v+=b[bi1+j-1][i_]*a[i_+i1_][aj1+i-1]; + } + } + //--- check + if(beta==0.0) + c[ci1+i-1].Set(cj1+j-1,alpha*v); + else + c[ci1+i-1].Set(cj1+j-1,beta*c[ci1+i-1][cj1+j-1]+alpha*v); + } + } + } +//+------------------------------------------------------------------+ +//| Testing class CKMeans | +//+------------------------------------------------------------------+ +class CTestKMeansUnit + { +public: + CTestKMeansUnit(void); + ~CTestKMeansUnit(void); + + static bool TestKMeans(const bool silent); + +private: + static void SimpleTest1(const int nvars,const int nc,int passcount,bool &converrors,bool &othererrors,bool &simpleerrors); + static void RestartsTest(bool &converrors,bool &restartserrors); + static double RNormal(void); + static void RSphere(CMatrixDouble &xy,const int n,const int i); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestKMeansUnit::CTestKMeansUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestKMeansUnit::~CTestKMeansUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CKMeans | +//+------------------------------------------------------------------+ +static bool CTestKMeansUnit::TestKMeans(const bool silent) + { +//--- create variables + int nf=0; + int maxnf=0; + int nc=0; + int maxnc=0; + int passcount=0; + bool waserrors; + bool converrors; + bool simpleerrors; + bool complexerrors; + bool othererrors; + bool restartserrors; +//--- Primary settings + maxnf=5; + maxnc=5; + passcount=10; + waserrors=false; + converrors=false; + othererrors=false; + simpleerrors=false; + complexerrors=false; + restartserrors=false; +//--- calculation + for(nf=1;nf<=maxnf;nf++) + { + for(nc=1;nc<=maxnc;nc++) + SimpleTest1(nf,nc,passcount,converrors,othererrors,simpleerrors); + } + RestartsTest(converrors,restartserrors); +//--- Final report + waserrors=(((converrors || othererrors) || simpleerrors) || complexerrors) || restartserrors; +//--- check + if(!silent) + { + Print("K-MEANS TEST"); + Print("TOTAL RESULTS: "); + //--- check + if(!waserrors) + Print("OK"); + else + Print("FAILED"); + Print("* CONVERGENCE: "); + //--- check + if(!converrors) + Print("OK"); + else + Print("FAILED"); + Print("* SIMPLE TASKS: "); + //--- check + if(!simpleerrors) + Print("OK"); + else + Print("FAILED"); + Print("* COMPLEX TASKS: "); + //--- check + if(!complexerrors) + Print("OK"); + else + Print("FAILED"); + Print("* OTHER PROPERTIES: "); + //--- check + if(!othererrors) + Print("OK"); + else + Print("FAILED"); + Print("* RESTARTS PROPERTIES: "); + //--- check + if(!restartserrors) + Print("OK"); + else + Print("FAILED"); + //--- check + if(waserrors) + Print("TEST SUMMARY: FAILED"); + else + Print("TEST SUMMARY: PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Simple test 1: ellipsoid in NF-dimensional space. | +//| compare k-means centers with random centers | +//+------------------------------------------------------------------+ +static void CTestKMeansUnit::SimpleTest1(const int nvars,const int nc, + int passcount,bool &converrors, + bool &othererrors,bool &simpleerrors) + { +//--- create variables + int npoints=0; + int majoraxis=0; + double v=0; + int i=0; + int j=0; + int info=0; + int pass=0; + int restarts=0; + double ekmeans=0; + double erandom=0; + double dclosest=0; + int cclosest=0; + int i_=0; +//--- create arrays + double tmp[]; + int xyc[]; +//--- create matrix + CMatrixDouble xy; + CMatrixDouble c; +//--- initialization + npoints=nc*100; + restarts=5; + passcount=10; +//--- allocation + ArrayResize(tmp,nvars); +//--- calculation + for(pass=1;pass<=passcount;pass++) + { + //--- Fill + xy.Resize(npoints,nvars); + majoraxis=CMath::RandomInteger(nvars); + for(i=0;i<=npoints-1;i++) + { + RSphere(xy,nvars,i); + xy[i].Set(majoraxis,nc*xy[i][majoraxis]); + } + //--- Test + CKMeans::KMeansGenerate(xy,npoints,nvars,nc,restarts,info,c,xyc); + //--- check + if(info<0) + { + converrors=true; + return; + } + //--- Test that XYC is correct mapping to cluster centers + for(i=0;i<=npoints-1;i++) + { + cclosest=-1; + dclosest=CMath::m_maxrealnumber; + //--- calculation + for(j=0;j<=nc-1;j++) + { + for(i_=0;i_<=nvars-1;i_++) + tmp[i_]=xy[i][i_]; + for(i_=0;i_<=nvars-1;i_++) + tmp[i_]=tmp[i_]-c[i_][j]; + v=0.0; + for(i_=0;i_<=nvars-1;i_++) + v+=tmp[i_]*tmp[i_]; + //--- check + if(v1 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 olved. 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 CTestKMeansUnit::RestartsTest(bool &converrors,bool &restartserrors) + { +//--- create variables + int npoints=0; + int nvars=0; + int nclusters=0; + int clustersize=0; + int restarts=0; + int passcount=0; + double sigmathreshold=0; + double p=0; + double s=0; + int i=0; + int j=0; + int info=0; + int pass=0; + double ea=0; + double eb=0; + double v=0; + int i_=0; +//--- create matrix + CMatrixDouble xy; + CMatrixDouble ca; + CMatrixDouble cb; +//--- create arrays + int xyca[]; + int xycb[]; + double tmp[]; +//--- initialization + restarts=5; + passcount=1000; + clustersize=20; + nclusters=3; + nvars=2; + npoints=nclusters*clustersize; + sigmathreshold=5; +//--- allocation + xy.Resize(npoints,nvars); + ArrayResize(tmp,nvars); + p=0; +//--- calculation + for(pass=1;pass<=passcount;pass++) + { + //--- Fill + for(i=0;i<=npoints-1;i++) + { + RSphere(xy,nvars,i); + for(j=0;j<=nvars-1;j++) + xy[i].Set(j,xy[i][j]+(double)i/(double)clustersize*5); + } + //--- Test: Restarts=1 + CKMeans::KMeansGenerate(xy,npoints,nvars,nclusters,1,info,ca,xyca); + //--- check + if(info<0) + { + converrors=true; + return; + } + //--- calculation + ea=0; + for(i=0;i<=npoints-1;i++) + { + for(i_=0;i_<=nvars-1;i_++) + tmp[i_]=xy[i][i_]; + for(i_=0;i_<=nvars-1;i_++) + tmp[i_]=tmp[i_]-ca[i_][xyca[i]]; + //--- change value + v=0.0; + for(i_=0;i_<=nvars-1;i_++) + v+=tmp[i_]*tmp[i_]; + ea=ea+v; + } + //--- Test: Restarts>1 + CKMeans::KMeansGenerate(xy,npoints,nvars,nclusters,restarts,info,cb,xycb); + //--- check + if(info<0) + { + converrors=true; + return; + } + //--- calculation + eb=0; + for(i=0;i<=npoints-1;i++) + { + for(i_=0;i_<=nvars-1;i_++) + tmp[i_]=xy[i][i_]; + for(i_=0;i_<=nvars-1;i_++) + tmp[i_]=tmp[i_]-cb[i_][xycb[i]]; + //--- change value + v=0.0; + for(i_=0;i_<=nvars-1;i_++) + v+=tmp[i_]*tmp[i_]; + eb=eb+v; + } + //--- Calculate statistic. + if(ea(double)(-sigmathreshold); + } +//+------------------------------------------------------------------+ +//| Random normal number | +//+------------------------------------------------------------------+ +static double CTestKMeansUnit::RNormal(void) + { +//--- create variables + double result=0; + double u=0; + double v=0; + double s=0; + double x1=0; + double x2=0; +//--- calculation + while(true) + { + //--- change values + u=2*CMath::RandomReal()-1; + v=2*CMath::RandomReal()-1; + s=CMath::Sqr(u)+CMath::Sqr(v); + //--- check + if(s>0.0 && s<1.0) + { + s=MathSqrt(-(2*MathLog(s)/s)); + x1=u*s; + x2=v*s; + //--- break the cycle + break; + } + } +//--- check + if(x1==0) + result=x2; + else + result=x1; +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Random point from sphere | +//+------------------------------------------------------------------+ +static void CTestKMeansUnit::RSphere(CMatrixDouble &xy,const int n,const int i) + { +//--- create variables + int j=0; + double v=0; + int i_=0; +//--- change values + for(j=0;j<=n-1;j++) + xy[i].Set(j,RNormal()); + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=xy[i][i_]*xy[i][i_]; +//--- calculation + v=CMath::RandomReal()/MathSqrt(v); + for(i_=0;i_<=n-1;i_++) + xy[i].Set(i_,v*xy[i][i_]); + } +//+------------------------------------------------------------------+ +//| Testing class CHblas | +//+------------------------------------------------------------------+ +class CTestHblasUnit + { +public: + //--- constructor, destructor + CTestHblasUnit(void); + ~CTestHblasUnit(void); + //--- public method + static bool TestHblas(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestHblasUnit::CTestHblasUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestHblasUnit::~CTestHblasUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CHblas | +//+------------------------------------------------------------------+ +static bool CTestHblasUnit::TestHblas(const bool silent) + { +//--- create variables + int n=0; + int maxn=0; + int i=0; + int j=0; + int i1=0; + int i2=0; + bool waserrors; + double mverr=0; + double threshold=0; + complex alpha=0; + complex v=0; + int i_=0; + int i1_=0; +//--- create arrays + complex x[]; + complex y1[]; + complex y2[]; + complex y3[]; +//--- create matrix + CMatrixComplex a; + CMatrixComplex ua; + CMatrixComplex la; +//--- initialization + mverr=0; + waserrors=false; + maxn=10; + threshold=1000*CMath::m_machineepsilon; +//--- Test MV + for(n=2;n<=maxn;n++) + { + //--- allocation + a.Resize(n+1,n+1); + ua.Resize(n+1,n+1); + la.Resize(n+1,n+1); + ArrayResize(x,n+1); + ArrayResize(y1,n+1); + ArrayResize(y2,n+1); + ArrayResize(y3,n+1); + //--- fill A,UA,LA + for(i=1;i<=n;i++) + { + a[i].SetRe(i,2*CMath::RandomReal()-1); + a[i].SetIm(i,0); + //--- change values + for(j=i+1;j<=n;j++) + { + a[i].SetRe(j,2*CMath::RandomReal()-1); + a[i].SetIm(j,2*CMath::RandomReal()-1); + a[j].Set(i,CMath::Conj(a[i][j])); + } + } + //--- change values + for(i=1;i<=n;i++) + { + for(j=1;j<=n;j++) + ua[i].Set(j,0); + } + //--- change values + for(i=1;i<=n;i++) + { + for(j=i;j<=n;j++) + ua[i].Set(j,a[i][j]); + } + //--- change values + for(i=1;i<=n;i++) + { + for(j=1;j<=n;j++) + la[i].Set(j,0); + } + //--- change values + for(i=1;i<=n;i++) + { + for(j=1;j<=i;j++) + la[i].Set(j,a[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[i].re=2*CMath::RandomReal()-1; + x[i].im=2*CMath::RandomReal()-1; + } + alpha.re=2*CMath::RandomReal()-1; + alpha.im=2*CMath::RandomReal()-1; + //--- calculate A*x,UA*x,LA*x + for(i=i1;i<=i2;i++) + { + i1_=1-i1; + v=0.0; + for(i_=i1;i_<=i2;i_++) + v+=a[i][i_]*x[i_+i1_]; + y1[i-i1+1]=alpha*v; + } + //--- function call + CHblas::HermitianMatrixVectorMultiply(ua,true,i1,i2,x,alpha,y2); + //--- function call + CHblas::HermitianMatrixVectorMultiply(la,false,i1,i2,x,alpha,y3); + //--- Calculate error + for(i_=1;i_<=i2-i1+1;i_++) + y2[i_]=y2[i_]-y1[i_]; + //--- change value + v=0.0; + for(i_=1;i_<=i2-i1+1;i_++) + v+=y2[i_]*CMath::Conj(y2[i_]); + //--- search errors + mverr=MathMax(mverr,MathSqrt(CMath::AbsComplex(v))); + for(i_=1;i_<=i2-i1+1;i_++) + y3[i_]=y3[i_]-y1[i_]; + //--- change value + v=0.0; + for(i_=1;i_<=i2-i1+1;i_++) + v+=y3[i_]*CMath::Conj(y3[i_]); + //--- search errors + mverr=MathMax(mverr,MathSqrt(CMath::AbsComplex(v))); + } + } + } +//--- report + waserrors=mverr>threshold; +//--- check + if(!silent) + { + Print("TESTING HERMITIAN BLAS"); + Print("MV error: "); + Print("{0,5:E3}",mverr); + Print("Threshold: "); + Print("{0,5:E3}",threshold); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Testing class CReflections | +//+------------------------------------------------------------------+ +class CTestReflectionsUnit + { +public: + //--- constructor, destructor + CTestReflectionsUnit(void); + ~CTestReflectionsUnit(void); + //--- public method + static bool TestReflections(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestReflectionsUnit::CTestReflectionsUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestReflectionsUnit::~CTestReflectionsUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CReflections | +//+------------------------------------------------------------------+ +static bool CTestReflectionsUnit::TestReflections(const bool silent) + { +//--- create variables + bool result; + int i=0; + int j=0; + int n=0; + int m=0; + int maxmn=0; + double tmp=0; + double beta=0; + double tau=0; + double err=0; + double mer=0; + double mel=0; + double meg=0; + int pass=0; + int passcount=0; + double threshold=0; + int tasktype=0; + double xscale=0; + int i_=0; +//--- create arrays + double x[]; + double v[]; + double work[]; +//--- create matrix + CMatrixDouble h; + CMatrixDouble a; + CMatrixDouble b; + CMatrixDouble c; +//--- initialization + passcount=10; + threshold=100*CMath::m_machineepsilon; + mer=0; + mel=0; + meg=0; +//--- calculation + for(pass=1;pass<=passcount;pass++) + { + for(n=1;n<=10;n++) + { + for(m=1;m<=10;m++) + { + //--- Task + n=1+CMath::RandomInteger(10); + m=1+CMath::RandomInteger(10); + maxmn=MathMax(m,n); + //--- Initialize + ArrayResize(x,maxmn+1); + ArrayResize(v,maxmn+1); + ArrayResize(work,maxmn+1); + h.Resize(maxmn+1,maxmn+1); + a.Resize(maxmn+1,maxmn+1); + b.Resize(maxmn+1,maxmn+1); + c.Resize(maxmn+1,maxmn+1); + //--- 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=1; + //--- check + if(tasktype==0) + { + for(i=1;i<=n;i++) + x[i]=2*CMath::RandomReal()-1; + } + //--- check + if(tasktype==1) + { + for(i=1;i<=n;i++) + x[i]=0; + } + //--- check + if(tasktype==2) + { + x[1]=2*CMath::RandomReal()-1; + for(i=2;i<=n;i++) + x[i]=0; + } + //--- check + if(tasktype==3) + { + for(i=1;i<=n;i++) + x[i]=(CMath::RandomInteger(21)-10)*CMath::m_minrealnumber; + xscale=10*CMath::m_minrealnumber; + } + //--- check + if(tasktype==4) + { + for(i=1;i<=n;i++) + x[i]=(2*CMath::RandomReal()-1)*CMath::m_maxrealnumber; + xscale=CMath::m_maxrealnumber; + } + for(i_=1;i_<=n;i_++) + { + v[i_]=x[i_]; + } + //--- function call + CReflections::GenerateReflection(v,n,tau); + //--- change values + beta=v[1]; + v[1]=1; + for(i=1;i<=n;i++) + { + for(j=1;j<=n;j++) + { + //--- check + if(i==j) + h[i].Set(j,1-tau*v[i]*v[j]); + else + h[i].Set(j,-(tau*v[i]*v[j])); + } + } + //--- calculation + err=0; + for(i=1;i<=n;i++) + { + tmp=0.0; + for(i_=1;i_<=n;i_++) + tmp+=h[i][i_]*x[i_]; + //--- check + if(i==1) + err=MathMax(err,MathAbs(tmp-beta)); + else + err=MathMax(err,MathAbs(tmp)); + } + meg=MathMax(meg,err/xscale); + } + //--- ApplyReflectionFromTheLeft + for(i=1;i<=m;i++) + { + x[i]=2*CMath::RandomReal()-1; + v[i]=x[i]; + } + for(i=1;i<=m;i++) + { + for(j=1;j<=n;j++) + { + a[i].Set(j,2*CMath::RandomReal()-1); + b[i].Set(j,a[i][j]); + } + } + //--- function call + CReflections::GenerateReflection(v,m,tau); + beta=v[1]; + v[1]=1; + //--- function call + CReflections::ApplyReflectionFromTheLeft(b,tau,v,1,m,1,n,work); + //--- change values + for(i=1;i<=m;i++) + { + for(j=1;j<=m;j++) + { + //--- check + if(i==j) + h[i].Set(j,1-tau*v[i]*v[j]); + else + h[i].Set(j,-(tau*v[i]*v[j])); + } + } + //--- calculation + for(i=1;i<=m;i++) + { + for(j=1;j<=n;j++) + { + tmp=0.0; + for(i_=1;i_<=m;i_++) + tmp+=h[i][i_]*a[i_][j]; + c[i].Set(j,tmp); + } + } + //--- change value + err=0; + for(i=1;i<=m;i++) + { + for(j=1;j<=n;j++) + err=MathMax(err,MathAbs(b[i][j]-c[i][j])); + } + mel=MathMax(mel,err); + //--- ApplyReflectionFromTheRight + for(i=1;i<=n;i++) + { + x[i]=2*CMath::RandomReal()-1; + v[i]=x[i]; + } + for(i=1;i<=m;i++) + { + for(j=1;j<=n;j++) + { + a[i].Set(j,2*CMath::RandomReal()-1); + b[i].Set(j,a[i][j]); + } + } + //--- function call + CReflections::GenerateReflection(v,n,tau); + beta=v[1]; + v[1]=1; + //--- function call + CReflections::ApplyReflectionFromTheRight(b,tau,v,1,m,1,n,work); + //--- change value + for(i=1;i<=n;i++) + { + for(j=1;j<=n;j++) + { + //--- check + if(i==j) + h[i].Set(j,1-tau*v[i]*v[j]); + else + h[i].Set(j,-(tau*v[i]*v[j])); + } + } + //--- calculation + for(i=1;i<=m;i++) + { + for(j=1;j<=n;j++) + { + tmp=0.0; + for(i_=1;i_<=n;i_++) + tmp+=a[i][i_]*h[i_][j]; + c[i].Set(j,tmp); + } + } + err=0; + for(i=1;i<=m;i++) + { + for(j=1;j<=n;j++) + err=MathMax(err,MathAbs(b[i][j]-c[i][j])); + } + mer=MathMax(mer,err); + } + } + } +//--- Overflow crash test + ArrayResize(x,11); + ArrayResize(v,11); + for(i=1;i<=10;i++) + v[i]=CMath::m_maxrealnumber*0.01*(2*CMath::RandomReal()-1); +//--- function call + CReflections::GenerateReflection(v,10,tau); + result=(meg<=threshold && mel<=threshold) && mer<=threshold; +//--- check + if(!silent) + { + Print("TESTING REFLECTIONS"); + Print("Pass count is "); + Print("{0,0:d}",passcount); + Print("Generate absolute error is "); + Print("{0,5:E3}",meg); + Print("Apply(Left) absolute error is "); + Print("{0,5:E3}",mel); + Print("Apply(Right) absolute error is "); + Print("{0,5:E3}",mer); + Print("Overflow crash test passed"); + //--- check + if(result) + Print("TEST PASSED"); + else + Print("TEST FAILED"); + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Testing class CComplexReflections | +//+------------------------------------------------------------------+ +class CTestCReflectionsUnit + { +public: + //--- constructor, destructor + CTestCReflectionsUnit(void); + ~CTestCReflectionsUnit(void); + //--- public method + static bool TestCReflections(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestCReflectionsUnit::CTestCReflectionsUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestCReflectionsUnit::~CTestCReflectionsUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CComplexReflections | +//+------------------------------------------------------------------+ +static bool CTestCReflectionsUnit::TestCReflections(const bool silent) + { +//--- create variables + int i=0; + int j=0; + int n=0; + int m=0; + int maxmn=0; + complex tmp=0; + complex beta=0; + complex tau=0; + double err=0; + double mer=0; + double mel=0; + double meg=0; + int pass=0; + int passcount=0; + bool waserrors; + double threshold=0; + int i_=0; +//--- create arrays + complex x[]; + complex v[]; + complex work[]; +//--- create matrix + CMatrixComplex h; + CMatrixComplex a; + CMatrixComplex b; + CMatrixComplex c; +//--- initialization + threshold=1000*CMath::m_machineepsilon; + passcount=1000; + mer=0; + mel=0; + meg=0; +//--- calculation + for(pass=1;pass<=passcount;pass++) + { + //--- Task + n=1+CMath::RandomInteger(10); + m=1+CMath::RandomInteger(10); + maxmn=MathMax(m,n); + //--- Initialize + ArrayResize(x,maxmn+1); + ArrayResize(v,maxmn+1); + ArrayResize(work,maxmn+1); + h.Resize(maxmn+1,maxmn+1); + a.Resize(maxmn+1,maxmn+1); + b.Resize(maxmn+1,maxmn+1); + c.Resize(maxmn+1,maxmn+1); + //--- GenerateReflection + for(i=1;i<=n;i++) + { + x[i].re=2*CMath::RandomReal()-1; + x[i].im=2*CMath::RandomReal()-1; + v[i]=x[i]; + } + //--- function call + CComplexReflections::ComplexGenerateReflection(v,n,tau); + //--- change values + beta=v[1]; + v[1]=1; + for(i=1;i<=n;i++) + { + for(j=1;j<=n;j++) + { + //--- check + if(i==j) + h[i].Set(j,-tau*v[i]*CMath::Conj(v[j])+1); + else + h[i].Set(j,-(tau*v[i]*CMath::Conj(v[j]))); + } + } + //--- calculation + err=0; + for(i=1;i<=n;i++) + { + tmp=0.0; + for(i_=1;i_<=n;i_++) + tmp+=CMath::Conj(h[i_][i])*x[i_]; + //--- check + if(i==1) + err=MathMax(err,CMath::AbsComplex(tmp-beta)); + else + err=MathMax(err,CMath::AbsComplex(tmp)); + } + err=MathMax(err,MathAbs(beta.im)); + meg=MathMax(meg,err); + //--- ApplyReflectionFromTheLeft + for(i=1;i<=m;i++) + { + x[i].re=2*CMath::RandomReal()-1; + x[i].im=2*CMath::RandomReal()-1; + v[i]=x[i]; + } + for(i=1;i<=m;i++) + { + for(j=1;j<=n;j++) + { + a[i].SetRe(j,2*CMath::RandomReal()-1); + a[i].SetIm(j,2*CMath::RandomReal()-1); + b[i].Set(j,a[i][j]); + } + } + //--- function call + CComplexReflections::ComplexGenerateReflection(v,m,tau); + beta=v[1]; + v[1]=1; + //--- function call + CComplexReflections::ComplexApplyReflectionFromTheLeft(b,tau,v,1,m,1,n,work); + //--- change values + for(i=1;i<=m;i++) + { + for(j=1;j<=m;j++) + { + //--- check + if(i==j) + h[i].Set(j,-tau*v[i]*CMath::Conj(v[j])+1); + else + h[i].Set(j,-(tau*v[i]*CMath::Conj(v[j]))); + } + } + //--- calculation + for(i=1;i<=m;i++) + { + for(j=1;j<=n;j++) + { + tmp=0.0; + for(i_=1;i_<=m;i_++) + tmp+=h[i][i_]*a[i_][j]; + c[i].Set(j,tmp); + } + } + err=0; + for(i=1;i<=m;i++) + { + for(j=1;j<=n;j++) + err=MathMax(err,CMath::AbsComplex(b[i][j]-c[i][j])); + } + mel=MathMax(mel,err); + //--- ApplyReflectionFromTheRight + for(i=1;i<=n;i++) + { + x[i]=2*CMath::RandomReal()-1; + v[i]=x[i]; + } + for(i=1;i<=m;i++) + { + for(j=1;j<=n;j++) + { + a[i].Set(j,2*CMath::RandomReal()-1); + b[i].Set(j,a[i][j]); + } + } + //--- function call + CComplexReflections::ComplexGenerateReflection(v,n,tau); + beta=v[1]; + v[1]=1; + //--- function call + CComplexReflections::ComplexApplyReflectionFromTheRight(b,tau,v,1,m,1,n,work); + //--- change values + for(i=1;i<=n;i++) + { + for(j=1;j<=n;j++) + { + //--- check + if(i==j) + h[i].Set(j,-tau*v[i]*CMath::Conj(v[j])+1); + else + h[i].Set(j,-(tau*v[i]*CMath::Conj(v[j]))); + } + } + //--- calculation + for(i=1;i<=m;i++) + { + for(j=1;j<=n;j++) + { + tmp=0.0; + for(i_=1;i_<=n;i_++) + tmp+=a[i][i_]*h[i_][j]; + c[i].Set(j,tmp); + } + } + err=0; + for(i=1;i<=m;i++) + { + for(j=1;j<=n;j++) + err=MathMax(err,CMath::AbsComplex(b[i][j]-c[i][j])); + } + mer=MathMax(mer,err); + } +//--- Overflow crash test + ArrayResize(x,11); + ArrayResize(v,11); + for(i=1;i<=10;i++) + v[i]=CMath::m_maxrealnumber*0.01*(2*CMath::RandomReal()-1); +//--- function call + CComplexReflections::ComplexGenerateReflection(v,10,tau); +//--- report + waserrors=(meg>threshold || mel>threshold) || mer>threshold; +//--- check + if(!silent) + { + Print("TESTING COMPLEX REFLECTIONS"); + Print("Generate error: "); + Print("{0,5:E3}",meg); + Print("Apply(L) error: "); + Print("{0,5:E3}",mel); + Print("Apply(R) error: "); + Print("{0,5:E3}",mer); + Print("Threshold: "); + Print("{0,5:E3}",threshold); + Print("Overflow crash test: PASSED"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Testing class CSblas | +//+------------------------------------------------------------------+ +class CTestSblasUnit + { +public: + //--- constructor, destructor + CTestSblasUnit(void); + ~CTestSblasUnit(void); + //--- public method + static bool TestSblas(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestSblasUnit::CTestSblasUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestSblasUnit::~CTestSblasUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CSblas | +//+------------------------------------------------------------------+ +static bool CTestSblasUnit::TestSblas(const bool silent) + { +//--- create variables + int n=0; + int maxn=0; + int i=0; + int j=0; + int i1=0; + int i2=0; + bool waserrors; + double mverr=0; + double threshold=0; + double alpha=0; + double v=0; + int i_=0; + int i1_=0; +//--- create arrays + double x[]; + double y1[]; + double y2[]; + double y3[]; +//--- create matrix + CMatrixDouble a; + CMatrixDouble ua; + CMatrixDouble la; +//--- initialization + mverr=0; + waserrors=false; + maxn=10; + threshold=1000*CMath::m_machineepsilon; +//--- Test MV + for(n=2;n<=maxn;n++) + { + //--- allocation + a.Resize(n+1,n+1); + ua.Resize(n+1,n+1); + la.Resize(n+1,n+1); + ArrayResize(x,n+1); + ArrayResize(y1,n+1); + ArrayResize(y2,n+1); + ArrayResize(y3,n+1); + //--- fill A,UA,LA + for(i=1;i<=n;i++) + { + a[i].Set(i,2*CMath::RandomReal()-1); + for(j=i+1;j<=n;j++) + { + a[i].Set(j,2*CMath::RandomReal()-1); + a[j].Set(i,a[i][j]); + } + } + //--- change values + for(i=1;i<=n;i++) + { + for(j=1;j<=n;j++) + ua[i].Set(j,0); + } + //--- change values + for(i=1;i<=n;i++) + { + for(j=i;j<=n;j++) + ua[i].Set(j,a[i][j]); + } + //--- change values + for(i=1;i<=n;i++) + { + for(j=1;j<=n;j++) + la[i].Set(j,0); + } + //--- change values + for(i=1;i<=n;i++) + { + for(j=1;j<=i;j++) + la[i].Set(j,a[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[i]=2*CMath::RandomReal()-1; + alpha=2*CMath::RandomReal()-1; + //--- calculate A*x,UA*x,LA*x + for(i=i1;i<=i2;i++) + { + i1_=1-i1; + v=0.0; + for(i_=i1;i_<=i2;i_++) + v+=a[i][i_]*x[i_+i1_]; + y1[i-i1+1]=alpha*v; + } + //--- function call + CSblas::SymmetricMatrixVectorMultiply(ua,true,i1,i2,x,alpha,y2); + //--- function call + CSblas::SymmetricMatrixVectorMultiply(la,false,i1,i2,x,alpha,y3); + //--- Calculate error + for(i_=1;i_<=i2-i1+1;i_++) + y2[i_]=y2[i_]-y1[i_]; + v=0.0; + for(i_=1;i_<=i2-i1+1;i_++) + v+=y2[i_]*y2[i_]; + //--- search errors + mverr=MathMax(mverr,MathSqrt(v)); + for(i_=1;i_<=i2-i1+1;i_++) + y3[i_]=y3[i_]-y1[i_]; + v=0.0; + for(i_=1;i_<=i2-i1+1;i_++) + v+=y3[i_]*y3[i_]; + //--- search errors + mverr=MathMax(mverr,MathSqrt(v)); + } + } + } +//--- report + waserrors=mverr>threshold; +//--- check + if(!silent) + { + Print("TESTING SYMMETRIC BLAS"); + Print("MV error: "); + Print("{0,5:E3}",mverr); + Print("Threshold: "); + Print("{0,5:E3}",threshold); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Testing class COrtFac | +//+------------------------------------------------------------------+ +class CTestOrtFacUnit + { +private: + //--- private methods + static double RMatrixDiff(CMatrixDouble &a,CMatrixDouble &b,const int m,const int n); + static void RMatrixMakeACopy(CMatrixDouble &a,const int m,const int n,CMatrixDouble &b); + static void CMatrixMakeACopy(CMatrixComplex &a,const int m,const int n,CMatrixComplex &b); + static void RMatrixFillSparseA(CMatrixDouble &a,const int m,const int n,const double sparcity); + static void CMatrixFillSparseA(CMatrixComplex &a,const int m,const int n,const double sparcity); + static void InternalMatrixMatrixMultiply(CMatrixDouble &a,const int ai1,const int ai2,const int aj1,const int aj2,const bool transa,CMatrixDouble &b,const int bi1,const int bi2,const int bj1,const int bj2,const bool transb,CMatrixDouble &c,const int ci1,const int ci2,const int cj1,const int cj2); + static void TestRQRProblem(CMatrixDouble &a,const int m,const int n,const double threshold,bool &qrerrors); + static void TestCQRProblem(CMatrixComplex &a,const int m,const int n,const double threshold,bool &qrerrors); + static void TestRLQProblem(CMatrixDouble &a,const int m,const int n,const double threshold,bool &lqerrors); + static void TestCLQProblem(CMatrixComplex &a,const int m,const int n,const double threshold,bool &lqerrors); + static void TestRBdProblem(CMatrixDouble &a,const int m,const int n,const double threshold,bool &bderrors); + static void TestRHessProblem(CMatrixDouble &a,const int n,const double threshold,bool &hesserrors); + static void TestRTdProblem(CMatrixDouble &a,const int n,const double threshold,bool &tderrors); + static void TestCTdProblem(CMatrixComplex &a,const int n,const double threshold,bool &tderrors); +public: + //--- constructor, destructor + CTestOrtFacUnit(void); + ~CTestOrtFacUnit(void); + //--- public method + static bool TestOrtFac(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestOrtFacUnit::CTestOrtFacUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestOrtFacUnit::~CTestOrtFacUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Main unittest subroutine | +//+------------------------------------------------------------------+ +static bool CTestOrtFacUnit::TestOrtFac(const bool silent) + { + int maxmn=0; + double threshold=0; + int passcount=0; + int mx=0; + int m=0; + int n=0; + int pass=0; + int i=0; + int j=0; + bool rqrerrors; + bool rlqerrors; + bool cqrerrors; + bool clqerrors; + bool rbderrors; + bool rhesserrors; + bool rtderrors; + bool ctderrors; + bool waserrors; +//--- create matrix + CMatrixDouble ra; + CMatrixComplex ca; +//--- initialization + waserrors=false; + rqrerrors=false; + rlqerrors=false; + cqrerrors=false; + clqerrors=false; + rbderrors=false; + rhesserrors=false; + rtderrors=false; + ctderrors=false; + maxmn=3*CAblas::AblasBlockSize()+1; + passcount=1; + threshold=5*1000*CMath::m_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+CMath::RandomInteger(mx); + m=1+CMath::RandomInteger(mx); + //--- check + if(CMath::RandomReal()>0.5) + n=mx; + else + m=mx; + //--- allocation + ra.Resize(m,n); + ca.Resize(m,n); + //--- change values + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + ra[i].Set(j,0); + ca[i].Set(j,0); + } + } + //--- function calls + TestRQRProblem(ra,m,n,threshold,rqrerrors); + TestRLQProblem(ra,m,n,threshold,rlqerrors); + TestCQRProblem(ca,m,n,threshold,cqrerrors); + TestCLQProblem(ca,m,n,threshold,clqerrors); + TestRBdProblem(ra,m,n,threshold,rbderrors); + //--- change values + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + ra[i].Set(j,2*CMath::RandomReal()-1); + ca[i].SetRe(j,2*CMath::RandomReal()-1); + ca[i].SetIm(j,2*CMath::RandomReal()-1); + } + } + //--- function calls + TestRQRProblem(ra,m,n,threshold,rqrerrors); + TestRLQProblem(ra,m,n,threshold,rlqerrors); + TestCQRProblem(ca,m,n,threshold,cqrerrors); + TestCLQProblem(ca,m,n,threshold,clqerrors); + TestRBdProblem(ra,m,n,threshold,rbderrors); + //--- function calls + RMatrixFillSparseA(ra,m,n,0.95); + CMatrixFillSparseA(ca,m,n,0.95); + //--- function calls + TestRQRProblem(ra,m,n,threshold,rqrerrors); + TestRLQProblem(ra,m,n,threshold,rlqerrors); + TestCQRProblem(ca,m,n,threshold,cqrerrors); + TestCLQProblem(ca,m,n,threshold,clqerrors); + TestRBdProblem(ra,m,n,threshold,rbderrors); + //--- Square factorizations: Hessenberg,tridiagonal + //--- Matrix types: zero,dense,sparse + ra.Resize(mx,mx); + ca.Resize(mx,mx); + //--- change values + for(i=0;i<=mx-1;i++) + { + for(j=0;j<=mx-1;j++) + { + ra[i].Set(j,0); + ca[i].Set(j,0); + } + } + //--- function call + TestRHessProblem(ra,mx,threshold,rhesserrors); + //--- change values + for(i=0;i<=mx-1;i++) + { + for(j=0;j<=mx-1;j++) + { + ra[i].Set(j,2*CMath::RandomReal()-1); + ca[i].SetRe(j,2*CMath::RandomReal()-1); + ca[i].SetIm(j,2*CMath::RandomReal()-1); + } + } + //--- function calls + TestRHessProblem(ra,mx,threshold,rhesserrors); + RMatrixFillSparseA(ra,mx,mx,0.95); + CMatrixFillSparseA(ca,mx,mx,0.95); + TestRHessProblem(ra,mx,threshold,rhesserrors); + //--- Symetric factorizations: tridiagonal + //--- Matrix types: zero,dense,sparse + ra.Resize(mx,mx); + ca.Resize(mx,mx); + //--- change values + for(i=0;i<=mx-1;i++) + { + for(j=0;j<=mx-1;j++) + { + ra[i].Set(j,0); + ca[i].Set(j,0); + } + } + //--- function calls + TestRTdProblem(ra,mx,threshold,rtderrors); + TestCTdProblem(ca,mx,threshold,ctderrors); + //--- change values + for(i=0;i<=mx-1;i++) + { + for(j=i;j<=mx-1;j++) + { + ra[i].Set(j,2*CMath::RandomReal()-1); + ca[i].SetRe(j,2*CMath::RandomReal()-1); + ca[i].SetIm(j,2*CMath::RandomReal()-1); + ra[j].Set(i,ra[i][j]); + ca[j].Set(i,CMath::Conj(ca[i][j])); + } + } + for(i=0;i<=mx-1;i++) + ca[i].Set(i,2*CMath::RandomReal()-1); + //--- function calls + TestRTdProblem(ra,mx,threshold,rtderrors); + TestCTdProblem(ca,mx,threshold,ctderrors); + RMatrixFillSparseA(ra,mx,mx,0.95); + CMatrixFillSparseA(ca,mx,mx,0.95); + //--- change values + for(i=0;i<=mx-1;i++) + { + for(j=i;j<=mx-1;j++) + { + ra[j].Set(i,ra[i][j]); + ca[j].Set(i,CMath::Conj(ca[i][j])); + } + } + for(i=0;i<=mx-1;i++) + ca[i].Set(i,2*CMath::RandomReal()-1); + //--- function calls + TestRTdProblem(ra,mx,threshold,rtderrors); + TestCTdProblem(ca,mx,threshold,ctderrors); + } + } +//--- report + waserrors=((((((rqrerrors || rlqerrors) || cqrerrors) || clqerrors) || rbderrors) || rhesserrors) || rtderrors) || ctderrors; +//--- check + if(!silent) + { + Print("TESTING ORTFAC UNIT"); + Print("RQR ERRORS: "); + //--- check + if(!rqrerrors) + Print("OK"); + else + Print("FAILED"); + Print("RLQ ERRORS: "); + //--- check + if(!rlqerrors) + Print("OK"); + else + Print("FAILED"); + Print("CQR ERRORS: "); + //--- check + if(!cqrerrors) + Print("OK"); + else + Print("FAILED"); + Print("CLQ ERRORS: "); + //--- check + if(!clqerrors) + Print("OK"); + else + Print("FAILED"); + Print("RBD ERRORS: "); + //--- check + if(!rbderrors) + Print("OK"); + else + Print("FAILED"); + Print("RHESS ERRORS: "); + //--- check + if(!rhesserrors) + Print("OK"); + else + Print("FAILED"); + Print("RTD ERRORS: "); + //--- check + if(!rtderrors) + Print("OK"); + else + Print("FAILED"); + Print("CTD ERRORS: "); + //--- check + if(!ctderrors) + Print("OK"); + else + Print("FAILED"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Diff | +//+------------------------------------------------------------------+ +static double CTestOrtFacUnit::RMatrixDiff(CMatrixDouble &a,CMatrixDouble &b, + const int m,const int n) + { +//--- create variables + double result=0; + int i=0; + int j=0; +//--- calculation + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + result=MathMax(result,MathAbs(b[i][j]-a[i][j])); + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Copy | +//+------------------------------------------------------------------+ +static void CTestOrtFacUnit::RMatrixMakeACopy(CMatrixDouble &a,const int m, + const int n,CMatrixDouble &b) + { +//--- create variables + int i=0; + int j=0; +//--- allocation + b.Resize(m,n); +//--- copy + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + b[i].Set(j,a[i][j]); + } + } +//+------------------------------------------------------------------+ +//| Copy | +//+------------------------------------------------------------------+ +static void CTestOrtFacUnit::CMatrixMakeACopy(CMatrixComplex &a,const int m, + const int n,CMatrixComplex &b) + { +//--- create variables + int i=0; + int j=0; +//--- allocation + b.Resize(m,n); +//--- copy + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + b[i].Set(j,a[i][j]); + } + } +//+------------------------------------------------------------------+ +//| Sparse fill | +//+------------------------------------------------------------------+ +static void CTestOrtFacUnit::RMatrixFillSparseA(CMatrixDouble &a,const int m, + const int n,const double sparcity) + { +//--- create variables + int i=0; + int j=0; +//--- calculation + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(CMath::RandomReal()>=sparcity) + a[i].Set(j,2*CMath::RandomReal()-1); + else + a[i].Set(j,0); + } + } + } +//+------------------------------------------------------------------+ +//| Sparse fill | +//+------------------------------------------------------------------+ +static void CTestOrtFacUnit::CMatrixFillSparseA(CMatrixComplex &a,const int m, + const int n,const double sparcity) + { +//--- create variables + int i=0; + int j=0; +//--- calculation + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(CMath::RandomReal()>=sparcity) + { + a[i].SetRe(j,2*CMath::RandomReal()-1); + a[i].SetIm(j,2*CMath::RandomReal()-1); + } + else + a[i].Set(j,0); + } + } + } +//+------------------------------------------------------------------+ +//| Matrix multiplication | +//+------------------------------------------------------------------+ +static void CTestOrtFacUnit::InternalMatrixMatrixMultiply(CMatrixDouble &a, + const int ai1, + const int ai2, + const int aj1, + const int aj2, + const bool transa, + CMatrixDouble &b, + const int bi1, + const int bi2, + const int bj1, + const int bj2, + const bool transb, + CMatrixDouble &c, + const int ci1, + const int ci2, + const int cj1, + const int cj2) + { +//--- create variables + int arows=0; + int acols=0; + int brows=0; + int bcols=0; + int crows=0; + int ccols=0; + int i=0; + int j=0; + int k=0; + int l=0; + int r=0; + double v=0; + double beta=0; + double alpha=0; + int i_=0; + int i1_=0; +//--- create array + double work[]; +//--- Pre-setup + k=MathMax(ai2-ai1+1,aj2-aj1+1); + k=MathMax(k,bi2-bi1+1); + k=MathMax(k,bj2-bj1+1); +//--- allocation + ArrayResize(work,k+1); +//--- initialization + beta=0; + alpha=1; +//--- Setup + if(!transa) + { + arows=ai2-ai1+1; + acols=aj2-aj1+1; + } + else + { + arows=aj2-aj1+1; + acols=ai2-ai1+1; + } +//--- check + if(!transb) + { + brows=bi2-bi1+1; + bcols=bj2-bj1+1; + } + else + { + brows=bj2-bj1+1; + bcols=bi2-bi1+1; + } +//--- check + if(!CAp::Assert(acols==brows,"MatrixMatrixMultiply: incorrect matrix sizes!")) + return; +//--- check + if(((arows<=0 || acols<=0) || brows<=0) || bcols<=0) + return; +//--- change values + crows=arows; + ccols=bcols; +//--- Test WORK + i=MathMax(arows,acols); + i=MathMax(brows,i); + i=MathMax(i,bcols); + work[1]=0; + work[i]=0; +//--- Prepare C + if(beta==0.0) + { + for(i=ci1;i<=ci2;i++) + { + for(j=cj1;j<=cj2;j++) + c[i].Set(j,0); + } + } + else + { + for(i=ci1;i<=ci2;i++) + { + for(i_=cj1;i_<=cj2;i_++) + c[i].Set(i_,beta*c[i][i_]); + } + } +//--- A*B + if(!transa && !transb) + { + for(l=ai1;l<=ai2;l++) + { + for(r=bi1;r<=bi2;r++) + { + //--- change values + v=alpha*a[l][aj1+r-bi1]; + k=ci1+l-ai1; + i1_=bj1-cj1; + //--- calculation + for(i_=cj1;i_<=cj2;i_++) + c[k].Set(i_,c[k][i_]+v*b[r][i_+i1_]); + } + } + return; + } +//--- A*B' + if(!transa && transb) + { + //--- check + if(arows*acolsthreshold; + } + } +//--- search errors + for(i=0;i<=m-1;i++) + { + for(j=0;j<=MathMin(i,n-1)-1;j++) + qrerrors=qrerrors || r[i][j]!=0.0; + } + for(i=0;i<=m-1;i++) + { + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=m-1;i_++) + v+=q[i][i_]*q[j][i_]; + //--- check + if(i==j) + v=v-1; + qrerrors=qrerrors || MathAbs(v)>=threshold; + } + } +//--- Test for other errors + k=1+CMath::RandomInteger(m); +//--- function call + COrtFac::RMatrixQRUnpackQ(b,m,n,taub,k,q2); +//--- search errors + for(i=0;i<=m-1;i++) + { + for(j=0;j<=k-1;j++) + qrerrors=qrerrors || MathAbs(q2[i][j]-q[i][j])>10*CMath::m_machineepsilon; + } + } +//+------------------------------------------------------------------+ +//| Problem testing | +//+------------------------------------------------------------------+ +static void CTestOrtFacUnit::TestCQRProblem(CMatrixComplex &a,const int m, + const int n,const double threshold, + bool &qrerrors) + { +//--- create variables + int i=0; + int j=0; + int k=0; + complex v=0; + int i_=0; +//--- create array + complex taub[]; +//--- create matrix + CMatrixComplex b; + CMatrixComplex q; + CMatrixComplex r; + CMatrixComplex q2; +//--- Test decompose-and-unpack error + CMatrixMakeACopy(a,m,n,b); +//--- function calls + COrtFac::CMatrixQR(b,m,n,taub); + COrtFac::CMatrixQRUnpackQ(b,m,n,taub,m,q); + COrtFac::CMatrixQRUnpackR(b,m,n,r); +//--- search errors + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=m-1;i_++) + v+=q[i][i_]*r[i_][j]; + qrerrors=qrerrors || CMath::AbsComplex(v-a[i][j])>threshold; + } + } +//--- search errors + for(i=0;i<=m-1;i++) + { + for(j=0;j<=MathMin(i,n-1)-1;j++) + qrerrors=qrerrors || r[i][j]!=0; + } + for(i=0;i<=m-1;i++) + { + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=m-1;i_++) + v+=q[i][i_]*CMath::Conj(q[j][i_]); + //--- check + if(i==j) + v=v-1; + qrerrors=qrerrors || CMath::AbsComplex(v)>=threshold; + } + } +//--- Test for other errors + k=1+CMath::RandomInteger(m); +//--- function call + COrtFac::CMatrixQRUnpackQ(b,m,n,taub,k,q2); +//--- search errors + for(i=0;i<=m-1;i++) + { + for(j=0;j<=k-1;j++) + qrerrors=qrerrors || CMath::AbsComplex(q2[i][j]-q[i][j])>10*CMath::m_machineepsilon; + } + } +//+------------------------------------------------------------------+ +//| Problem testing | +//+------------------------------------------------------------------+ +static void CTestOrtFacUnit::TestRLQProblem(CMatrixDouble &a,const int m, + const int n,const double threshold, + bool &lqerrors) + { +//--- create variables + int i=0; + int j=0; + int k=0; + double v=0; + int i_=0; +//--- create array + double taub[]; +//--- create matrix + CMatrixDouble b; + CMatrixDouble q; + CMatrixDouble l; + CMatrixDouble q2; +//--- Test decompose-and-unpack error + RMatrixMakeACopy(a,m,n,b); +//--- function calls + COrtFac::RMatrixLQ(b,m,n,taub); + COrtFac::RMatrixLQUnpackQ(b,m,n,taub,n,q); + COrtFac::RMatrixLQUnpackL(b,m,n,l); +//--- search errors + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=l[i][i_]*q[i_][j]; + lqerrors=lqerrors || MathAbs(v-a[i][j])>=threshold; + } + } +//--- search errors + for(i=0;i<=m-1;i++) + { + for(j=MathMin(i,n-1)+1;j<=n-1;j++) + lqerrors=lqerrors || l[i][j]!=0.0; + } + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=q[i][i_]*q[j][i_]; + //--- check + if(i==j) + v=v-1; + lqerrors=lqerrors || MathAbs(v)>=threshold; + } + } +//--- Test for other errors + k=1+CMath::RandomInteger(n); +//--- function call + COrtFac::RMatrixLQUnpackQ(b,m,n,taub,k,q2); +//--- search errors + for(i=0;i<=k-1;i++) + { + for(j=0;j<=n-1;j++) + lqerrors=lqerrors || MathAbs(q2[i][j]-q[i][j])>10*CMath::m_machineepsilon; + } + } +//+------------------------------------------------------------------+ +//| Problem testing | +//+------------------------------------------------------------------+ +static void CTestOrtFacUnit::TestCLQProblem(CMatrixComplex &a,const int m, + const int n,const double threshold, + bool &lqerrors) + { +//--- create variables + int i=0; + int j=0; + int k=0; + complex v=0; + int i_=0; +//--- create array + complex taub[]; +//--- create matrix + CMatrixComplex b; + CMatrixComplex q; + CMatrixComplex l; + CMatrixComplex q2; +//--- Test decompose-and-unpack error + CMatrixMakeACopy(a,m,n,b); +//--- function calls + COrtFac::CMatrixLQ(b,m,n,taub); + COrtFac::CMatrixLQUnpackQ(b,m,n,taub,n,q); + COrtFac::CMatrixLQUnpackL(b,m,n,l); +//--- search errors + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=l[i][i_]*q[i_][j]; + lqerrors=lqerrors || CMath::AbsComplex(v-a[i][j])>=threshold; + } + } +//--- search errors + for(i=0;i<=m-1;i++) + { + for(j=MathMin(i,n-1)+1;j<=n-1;j++) + lqerrors=lqerrors || l[i][j]!=0; + } + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=q[i][i_]*CMath::Conj(q[j][i_]); + //--- check + if(i==j) + v=v-1; + lqerrors=lqerrors || CMath::AbsComplex(v)>=threshold; + } + } +//--- Test for other errors + k=1+CMath::RandomInteger(n); +//--- function call + COrtFac::CMatrixLQUnpackQ(b,m,n,taub,k,q2); +//--- search errors + for(i=0;i<=k-1;i++) + { + for(j=0;j<=n-1;j++) + lqerrors=lqerrors || CMath::AbsComplex(q2[i][j]-q[i][j])>10*CMath::m_machineepsilon; + } + } +//+------------------------------------------------------------------+ +//| Problem testing | +//+------------------------------------------------------------------+ +static void CTestOrtFacUnit::TestRBdProblem(CMatrixDouble &a,const int m, + const int n,const double threshold, + bool &bderrors) + { +//--- create variables + int i=0; + int j=0; + int k=0; + bool up; + double v=0; + int mtsize=0; + int i_=0; +//--- create arrays + double taup[]; + double tauq[]; + double d[]; + double e[]; +//--- create matrix + CMatrixDouble t; + CMatrixDouble pt; + CMatrixDouble q; + CMatrixDouble r; + CMatrixDouble bd; + CMatrixDouble x; + CMatrixDouble r1; + CMatrixDouble r2; +//--- Bidiagonal decomposition error + RMatrixMakeACopy(a,m,n,t); +//--- function calls + COrtFac::RMatrixBD(t,m,n,tauq,taup); + COrtFac::RMatrixBDUnpackQ(t,m,n,tauq,m,q); + COrtFac::RMatrixBDUnpackPT(t,m,n,taup,n,pt); + COrtFac::RMatrixBDUnpackDiagonals(t,m,n,up,d,e); +//--- allocation + bd.Resize(m,n); +//--- change values + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + bd[i].Set(j,0); + } + for(i=0;i<=MathMin(m,n)-1;i++) + bd[i].Set(i,d[i]); +//--- check + if(up) + { + for(i=0;i<=MathMin(m,n)-2;i++) + bd[i].Set(i+1,e[i]); + } + else + { + for(i=0;i<=MathMin(m,n)-2;i++) + bd[i+1].Set(i,e[i]); + } +//--- allocation + r.Resize(m,n); +//--- calculation + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + v=0.0; + for(i_=0;i_<=m-1;i_++) + v+=q[i][i_]*bd[i_][j]; + r[i].Set(j,v); + } + } +//--- search errors + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=r[i][i_]*pt[i_][j]; + bderrors=bderrors || MathAbs(v-a[i][j])>threshold; + } + } +//--- Orthogonality test for Q/PT + for(i=0;i<=m-1;i++) + { + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=m-1;i_++) + v+=q[i_][i]*q[i_][j]; + //--- check + if(i==j) + bderrors=bderrors || MathAbs(v-1)>threshold; + else + bderrors=bderrors || MathAbs(v)>threshold; + } + } +//--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=pt[i][i_]*pt[j][i_]; + //--- check + if(i==j) + bderrors=bderrors || MathAbs(v-1)>threshold; + else + bderrors=bderrors || MathAbs(v)>threshold; + } + } +//--- Partial unpacking test + k=1+CMath::RandomInteger(m); +//--- function call + COrtFac::RMatrixBDUnpackQ(t,m,n,tauq,k,r); +//--- search errors + for(i=0;i<=m-1;i++) + { + for(j=0;j<=k-1;j++) + bderrors=bderrors || MathAbs(r[i][j]-q[i][j])>10*CMath::m_machineepsilon; + } + k=1+CMath::RandomInteger(n); +//--- function call + COrtFac::RMatrixBDUnpackPT(t,m,n,taup,k,r); +//--- search errors + for(i=0;i<=k-1;i++) + { + for(j=0;j<=n-1;j++) + bderrors=bderrors || r[i][j]-pt[i][j]!=0.0; + } +//--- Multiplication test + x.Resize(MathMax(m,n),MathMax(m,n)); + r.Resize(MathMax(m,n),MathMax(m,n)); + r1.Resize(MathMax(m,n),MathMax(m,n)); + r2.Resize(MathMax(m,n),MathMax(m,n)); +//--- change values + for(i=0;i<=MathMax(m,n)-1;i++) + { + for(j=0;j<=MathMax(m,n)-1;j++) + x[i].Set(j,2*CMath::RandomReal()-1); + } + mtsize=1+CMath::RandomInteger(MathMax(m,n)); +//--- function calls + RMatrixMakeACopy(x,mtsize,m,r); + InternalMatrixMatrixMultiply(r,0,mtsize-1,0,m-1,false,q,0,m-1,0,m-1,false,r1,0,mtsize-1,0,m-1); + RMatrixMakeACopy(x,mtsize,m,r2); + COrtFac::RMatrixBDMultiplyByQ(t,m,n,tauq,r2,mtsize,m,true,false); +//--- search errors + bderrors=bderrors || RMatrixDiff(r1,r2,mtsize,m)>threshold; +//--- function calls + RMatrixMakeACopy(x,mtsize,m,r); + InternalMatrixMatrixMultiply(r,0,mtsize-1,0,m-1,false,q,0,m-1,0,m-1,true,r1,0,mtsize-1,0,m-1); + RMatrixMakeACopy(x,mtsize,m,r2); + COrtFac::RMatrixBDMultiplyByQ(t,m,n,tauq,r2,mtsize,m,true,true); +//--- search errors + bderrors=bderrors || RMatrixDiff(r1,r2,mtsize,m)>threshold; +//--- function calls + RMatrixMakeACopy(x,m,mtsize,r); + InternalMatrixMatrixMultiply(q,0,m-1,0,m-1,false,r,0,m-1,0,mtsize-1,false,r1,0,m-1,0,mtsize-1); + RMatrixMakeACopy(x,m,mtsize,r2); + COrtFac::RMatrixBDMultiplyByQ(t,m,n,tauq,r2,m,mtsize,false,false); +//--- search errors + bderrors=bderrors || RMatrixDiff(r1,r2,m,mtsize)>threshold; +//--- function calls + RMatrixMakeACopy(x,m,mtsize,r); + InternalMatrixMatrixMultiply(q,0,m-1,0,m-1,true,r,0,m-1,0,mtsize-1,false,r1,0,m-1,0,mtsize-1); + RMatrixMakeACopy(x,m,mtsize,r2); + COrtFac::RMatrixBDMultiplyByQ(t,m,n,tauq,r2,m,mtsize,false,true); +//--- search errors + bderrors=bderrors || RMatrixDiff(r1,r2,m,mtsize)>threshold; +//--- function calls + RMatrixMakeACopy(x,mtsize,n,r); + InternalMatrixMatrixMultiply(r,0,mtsize-1,0,n-1,false,pt,0,n-1,0,n-1,true,r1,0,mtsize-1,0,n-1); + RMatrixMakeACopy(x,mtsize,n,r2); + COrtFac::RMatrixBDMultiplyByP(t,m,n,taup,r2,mtsize,n,true,false); +//--- search errors + bderrors=bderrors || RMatrixDiff(r1,r2,mtsize,n)>threshold; +//--- function calls + RMatrixMakeACopy(x,mtsize,n,r); + InternalMatrixMatrixMultiply(r,0,mtsize-1,0,n-1,false,pt,0,n-1,0,n-1,false,r1,0,mtsize-1,0,n-1); + RMatrixMakeACopy(x,mtsize,n,r2); + COrtFac::RMatrixBDMultiplyByP(t,m,n,taup,r2,mtsize,n,true,true); +//--- search errors + bderrors=bderrors || RMatrixDiff(r1,r2,mtsize,n)>threshold; +//--- function calls + RMatrixMakeACopy(x,n,mtsize,r); + InternalMatrixMatrixMultiply(pt,0,n-1,0,n-1,true,r,0,n-1,0,mtsize-1,false,r1,0,n-1,0,mtsize-1); + RMatrixMakeACopy(x,n,mtsize,r2); + COrtFac::RMatrixBDMultiplyByP(t,m,n,taup,r2,n,mtsize,false,false); +//--- search errors + bderrors=bderrors || RMatrixDiff(r1,r2,n,mtsize)>threshold; +//--- function calls + RMatrixMakeACopy(x,n,mtsize,r); + InternalMatrixMatrixMultiply(pt,0,n-1,0,n-1,false,r,0,n-1,0,mtsize-1,false,r1,0,n-1,0,mtsize-1); + RMatrixMakeACopy(x,n,mtsize,r2); + COrtFac::RMatrixBDMultiplyByP(t,m,n,taup,r2,n,mtsize,false,true); +//--- search errors + bderrors=bderrors || RMatrixDiff(r1,r2,n,mtsize)>threshold; + } +//+------------------------------------------------------------------+ +//| Problem testing | +//+------------------------------------------------------------------+ +static void CTestOrtFacUnit::TestRHessProblem(CMatrixDouble &a,const int n, + const double threshold,bool &hesserrors) + { +//--- create variables + int i=0; + int j=0; + double v=0; + int i_=0; +//--- create array + double tau[]; +//--- create matrix + CMatrixDouble b; + CMatrixDouble h; + CMatrixDouble q; + CMatrixDouble t1; + CMatrixDouble t2; +//--- function call + RMatrixMakeACopy(a,n,n,b); +//--- Decomposition + COrtFac::RMatrixHessenberg(b,n,tau); + COrtFac::RMatrixHessenbergUnpackQ(b,n,tau,q); + COrtFac::RMatrixHessenbergUnpackH(b,n,h); +//--- Matrix properties + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=q[i_][i]*q[i_][j]; + //--- check + if(i==j) + v=v-1; + hesserrors=hesserrors || MathAbs(v)>threshold; + } + } +//--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=i-2;j++) + hesserrors=hesserrors || h[i][j]!=0.0; + } +//--- Decomposition error + t1.Resize(n,n); + t2.Resize(n,n); +//--- function calls + InternalMatrixMatrixMultiply(q,0,n-1,0,n-1,false,h,0,n-1,0,n-1,false,t1,0,n-1,0,n-1); + InternalMatrixMatrixMultiply(t1,0,n-1,0,n-1,false,q,0,n-1,0,n-1,true,t2,0,n-1,0,n-1); +//--- search errors + hesserrors=hesserrors || RMatrixDiff(t2,a,n,n)>threshold; + } +//+------------------------------------------------------------------+ +//| Tridiagonal tester | +//+------------------------------------------------------------------+ +static void CTestOrtFacUnit::TestRTdProblem(CMatrixDouble &a,const int n, + const double threshold,bool &tderrors) + { +//--- create variables + int i=0; + int j=0; + double v=0; + int i_=0; +//--- create arrays + double tau[]; + double d[]; + double e[]; +//--- create matrix + CMatrixDouble ua; + CMatrixDouble la; + CMatrixDouble t; + CMatrixDouble q; + CMatrixDouble t2; + CMatrixDouble t3; +//--- allocation + ua.Resize(n,n); + la.Resize(n,n); + t.Resize(n,n); + q.Resize(n,n); + t2.Resize(n,n); + t3.Resize(n,n); +//--- fill + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + ua[i].Set(j,0); + } +//--- change values + for(i=0;i<=n-1;i++) + { + for(j=i;j<=n-1;j++) + ua[i].Set(j,a[i][j]); + } +//--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + la[i].Set(j,0); + } +//--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=i;j++) + la[i].Set(j,a[i][j]); + } +//--- Test 2tridiagonal: upper + COrtFac::SMatrixTD(ua,n,true,tau,d,e); + COrtFac::SMatrixTDUnpackQ(ua,n,true,tau,q); +//--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + t[i].Set(j,0); + } + for(i=0;i<=n-1;i++) + t[i].Set(i,d[i]); + for(i=0;i<=n-2;i++) + { + t[i].Set(i+1,e[i]); + t[i+1].Set(i,e[i]); + } +//--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=q[i_][i]*a[i_][j]; + t2[i].Set(j,v); + } + } +//--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=t2[i][i_]*q[i_][j]; + t3[i].Set(j,v); + } + } +//--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + tderrors=tderrors || MathAbs(t3[i][j]-t[i][j])>threshold; + } +//--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=q[i][i_]*q[j][i_]; + //--- check + if(i==j) + v=v-1; + tderrors=tderrors || MathAbs(v)>threshold; + } + } +//--- Test 2tridiagonal: lower + COrtFac::SMatrixTD(la,n,false,tau,d,e); + COrtFac::SMatrixTDUnpackQ(la,n,false,tau,q); +//--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + t[i].Set(j,0); + } + for(i=0;i<=n-1;i++) + t[i].Set(i,d[i]); + for(i=0;i<=n-2;i++) + { + t[i].Set(i+1,e[i]); + t[i+1].Set(i,e[i]); + } +//--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=q[i_][i]*a[i_][j]; + t2[i].Set(j,v); + } + } +//--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=t2[i][i_]*q[i_][j]; + t3[i].Set(j,v); + } + } +//--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + tderrors=tderrors || MathAbs(t3[i][j]-t[i][j])>threshold; + } +//--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=q[i][i_]*q[j][i_]; + //--- check + if(i==j) + v=v-1; + tderrors=tderrors || MathAbs(v)>threshold; + } + } + } +//+------------------------------------------------------------------+ +//| Hermitian problem tester | +//+------------------------------------------------------------------+ +static void CTestOrtFacUnit::TestCTdProblem(CMatrixComplex &a,const int n, + const double threshold,bool &tderrors) + { +//--- create variables + int i=0; + int j=0; + complex v=0; + int i_=0; +//--- create arrays + complex tau[]; + double d[]; + double e[]; +//--- create matrix + CMatrixComplex ua; + CMatrixComplex la; + CMatrixComplex t; + CMatrixComplex q; + CMatrixComplex t2; + CMatrixComplex t3; +//--- allocation + ua.Resize(n,n); + la.Resize(n,n); + t.Resize(n,n); + q.Resize(n,n); + t2.Resize(n,n); + t3.Resize(n,n); +//--- fill + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + ua[i].Set(j,0); + } +//--- change values + for(i=0;i<=n-1;i++) + { + for(j=i;j<=n-1;j++) + ua[i].Set(j,a[i][j]); + } +//--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + la[i].Set(j,0); + } +//--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=i;j++) + la[i].Set(j,a[i][j]); + } +//--- Test 2tridiagonal: upper + COrtFac::HMatrixTD(ua,n,true,tau,d,e); + COrtFac::HMatrixTDUnpackQ(ua,n,true,tau,q); +//--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + t[i].Set(j,0); + } + for(i=0;i<=n-1;i++) + t[i].Set(i,d[i]); + for(i=0;i<=n-2;i++) + { + t[i].Set(i+1,e[i]); + t[i+1].Set(i,e[i]); + } +//--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=CMath::Conj(q[i_][i])*a[i_][j]; + t2[i].Set(j,v); + } + } +//--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=t2[i][i_]*q[i_][j]; + t3[i].Set(j,v); + } + } +//--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + tderrors=tderrors || CMath::AbsComplex(t3[i][j]-t[i][j])>threshold; + } +//--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=q[i][i_]*CMath::Conj(q[j][i_]); + //--- check + if(i==j) + v=v-1; + tderrors=tderrors || CMath::AbsComplex(v)>threshold; + } + } +//--- Test 2tridiagonal: lower + COrtFac::HMatrixTD(la,n,false,tau,d,e); + COrtFac::HMatrixTDUnpackQ(la,n,false,tau,q); +//--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + t[i].Set(j,0); + } + for(i=0;i<=n-1;i++) + t[i].Set(i,d[i]); + for(i=0;i<=n-2;i++) + { + t[i].Set(i+1,e[i]); + t[i+1].Set(i,e[i]); + } +//--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=CMath::Conj(q[i_][i])*a[i_][j]; + t2[i].Set(j,v); + } + } +//--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=t2[i][i_]*q[i_][j]; + t3[i].Set(j,v); + } + } +//--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + tderrors=tderrors || CMath::AbsComplex(t3[i][j]-t[i][j])>threshold; + } +//--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=q[i][i_]*CMath::Conj(q[j][i_]); + //--- check + if(i==j) + v=v-1; + tderrors=tderrors || CMath::AbsComplex(v)>threshold; + } + } + } +//+------------------------------------------------------------------+ +//| Testing class CEigenVDetect | +//+------------------------------------------------------------------+ +class CTestEVDUnit + { +private: + //--- private methods + static void RMatrixFillSparseA(CMatrixDouble &a,const int m,const int n,const double sparcity); + static void CMatrixFillSparseA(CMatrixComplex &a,const int m,const int n,const double sparcity); + static void RMatrixSymmetricSplit(CMatrixDouble &a,const int n,CMatrixDouble &al,CMatrixDouble &au); + static void CMatrixHermitianSplit(CMatrixComplex &a,const int n,CMatrixComplex &al,CMatrixComplex &au); + static void Unset2D(CMatrixDouble &a); + static void CUnset2D(CMatrixComplex &a); + static void Unset1D(double &a[]); + static void CUnset1D(complex &a[]); + static double TdTestProduct(double &d[],double &e[],const int n,CMatrixDouble &z,double &lambdav[]); + static double TestProduct(CMatrixDouble &a,const int n,CMatrixDouble &z,double &lambdav[]); + static double TestOrt(CMatrixDouble &z,const int n); + static double TestCProduct(CMatrixComplex &a,const int n,CMatrixComplex &z,double &lambdav[]); + static double TestCOrt(CMatrixComplex &z,const int n); + static void TestSEVDProblem(CMatrixDouble &a,CMatrixDouble &al,CMatrixDouble &au,const int n,const double threshold,bool &serrors,int &failc,int &runs); + static void TestHEVDProblem(CMatrixComplex &a,CMatrixComplex &al,CMatrixComplex &au,const int n,const double threshold,bool &herrors,int &failc,int &runs); + static void TestSEVDBiProblem(CMatrixDouble &afull,CMatrixDouble &al,CMatrixDouble &au,const int n,const bool distvals,const double threshold,bool &serrors,int &failc,int &runs); + static void TestHEVDBiProblem(CMatrixComplex &afull,CMatrixComplex &al,CMatrixComplex &au,const int n,const bool distvals,const double threshold,bool &herrors,int &failc,int &runs); + static void TestTdEVDProblem(double &d[],double &e[],const int n,const double threshold,bool &tderrors,int &failc,int &runs); + static void TestTdEVDBiProblem(double &d[],double &e[],const int n,const bool distvals,const double threshold,bool &serrors,int &failc,int &runs); + static void TestNSEVDProblem(CMatrixDouble &a,const int n,const double threshold,bool &nserrors,int &failc,int &runs); + static void TestEVDSet(const int n,const double threshold,double bithreshold,int &failc,int &runs,bool &nserrors,bool &serrors,bool &herrors,bool &tderrors,bool &sbierrors,bool &hbierrors,bool &tdbierrors); +public: + //--- constructor, destructor + CTestEVDUnit(void); + ~CTestEVDUnit(void); + //--- public method + static bool TestEVD(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestEVDUnit::CTestEVDUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestEVDUnit::~CTestEVDUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing symmetric EVD subroutine | +//+------------------------------------------------------------------+ +static bool CTestEVDUnit::TestEVD(const bool silent) + { +//--- create variables + int n=0; + int j=0; + int failc=0; + int runs=0; + double failthreshold=0; + double threshold=0; + double bithreshold=0; + bool waserrors; + bool nserrors; + bool serrors; + bool herrors; + bool tderrors; + bool sbierrors; + bool hbierrors; + bool tdbierrors; + bool wfailed; +//--- create matrix + CMatrixDouble ra; +//--- initialization + failthreshold=0.005; + threshold=100000*CMath::m_machineepsilon; + bithreshold=1.0E-6; + nserrors=false; + serrors=false; + herrors=false; + tderrors=false; + sbierrors=false; + hbierrors=false; + tdbierrors=false; + failc=0; + runs=0; +//--- Test problems + for(n=1;n<=CAblas::AblasBlockSize();n++) + TestEVDSet(n,threshold,bithreshold,failc,runs,nserrors,serrors,herrors,tderrors,sbierrors,hbierrors,tdbierrors); + for(j=2;j<=3;j++) + { + for(n=j*CAblas::AblasBlockSize()-1;n<=j*CAblas::AblasBlockSize()+1;n++) + TestEVDSet(n,threshold,bithreshold,failc,runs,nserrors,serrors,herrors,tderrors,sbierrors,hbierrors,tdbierrors); + } +//--- report + wfailed=(double)failc/(double)runs>failthreshold; + waserrors=((((((nserrors || serrors) || herrors) || tderrors) || sbierrors) || hbierrors) || tdbierrors) || wfailed; +//--- check + if(!silent) + { + Print("TESTING EVD UNIT"); + Print("NS ERRORS: "); + //--- check + if(!nserrors) + Print("OK"); + else + Print("FAILED"); + Print("S ERRORS: "); + //--- check + if(!serrors) + Print("OK"); + else + Print("FAILED"); + Print("H ERRORS: "); + //--- check + if(!herrors) + Print("OK"); + else + Print("FAILED"); + Print("TD ERRORS: "); + //--- check + if(!tderrors) + Print("OK"); + else + Print("FAILED"); + Print("SBI ERRORS: "); + //--- check + if(!sbierrors) + Print("OK"); + else + Print("FAILED"); + Print("HBI ERRORS: "); + //--- check + if(!hbierrors) + Print("OK"); + else + Print("FAILED"); + Print("TDBI ERRORS: "); + //--- check + if(!tdbierrors) + Print("OK"); + else + Print("FAILED"); + Print("FAILURE THRESHOLD: "); + //--- check + if(!wfailed) + Print("OK"); + else + Print("FAILED"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Sparse fill | +//+------------------------------------------------------------------+ +static void CTestEVDUnit::RMatrixFillSparseA(CMatrixDouble &a,const int m, + const int n,const double sparcity) + { +//--- create variables + int i=0; + int j=0; +//--- change values + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(CMath::RandomReal()>=sparcity) + a[i].Set(j,2*CMath::RandomReal()-1); + else + a[i].Set(j,0); + } + } + } +//+------------------------------------------------------------------+ +//| Sparse fill | +//+------------------------------------------------------------------+ +static void CTestEVDUnit::CMatrixFillSparseA(CMatrixComplex &a,const int m, + const int n,const double sparcity) + { +//--- create variables + int i=0; + int j=0; +//--- change values + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(CMath::RandomReal()>=sparcity) + { + a[i].SetRe(j,2*CMath::RandomReal()-1); + a[i].SetIm(j,2*CMath::RandomReal()-1); + } + else + a[i].Set(j,0); + } + } + } +//+------------------------------------------------------------------+ +//| Copies A to AL (lower half) and AU (upper half),filling unused | +//| parts by random garbage. | +//+------------------------------------------------------------------+ +static void CTestEVDUnit::RMatrixSymmetricSplit(CMatrixDouble &a,const int n, + CMatrixDouble &al,CMatrixDouble &au) + { +//--- create variables + int i=0; + int j=0; +//--- change values + for(i=0;i<=n-1;i++) + { + for(j=i+1;j<=n-1;j++) + { + al[i].Set(j,2*CMath::RandomReal()-1); + al[j].Set(i,a[i][j]); + au[i].Set(j,a[i][j]); + au[j].Set(i,2*CMath::RandomReal()-1); + } + al[i].Set(i,a[i][i]); + au[i].Set(i,a[i][i]); + } + } +//+------------------------------------------------------------------+ +//| Copies A to AL (lower half) and AU (upper half),filling unused | +//| parts by random garbage. | +//+------------------------------------------------------------------+ +static void CTestEVDUnit::CMatrixHermitianSplit(CMatrixComplex &a,const int n, + CMatrixComplex &al,CMatrixComplex &au) + { +//--- create variables + int i=0; + int j=0; +//--- change values + for(i=0;i<=n-1;i++) + { + for(j=i+1;j<=n-1;j++) + { + al[i].Set(j,2*CMath::RandomReal()-1); + al[j].Set(i,CMath::Conj(a[i][j])); + au[i].Set(j,a[i][j]); + au[j].Set(i,2*CMath::RandomReal()-1); + } + al[i].Set(i,a[i][i]); + au[i].Set(i,a[i][i]); + } + } +//+------------------------------------------------------------------+ +//| Unsets 2D array. | +//+------------------------------------------------------------------+ +static void CTestEVDUnit::Unset2D(CMatrixDouble &a) + { +//--- allocation + a.Resize(1,1); +//--- change value + a[0].Set(0,2*CMath::RandomReal()-1); + } +//+------------------------------------------------------------------+ +//| Unsets 2D array. | +//+------------------------------------------------------------------+ +static void CTestEVDUnit::CUnset2D(CMatrixComplex &a) + { +//--- allocation + a.Resize(1,1); +//--- change value + a[0].Set(0,2*CMath::RandomReal()-1); + } +//+------------------------------------------------------------------+ +//| Unsets 1D array. | +//+------------------------------------------------------------------+ +static void CTestEVDUnit::Unset1D(double &a[]) + { +//--- allocation + ArrayResize(a,1); +//--- change value + a[0]=2*CMath::RandomReal()-1; + } +//+------------------------------------------------------------------+ +//| Unsets 1D array. | +//+------------------------------------------------------------------+ +static void CTestEVDUnit::CUnset1D(complex &a[]) + { +//--- allocation + ArrayResize(a,1); +//--- change value + a[0]=2*CMath::RandomReal()-1; + } +//+------------------------------------------------------------------+ +//| Tests Z*Lambda*Z' against tridiag(D,E). | +//| Returns relative error. | +//+------------------------------------------------------------------+ +static double CTestEVDUnit::TdTestProduct(double &d[],double &e[],const int n, + CMatrixDouble &z,double &lambdav[]) + { +//--- create variables + double result=0; + int i=0; + int j=0; + int k=0; + double v=0; + double mx=0; +//--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- Calculate V=A[i][j],A=Z*Lambda*Z' + v=0; + for(k=0;k<=n-1;k++) + v=v+z[i][k]*lambdav[k]*z[j][k]; + //--- Compare + if(MathAbs(i-j)==0) + result=MathMax(result,MathAbs(v-d[i])); + //--- check + if(MathAbs(i-j)==1) + result=MathMax(result,MathAbs(v-e[MathMin(i,j)])); + //--- check + if(MathAbs(i-j)>1) + result=MathMax(result,MathAbs(v)); + } + } +//--- change value + mx=0; + for(i=0;i<=n-1;i++) + mx=MathMax(mx,MathAbs(d[i])); + for(i=0;i<=n-2;i++) + mx=MathMax(mx,MathAbs(e[i])); +//--- check + if(mx==0.0) + mx=1; +//--- return result + return(result/mx); + } +//+------------------------------------------------------------------+ +//| Tests Z*Lambda*Z' against A | +//| Returns relative error. | +//+------------------------------------------------------------------+ +static double CTestEVDUnit::TestProduct(CMatrixDouble &a,const int n, + CMatrixDouble &z,double &lambdav[]) + { +//--- create variables + double result=0; + int i=0; + int j=0; + int k=0; + double v=0; + double mx=0; +//--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- Calculate V=A[i][j],A=Z*Lambda*Z' + v=0; + for(k=0;k<=n-1;k++) + v=v+z[i][k]*lambdav[k]*z[j][k]; + //--- Compare + result=MathMax(result,MathAbs(v-a[i][j])); + } + } +//--- change value + mx=0; + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + mx=MathMax(mx,MathAbs(a[i][j])); + } +//--- check + if(mx==0.0) + mx=1; +//--- return result + return(result/mx); + } +//+------------------------------------------------------------------+ +//| Tests Z*Z' against diag(1...1) | +//| Returns absolute error. | +//+------------------------------------------------------------------+ +static double CTestEVDUnit::TestOrt(CMatrixDouble &z,const int n) + { +//--- create variables + double result=0; + int i=0; + int j=0; + double v=0; + int i_=0; +//--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=z[i_][i]*z[i_][j]; + //--- check + if(i==j) + v=v-1; + result=MathMax(result,MathAbs(v)); + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Tests Z*Lambda*Z' against A | +//| Returns relative error. | +//+------------------------------------------------------------------+ +static double CTestEVDUnit::TestCProduct(CMatrixComplex &a,const int n, + CMatrixComplex &z,double &lambdav[]) + { +//--- create variables + double result=0; + int i=0; + int j=0; + int k=0; + complex v=0; + double mx=0; +//--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- Calculate V=A[i][j],A=Z*Lambda*Z' + v=0; + for(k=0;k<=n-1;k++) + v=v+z[i][k]*lambdav[k]*CMath::Conj(z[j][k]); + //--- Compare + result=MathMax(result,CMath::AbsComplex(v-a[i][j])); + } + } +//--- change value + mx=0; + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + mx=MathMax(mx,CMath::AbsComplex(a[i][j])); + } +//--- check + if(mx==0.0) + mx=1; +//--- return result + return(result/mx); + } +//+------------------------------------------------------------------+ +//| Tests Z*Z' against diag(1...1) | +//| Returns absolute error. | +//+------------------------------------------------------------------+ +static double CTestEVDUnit::TestCOrt(CMatrixComplex &z,const int n) + { +//--- create variables + double result=0; + int i=0; + int j=0; + complex v=0; + int i_=0; +//--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=z[i_][i]*CMath::Conj(z[i_][j]); + //--- check + if(i==j) + v=v-1; + result=MathMax(result,CMath::AbsComplex(v)); + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Tests SEVD problem | +//+------------------------------------------------------------------+ +static void CTestEVDUnit::TestSEVDProblem(CMatrixDouble &a,CMatrixDouble &al, + CMatrixDouble &au,const int n, + const double threshold, + bool &serrors,int &failc,int &runs) + { +//--- create a variable + int i=0; +//--- create arrays + double lambdav[]; + double lambdaref[]; +//--- create matrix + CMatrixDouble z; +//--- Test simple EVD: values and full vectors,lower A + Unset1D(lambdaref); + Unset2D(z); + runs=runs+1; +//--- check + if(!CEigenVDetect::SMatrixEVD(al,n,1,false,lambdaref,z)) + { + failc=failc+1; + return; + } +//--- search errors + serrors=serrors || TestProduct(a,n,z,lambdaref)>threshold; + serrors=serrors || TestOrt(z,n)>threshold; + for(i=0;i<=n-2;i++) + { + //--- check + if(lambdaref[i+1]threshold; + serrors=serrors || TestOrt(z,n)>threshold; + for(i=0;i<=n-2;i++) + { + //--- check + if(lambdav[i+1]threshold; +//--- Test simple EVD: values only,upper A + Unset1D(lambdav); + Unset2D(z); + runs=runs+1; +//--- check + if(!CEigenVDetect::SMatrixEVD(au,n,0,true,lambdav,z)) + { + failc=failc+1; + return; + } +//--- search errors + for(i=0;i<=n-1;i++) + serrors=serrors || MathAbs(lambdav[i]-lambdaref[i])>threshold; + } +//+------------------------------------------------------------------+ +//| Tests SEVD problem | +//+------------------------------------------------------------------+ +static void CTestEVDUnit::TestHEVDProblem(CMatrixComplex &a,CMatrixComplex &al, + CMatrixComplex &au,const int n, + const double threshold,bool &herrors, + int &failc,int &runs) + { +//--- create a variable + int i=0; +//--- create arrays + double lambdav[]; + double lambdaref[]; +//--- create matrix + CMatrixComplex z; +//--- Test simple EVD: values and full vectors,lower A + Unset1D(lambdaref); + CUnset2D(z); + runs=runs+1; +//--- check + if(!CEigenVDetect::HMatrixEVD(al,n,1,false,lambdaref,z)) + { + failc=failc+1; + return; + } +//--- search errors + herrors=herrors || TestCProduct(a,n,z,lambdaref)>threshold; + herrors=herrors || TestCOrt(z,n)>threshold; + for(i=0;i<=n-2;i++) + { + //--- check + if(lambdaref[i+1]threshold; + herrors=herrors || TestCOrt(z,n)>threshold; + for(i=0;i<=n-2;i++) + { + //--- check + if(lambdav[i+1]threshold; +//--- Test simple EVD: values only,upper A + Unset1D(lambdav); + CUnset2D(z); + runs=runs+1; +//--- check + if(!CEigenVDetect::HMatrixEVD(au,n,0,true,lambdav,z)) + { + failc=failc+1; + return; + } +//--- search errors + for(i=0;i<=n-1;i++) + herrors=herrors || MathAbs(lambdav[i]-lambdaref[i])>threshold; + } +//+------------------------------------------------------------------+ +//| 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 CTestEVDUnit::TestSEVDBiProblem(CMatrixDouble &afull, + CMatrixDouble &al,CMatrixDouble &au, + const int n,const bool distvals, + const double threshold,bool &serrors, + int &failc,int &runs) + { +//--- create variables + int i=0; + int j=0; + int k=0; + int m=0; + int i1=0; + int i2=0; + double v=0; + double a=0; + double b=0; + int i_=0; +//--- create arrays + double lambdav[]; + double lambdaref[]; +//--- create matrix + CMatrixDouble z; + CMatrixDouble zref; + CMatrixDouble a1; + CMatrixDouble a2; + CMatrixDouble ar; +//--- allocation + ArrayResize(lambdaref,n); + zref.Resize(n,n); + a1.Resize(n,n); + a2.Resize(n,n); +//--- Reference EVD + runs=runs+1; +//--- check + if(!CEigenVDetect::SMatrixEVD(afull,n,1,true,lambdaref,zref)) + { + failc=failc+1; + 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=CMath::RandomInteger(n); + i2=i1+CMath::RandomInteger(n-i1); +//--- calculation + while(i1>0) + { + //--- check + if(MathAbs(lambdaref[i1-1]-lambdaref[i1])>10*threshold) + break; + i1=i1-1; + } + while(i210*threshold) + break; + i2=i2+1; + } +//--- Select A,B + if(i1>0) + a=0.5*(lambdaref[i1]+lambdaref[i1-1]); + else + a=lambdaref[0]-1; +//--- check + if(i2threshold; +//--- Test interval,no vectors,upper A + Unset1D(lambdav); + Unset2D(z); + runs=runs+1; +//--- check + if(!CEigenVDetect::SMatrixEVDR(au,n,0,true,a,b,m,lambdav,z)) + { + failc=failc+1; + return; + } +//--- check + if(m!=i2-i1+1) + { + failc=failc+1; + return; + } +//--- search errors + for(k=0;k<=m-1;k++) + serrors=serrors || MathAbs(lambdav[k]-lambdaref[i1+k])>threshold; +//--- Test indexes,no vectors,lower A + Unset1D(lambdav); + Unset2D(z); + runs=runs+1; +//--- check + if(!CEigenVDetect::SMatrixEVDI(al,n,0,false,i1,i2,lambdav,z)) + { + failc=failc+1; + return; + } + m=i2-i1+1; +//--- search errors + for(k=0;k<=m-1;k++) + serrors=serrors || MathAbs(lambdav[k]-lambdaref[i1+k])>threshold; +//--- Test indexes,no vectors,upper A + Unset1D(lambdav); + Unset2D(z); + runs=runs+1; +//--- check + if(!CEigenVDetect::SMatrixEVDI(au,n,0,true,i1,i2,lambdav,z)) + { + failc=failc+1; + return; + } + m=i2-i1+1; +//--- search errors + for(k=0;k<=m-1;k++) + serrors=serrors || MathAbs(lambdav[k]-lambdaref[i1+k])>threshold; +//--- Test interval,vectors,lower A + Unset1D(lambdav); + Unset2D(z); + runs=runs+1; +//--- check + if(!CEigenVDetect::SMatrixEVDR(al,n,1,false,a,b,m,lambdav,z)) + { + failc=failc+1; + return; + } +//--- check + if(m!=i2-i1+1) + { + failc=failc+1; + return; + } +//--- search errors + for(k=0;k<=m-1;k++) + serrors=serrors || MathAbs(lambdav[k]-lambdaref[i1+k])>threshold; +//--- check + if(distvals) + { + //--- Distinct eigenvalues,test vectors + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=z[i_][j]*zref[i_][i1+j]; + //--- check + if(v<0.0) + { + for(i_=0;i_<=n-1;i_++) + z[i_].Set(j,-1*z[i_][j]); + } + } + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + serrors=serrors || MathAbs(z[i][j]-zref[i][i1+j])>threshold; + } + } +//--- Test interval,vectors,upper A + Unset1D(lambdav); + Unset2D(z); + runs=runs+1; +//--- check + if(!CEigenVDetect::SMatrixEVDR(au,n,1,true,a,b,m,lambdav,z)) + { + failc=failc+1; + return; + } +//--- check + if(m!=i2-i1+1) + { + failc=failc+1; + return; + } +//--- search errors + for(k=0;k<=m-1;k++) + serrors=serrors || MathAbs(lambdav[k]-lambdaref[i1+k])>threshold; +//--- check + if(distvals) + { + //--- Distinct eigenvalues,test vectors + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=z[i_][j]*zref[i_][i1+j]; + //--- check + if(v<0.0) + { + for(i_=0;i_<=n-1;i_++) + z[i_].Set(j,-1*z[i_][j]); + } + } + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + serrors=serrors || MathAbs(z[i][j]-zref[i][i1+j])>threshold; + } + } +//--- Test indexes,vectors,lower A + Unset1D(lambdav); + Unset2D(z); + runs=runs+1; +//--- check + if(!CEigenVDetect::SMatrixEVDI(al,n,1,false,i1,i2,lambdav,z)) + { + failc=failc+1; + return; + } + m=i2-i1+1; +//--- search errors + for(k=0;k<=m-1;k++) + serrors=serrors || MathAbs(lambdav[k]-lambdaref[i1+k])>threshold; +//--- check + if(distvals) + { + //--- Distinct eigenvalues,test vectors + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=z[i_][j]*zref[i_][i1+j]; + //--- check + if(v<0.0) + { + for(i_=0;i_<=n-1;i_++) + z[i_].Set(j,-1*z[i_][j]); + } + } + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + serrors=serrors || MathAbs(z[i][j]-zref[i][i1+j])>threshold; + } + } +//--- Test indexes,vectors,upper A + Unset1D(lambdav); + Unset2D(z); + runs=runs+1; +//--- check + if(!CEigenVDetect::SMatrixEVDI(au,n,1,true,i1,i2,lambdav,z)) + { + failc=failc+1; + return; + } + m=i2-i1+1; +//--- search errors + for(k=0;k<=m-1;k++) + serrors=serrors || MathAbs(lambdav[k]-lambdaref[i1+k])>threshold; +//--- check + if(distvals) + { + //--- Distinct eigenvalues,test vectors + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=z[i_][j]*zref[i_][i1+j]; + //--- check + if(v<0.0) + { + for(i_=0;i_<=n-1;i_++) + z[i_].Set(j,-1*z[i_][j]); + } + } + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + serrors=serrors || MathAbs(z[i][j]-zref[i][i1+j])>threshold; + } + } + } +//+------------------------------------------------------------------+ +//| 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 CTestEVDUnit::TestHEVDBiProblem(CMatrixComplex &afull, + CMatrixComplex &al, + CMatrixComplex &au,const int n, + const bool distvals,const double threshold, + bool &herrors,int &failc,int &runs) + { +//--- create variables + int i=0; + int j=0; + int k=0; + int m=0; + int i1=0; + int i2=0; + complex v=0; + double a=0; + double b=0; + int i_=0; +//--- create arrays + double lambdav[]; + double lambdaref[]; +//--- create matrix + CMatrixComplex z; + CMatrixComplex zref; + CMatrixComplex a1; + CMatrixComplex a2; + CMatrixComplex ar; +//--- allocation + ArrayResize(lambdaref,n); + zref.Resize(n,n); + a1.Resize(n,n); + a2.Resize(n,n); +//--- Reference EVD + runs=runs+1; +//--- check + if(!CEigenVDetect::HMatrixEVD(afull,n,1,true,lambdaref,zref)) + { + failc=failc+1; + 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=CMath::RandomInteger(n); + i2=i1+CMath::RandomInteger(n-i1); +//--- calculation + while(i1>0) + { + //--- check + if(MathAbs(lambdaref[i1-1]-lambdaref[i1])>10*threshold) + break; + i1=i1-1; + } + while(i210*threshold) + break; + i2=i2+1; + } +//--- Select A,B + if(i1>0) + a=0.5*(lambdaref[i1]+lambdaref[i1-1]); + else + a=lambdaref[0]-1; +//--- check + if(i2threshold; +//--- Test interval,no vectors,upper A + Unset1D(lambdav); + CUnset2D(z); + runs=runs+1; +//--- check + if(!CEigenVDetect::HMatrixEVDR(au,n,0,true,a,b,m,lambdav,z)) + { + failc=failc+1; + return; + } +//--- check + if(m!=i2-i1+1) + { + failc=failc+1; + return; + } +//--- search errors + for(k=0;k<=m-1;k++) + herrors=herrors || MathAbs(lambdav[k]-lambdaref[i1+k])>threshold; +//--- Test indexes,no vectors,lower A + Unset1D(lambdav); + CUnset2D(z); + runs=runs+1; +//--- check + if(!CEigenVDetect::HMatrixEVDI(al,n,0,false,i1,i2,lambdav,z)) + { + failc=failc+1; + return; + } + m=i2-i1+1; +//--- search errors + for(k=0;k<=m-1;k++) + herrors=herrors || MathAbs(lambdav[k]-lambdaref[i1+k])>threshold; +//--- Test indexes,no vectors,upper A + Unset1D(lambdav); + CUnset2D(z); + runs=runs+1; +//--- check + if(!CEigenVDetect::HMatrixEVDI(au,n,0,true,i1,i2,lambdav,z)) + { + failc=failc+1; + return; + } + m=i2-i1+1; +//--- search errors + for(k=0;k<=m-1;k++) + herrors=herrors || MathAbs(lambdav[k]-lambdaref[i1+k])>threshold; +//--- Test interval,vectors,lower A + Unset1D(lambdav); + CUnset2D(z); + runs=runs+1; +//--- check + if(!CEigenVDetect::HMatrixEVDR(al,n,1,false,a,b,m,lambdav,z)) + { + failc=failc+1; + return; + } +//--- check + if(m!=i2-i1+1) + { + failc=failc+1; + return; + } +//--- search errors + for(k=0;k<=m-1;k++) + herrors=herrors || MathAbs(lambdav[k]-lambdaref[i1+k])>threshold; +//--- check + if(distvals) + { + //--- Distinct eigenvalues,test vectors + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=z[i_][j]*CMath::Conj(zref[i_][i1+j]); + v=CMath::Conj(v/CMath::AbsComplex(v)); + //--- calculation + for(i_=0;i_<=n-1;i_++) + z[i_].Set(j,v*z[i_][j]); + } + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + herrors=herrors || CMath::AbsComplex(z[i][j]-zref[i][i1+j])>threshold; + } + } +//--- Test interval,vectors,upper A + Unset1D(lambdav); + CUnset2D(z); + runs=runs+1; +//--- check + if(!CEigenVDetect::HMatrixEVDR(au,n,1,true,a,b,m,lambdav,z)) + { + failc=failc+1; + return; + } +//--- check + if(m!=i2-i1+1) + { + failc=failc+1; + return; + } +//--- search errors + for(k=0;k<=m-1;k++) + herrors=herrors || MathAbs(lambdav[k]-lambdaref[i1+k])>threshold; +//--- check + if(distvals) + { + //--- Distinct eigenvalues,test vectors + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=z[i_][j]*CMath::Conj(zref[i_][i1+j]); + v=CMath::Conj(v/CMath::AbsComplex(v)); + //--- calculation + for(i_=0;i_<=n-1;i_++) + z[i_].Set(j,v*z[i_][j]); + } + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + herrors=herrors || CMath::AbsComplex(z[i][j]-zref[i][i1+j])>threshold; + } + } +//--- Test indexes,vectors,lower A + Unset1D(lambdav); + CUnset2D(z); + runs=runs+1; +//--- check + if(!CEigenVDetect::HMatrixEVDI(al,n,1,false,i1,i2,lambdav,z)) + { + failc=failc+1; + return; + } + m=i2-i1+1; +//--- search errors + for(k=0;k<=m-1;k++) + herrors=herrors || MathAbs(lambdav[k]-lambdaref[i1+k])>threshold; +//--- check + if(distvals) + { + //--- Distinct eigenvalues,test vectors + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=z[i_][j]*CMath::Conj(zref[i_][i1+j]); + v=CMath::Conj(v/CMath::AbsComplex(v)); + //--- calculation + for(i_=0;i_<=n-1;i_++) + z[i_].Set(j,v*z[i_][j]); + } + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + herrors=herrors || CMath::AbsComplex(z[i][j]-zref[i][i1+j])>threshold; + } + } +//--- Test indexes,vectors,upper A + Unset1D(lambdav); + CUnset2D(z); + runs=runs+1; +//--- check + if(!CEigenVDetect::HMatrixEVDI(au,n,1,true,i1,i2,lambdav,z)) + { + failc=failc+1; + return; + } + m=i2-i1+1; +//--- search errors + for(k=0;k<=m-1;k++) + herrors=herrors || MathAbs(lambdav[k]-lambdaref[i1+k])>threshold; +//--- check + if(distvals) + { + //--- Distinct eigenvalues,test vectors + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=z[i_][j]*CMath::Conj(zref[i_][i1+j]); + v=CMath::Conj(v/CMath::AbsComplex(v)); + //--- calculation + for(i_=0;i_<=n-1;i_++) + z[i_].Set(j,v*z[i_][j]); + } + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + herrors=herrors || CMath::AbsComplex(z[i][j]-zref[i][i1+j])>threshold; + } + } + } +//+------------------------------------------------------------------+ +//| Tests EVD problem | +//+------------------------------------------------------------------+ +static void CTestEVDUnit::TestTdEVDProblem(double &d[],double &e[], + const int n,const double threshold, + bool &tderrors,int &failc,int &runs) + { +//--- create variables + bool wsucc; + int i=0; + int j=0; + double v=0; + int i_=0; +//--- create arrays + double lambdav[]; + double ee[]; + double lambda2[]; +//--- create matrix + CMatrixDouble z; + CMatrixDouble zref; + CMatrixDouble a1; + CMatrixDouble a2; +//--- allocation + ArrayResize(lambdav,n); + ArrayResize(lambda2,n); + zref.Resize(n,n); + a1.Resize(n,n); + a2.Resize(n,n); +//--- check + if(n>1) + { + //--- allocation + ArrayResize(ee,n-1); + } +//--- Test simple EVD: values and full vectors + for(i=0;i<=n-1;i++) + lambdav[i]=d[i]; + for(i=0;i<=n-2;i++) + ee[i]=e[i]; + runs=runs+1; + wsucc=CEigenVDetect::SMatrixTdEVD(lambdav,ee,n,2,z); +//--- check + if(!wsucc) + { + failc=failc+1; + return; + } +//--- search errors + tderrors=tderrors || TdTestProduct(d,e,n,z,lambdav)>threshold; + tderrors=tderrors || TestOrt(z,n)>threshold; + for(i=0;i<=n-2;i++) + { + //--- check + if(lambdav[i+1]threshold; +//--- Test multiplication variant + for(i=0;i<=n-1;i++) + lambda2[i]=d[i]; + for(i=0;i<=n-2;i++) + ee[i]=e[i]; +//--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + a1[i].Set(j,2*CMath::RandomReal()-1); + a2[i].Set(j,a1[i][j]); + } + } + runs=runs+1; + wsucc=CEigenVDetect::SMatrixTdEVD(lambda2,ee,n,1,a1); +//--- check + if(!wsucc) + { + failc=failc+1; + return; + } +//--- search errors + for(i=0;i<=n-1;i++) + tderrors=tderrors || MathAbs(lambda2[i]-lambdav[i])>threshold; + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a2[i][i_]*zref[i_][j]; + //--- 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 + tderrors=tderrors || (MathAbs(v-a1[i][j])>threshold && MathAbs(v+a1[i][j])>threshold); + } + } +//--- Test first row variant + for(i=0;i<=n-1;i++) + lambda2[i]=d[i]; + for(i=0;i<=n-2;i++) + ee[i]=e[i]; + runs=runs+1; + wsucc=CEigenVDetect::SMatrixTdEVD(lambda2,ee,n,3,z); +//--- check + if(!wsucc) + { + failc=failc+1; + return; + } +//--- search errors + for(i=0;i<=n-1;i++) + { + tderrors=tderrors || MathAbs(lambda2[i]-lambdav[i])>threshold; + //--- 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 + tderrors=tderrors || (MathAbs(z[0][i]-zref[0][i])>threshold && MathAbs(z[0][i]+zref[0][i])>threshold); + } + } +//+------------------------------------------------------------------+ +//| 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 CTestEVDUnit::TestTdEVDBiProblem(double &d[],double &e[], + const int n,const bool distvals, + const double threshold,bool &serrors, + int &failc,int &runs) + { +//--- create variables + int i=0; + int j=0; + int k=0; + int m=0; + int i1=0; + int i2=0; + double v=0; + double a=0; + double b=0; + int i_=0; +//--- create arrays + double lambdav[]; + double lambdaref[]; +//--- create matrix + CMatrixDouble z; + CMatrixDouble zref; + CMatrixDouble a1; + CMatrixDouble a2; + CMatrixDouble ar; +//--- allocation + ArrayResize(lambdaref,n); + zref.Resize(n,n); + a1.Resize(n,n); + a2.Resize(n,n); +//--- Reference EVD + ArrayResize(lambdaref,n); + for(i_=0;i_<=n-1;i_++) + lambdaref[i_]=d[i_]; + runs=runs+1; +//--- check + if(!CEigenVDetect::SMatrixTdEVD(lambdaref,e,n,2,zref)) + { + failc=failc+1; + 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=CMath::RandomInteger(n); + i2=i1+CMath::RandomInteger(n-i1); +//--- calculation + while(i1>0) + { + //--- check + if(MathAbs(lambdaref[i1-1]-lambdaref[i1])>10*threshold) + break; + i1=i1-1; + } + while(i210*threshold) + break; + i2=i2+1; + } +//--- Test different combinations +//--- Select A,B + if(i1>0) + a=0.5*(lambdaref[i1]+lambdaref[i1-1]); + else + a=lambdaref[0]-1; +//--- check + if(i2threshold; +//--- Test indexes,no vectors + ArrayResize(lambdav,n); + for(i=0;i<=n-1;i++) + lambdav[i]=d[i]; + runs=runs+1; +//--- check + if(!CEigenVDetect::SMatrixTdEVDI(lambdav,e,n,0,i1,i2,z)) + { + failc=failc+1; + return; + } + m=i2-i1+1; +//--- search errors + for(k=0;k<=m-1;k++) + serrors=serrors || MathAbs(lambdav[k]-lambdaref[i1+k])>threshold; +//--- Test interval,transform vectors + ArrayResize(lambdav,n); + for(i=0;i<=n-1;i++) + lambdav[i]=d[i]; +//--- allocation + a1.Resize(n,n); + a2.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + a1[i].Set(j,2*CMath::RandomReal()-1); + a2[i].Set(j,a1[i][j]); + } + } + runs=runs+1; +//--- check + if(!CEigenVDetect::SMatrixTdEVDR(lambdav,e,n,1,a,b,m,a1)) + { + failc=failc+1; + return; + } +//--- check + if(m!=i2-i1+1) + { + failc=failc+1; + return; + } +//--- search errors + for(k=0;k<=m-1;k++) + serrors=serrors || MathAbs(lambdav[k]-lambdaref[i1+k])>threshold; +//--- check + if(distvals) + { + //--- allocation + ar.Resize(n,m); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a2[i][i_]*zref[i_][i1+j]; + ar[i].Set(j,v); + } + } + //--- calculation + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a1[i_][j]*ar[i_][j]; + //--- check + if(v<0.0) + { + for(i_=0;i_<=n-1;i_++) + ar[i_].Set(j,-1*ar[i_][j]); + } + } + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + serrors=serrors || MathAbs(a1[i][j]-ar[i][j])>threshold; + } + } +//--- Test indexes,transform vectors + ArrayResize(lambdav,n); + for(i=0;i<=n-1;i++) + lambdav[i]=d[i]; +//--- allocation + a1.Resize(n,n); + a2.Resize(n,n); +//--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + a1[i].Set(j,2*CMath::RandomReal()-1); + a2[i].Set(j,a1[i][j]); + } + } + runs=runs+1; +//--- check + if(!CEigenVDetect::SMatrixTdEVDI(lambdav,e,n,1,i1,i2,a1)) + { + failc=failc+1; + return; + } + m=i2-i1+1; +//--- search errors + for(k=0;k<=m-1;k++) + serrors=serrors || MathAbs(lambdav[k]-lambdaref[i1+k])>threshold; +//--- check + if(distvals) + { + //--- allocation + ar.Resize(n,m); + //--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a2[i][i_]*zref[i_][i1+j]; + ar[i].Set(j,v); + } + } + //--- calculation + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a1[i_][j]*ar[i_][j]; + //--- check + if(v<0.0) + { + for(i_=0;i_<=n-1;i_++) + ar[i_].Set(j,-1*ar[i_][j]); + } + } + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + serrors=serrors || MathAbs(a1[i][j]-ar[i][j])>threshold; + } + } +//--- Test interval,do not transform vectors + ArrayResize(lambdav,n); + for(i=0;i<=n-1;i++) + lambdav[i]=d[i]; +//--- allocation + z.Resize(1,1); + runs=runs+1; +//--- check + if(!CEigenVDetect::SMatrixTdEVDR(lambdav,e,n,2,a,b,m,z)) + { + failc=failc+1; + return; + } +//--- check + if(m!=i2-i1+1) + { + failc=failc+1; + return; + } +//--- search errors + for(k=0;k<=m-1;k++) + serrors=serrors || MathAbs(lambdav[k]-lambdaref[i1+k])>threshold; +//--- check + if(distvals) + { + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=z[i_][j]*zref[i_][i1+j]; + //--- check + if(v<0.0) + { + for(i_=0;i_<=n-1;i_++) + z[i_].Set(j,-1*z[i_][j]); + } + } + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + serrors=serrors || MathAbs(z[i][j]-zref[i][i1+j])>threshold; + } + } +//--- Test indexes,do not transform vectors + ArrayResize(lambdav,n); + for(i=0;i<=n-1;i++) + lambdav[i]=d[i]; +//--- allocation + z.Resize(1,1); + runs=runs+1; +//--- check + if(!CEigenVDetect::SMatrixTdEVDI(lambdav,e,n,2,i1,i2,z)) + { + failc=failc+1; + return; + } + m=i2-i1+1; +//--- search errors + for(k=0;k<=m-1;k++) + serrors=serrors || MathAbs(lambdav[k]-lambdaref[i1+k])>threshold; +//--- check + if(distvals) + { + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=z[i_][j]*zref[i_][i1+j]; + //--- check + if(v<0.0) + { + for(i_=0;i_<=n-1;i_++) + z[i_].Set(j,-1*z[i_][j]); + } + } + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + serrors=serrors || MathAbs(z[i][j]-zref[i][i1+j])>threshold; + } + } + } +//+------------------------------------------------------------------+ +//| Non-symmetric problem | +//+------------------------------------------------------------------+ +static void CTestEVDUnit::TestNSEVDProblem(CMatrixDouble &a,const int n, + const double threshold, + bool &nserrors,int &failc, + int &runs) + { +//--- create variables + double mx=0; + int i=0; + int j=0; + int k=0; + int vjob=0; + bool needl; + bool needr; + double curwr=0; + double curwi=0; + double vt=0; + double tmp=0; + int i_=0; +//--- create arrays + double wr0[]; + double wi0[]; + double wr1[]; + double wi1[]; + double wr0s[]; + double wi0s[]; + double wr1s[]; + double wi1s[]; + double vec1r[]; + double vec1i[]; + double vec2r[]; + double vec2i[]; + double vec3r[]; + double vec3i[]; +//--- create matrix + CMatrixDouble vl; + CMatrixDouble vr; +//--- allocation + ArrayResize(vec1r,n); + ArrayResize(vec2r,n); + ArrayResize(vec3r,n); + ArrayResize(vec1i,n); + ArrayResize(vec2i,n); + ArrayResize(vec3i,n); + ArrayResize(wr0s,n); + ArrayResize(wr1s,n); + ArrayResize(wi0s,n); + ArrayResize(wi1s,n); +//--- initialization + mx=0; + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(MathAbs(a[i][j])>mx) + mx=MathAbs(a[i][j]); + } + } +//--- check + if(mx==0.0) + mx=1; +//--- Load values-only + runs=runs+1; +//--- check + if(!CEigenVDetect::RMatrixEVD(a,n,0,wr0,wi0,vl,vr)) + { + failc=failc+1; + return; + } +//--- Test different jobs + for(vjob=1;vjob<=3;vjob++) + { + needr=vjob==1 || vjob==3; + needl=vjob==2 || vjob==3; + runs=runs+1; + //--- check + if(!CEigenVDetect::RMatrixEVD(a,n,vjob,wr1,wi1,vl,vr)) + { + failc=failc+1; + return; + } + //--- Test values: + //--- 1. sort by real part + //--- 2. test + for(i_=0;i_<=n-1;i_++) + wr0s[i_]=wr0[i_]; + for(i_=0;i_<=n-1;i_++) + wi0s[i_]=wi0[i_]; + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-2-i;j++) + { + //--- check + if(wr0s[j]>wr0s[j+1]) + { + tmp=wr0s[j]; + wr0s[j]=wr0s[j+1]; + wr0s[j+1]=tmp; + tmp=wi0s[j]; + wi0s[j]=wi0s[j+1]; + wi0s[j+1]=tmp; + } + } + } + //--- copy + for(i_=0;i_<=n-1;i_++) + wr1s[i_]=wr1[i_]; + for(i_=0;i_<=n-1;i_++) + wi1s[i_]=wi1[i_]; + //--- swap + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-2-i;j++) + { + //--- check + if(wr1s[j]>wr1s[j+1]) + { + tmp=wr1s[j]; + wr1s[j]=wr1s[j+1]; + wr1s[j+1]=tmp; + tmp=wi1s[j]; + wi1s[j]=wi1s[j+1]; + wi1s[j+1]=tmp; + } + } + } + //--- search errors + for(i=0;i<=n-1;i++) + { + nserrors=nserrors || MathAbs(wr0s[i]-wr1s[i])>threshold; + nserrors=nserrors || MathAbs(wi0s[i]-wi1s[i])>threshold; + } + //--- Test right vectors + if(needr) + { + k=0; + //--- calculation + while(k<=n-1) + { + //--- check + if(wi1[k]==0.0) + { + for(i_=0;i_<=n-1;i_++) + vec1r[i_]=vr[i_][k]; + for(i=0;i<=n-1;i++) + vec1i[i]=0; + curwr=wr1[k]; + curwi=0; + } + //--- check + if(wi1[k]>0.0) + { + for(i_=0;i_<=n-1;i_++) + vec1r[i_]=vr[i_][k]; + for(i_=0;i_<=n-1;i_++) + vec1i[i_]=vr[i_][k+1]; + curwr=wr1[k]; + curwi=wi1[k]; + } + //--- check + if(wi1[k]<0.0) + { + for(i_=0;i_<=n-1;i_++) + vec1r[i_]=vr[i_][k-1]; + for(i_=0;i_<=n-1;i_++) + vec1i[i_]=-vr[i_][k]; + curwr=wr1[k]; + curwi=wi1[k]; + } + //--- calculation + for(i=0;i<=n-1;i++) + { + vt=0.0; + for(i_=0;i_<=n-1;i_++) + vt+=a[i][i_]*vec1r[i_]; + vec2r[i]=vt; + vt=0.0; + for(i_=0;i_<=n-1;i_++) + vt+=a[i][i_]*vec1i[i_]; + vec2i[i]=vt; + } + //--- change values + for(i_=0;i_<=n-1;i_++) + vec3r[i_]=curwr*vec1r[i_]; + for(i_=0;i_<=n-1;i_++) + vec3r[i_]=vec3r[i_]-curwi*vec1i[i_]; + for(i_=0;i_<=n-1;i_++) + vec3i[i_]=curwi*vec1r[i_]; + for(i_=0;i_<=n-1;i_++) + vec3i[i_]=vec3i[i_]+curwr*vec1i[i_]; + //--- search errors + for(i=0;i<=n-1;i++) + { + nserrors=nserrors || MathAbs(vec2r[i]-vec3r[i])>threshold; + nserrors=nserrors || MathAbs(vec2i[i]-vec3i[i])>threshold; + } + k=k+1; + } + } + //--- Test left vectors + if(needl) + { + k=0; + //--- calculation + while(k<=n-1) + { + //--- check + if(wi1[k]==0.0) + { + for(i_=0;i_<=n-1;i_++) + vec1r[i_]=vl[i_][k]; + for(i=0;i<=n-1;i++) + vec1i[i]=0; + curwr=wr1[k]; + curwi=0; + } + //--- check + if(wi1[k]>0.0) + { + for(i_=0;i_<=n-1;i_++) + vec1r[i_]=vl[i_][k]; + for(i_=0;i_<=n-1;i_++) + vec1i[i_]=vl[i_][k+1]; + curwr=wr1[k]; + curwi=wi1[k]; + } + //--- check + if(wi1[k]<0.0) + { + for(i_=0;i_<=n-1;i_++) + vec1r[i_]=vl[i_][k-1]; + for(i_=0;i_<=n-1;i_++) + vec1i[i_]=-vl[i_][k]; + curwr=wr1[k]; + curwi=wi1[k]; + } + //--- calculation + for(j=0;j<=n-1;j++) + { + vt=0.0; + for(i_=0;i_<=n-1;i_++) + vt+=vec1r[i_]*a[i_][j]; + vec2r[j]=vt; + vt=0.0; + for(i_=0;i_<=n-1;i_++) + vt+=vec1i[i_]*a[i_][j]; + vec2i[j]=-vt; + } + //--- change values + for(i_=0;i_<=n-1;i_++) + vec3r[i_]=curwr*vec1r[i_]; + for(i_=0;i_<=n-1;i_++) + vec3r[i_]=vec3r[i_]+curwi*vec1i[i_]; + for(i_=0;i_<=n-1;i_++) + vec3i[i_]=curwi*vec1r[i_]; + for(i_=0;i_<=n-1;i_++) + vec3i[i_]=vec3i[i_]-curwr*vec1i[i_]; + //--- search errors + for(i=0;i<=n-1;i++) + { + nserrors=nserrors || MathAbs(vec2r[i]-vec3r[i])>threshold; + nserrors=nserrors || MathAbs(vec2i[i]-vec3i[i])>threshold; + } + k=k+1; + } + } + } + } +//+------------------------------------------------------------------+ +//| 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 CTestEVDUnit::TestEVDSet(const int n,const double threshold, + double bithreshold,int &failc, + int &runs,bool &nserrors,bool &serrors, + bool &herrors,bool &tderrors,bool &sbierrors, + bool &hbierrors,bool &tdbierrors) + { +//--- create variables + int i=0; + int j=0; + int mkind=0; +//--- create arrays + double d[]; + double e[]; +//--- create matrix + CMatrixDouble ra; + CMatrixDouble ral; + CMatrixDouble rau; + CMatrixComplex ca; + CMatrixComplex cal; + CMatrixComplex cau; +//--- Test symmetric problems + ra.Resize(n,n); + ral.Resize(n,n); + rau.Resize(n,n); + ca.Resize(n,n); + cal.Resize(n,n); + cau.Resize(n,n); +//--- Zero matrices + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + ra[i].Set(j,0); + ca[i].Set(j,0); + } + } +//--- function calls + RMatrixSymmetricSplit(ra,n,ral,rau); + CMatrixHermitianSplit(ca,n,cal,cau); + TestSEVDProblem(ra,ral,rau,n,threshold,serrors,failc,runs); + TestHEVDProblem(ca,cal,cau,n,threshold,herrors,failc,runs); + TestSEVDBiProblem(ra,ral,rau,n,false,bithreshold,sbierrors,failc,runs); + TestHEVDBiProblem(ca,cal,cau,n,false,bithreshold,hbierrors,failc,runs); +//--- Random matrix + for(i=0;i<=n-1;i++) + { + for(j=i+1;j<=n-1;j++) + { + ra[i].Set(j,2*CMath::RandomReal()-1); + ca[i].SetRe(j,2*CMath::RandomReal()-1); + ca[i].SetIm(j,2*CMath::RandomReal()-1); + ra[j].Set(i,ra[i][j]); + ca[j].Set(i,CMath::Conj(ca[i][j])); + } + //--- change values + ra[i].Set(i,2*CMath::RandomReal()-1); + ca[i].Set(i,2*CMath::RandomReal()-1); + } +//--- function calls + RMatrixSymmetricSplit(ra,n,ral,rau); + CMatrixHermitianSplit(ca,n,cal,cau); + TestSEVDProblem(ra,ral,rau,n,threshold,serrors,failc,runs); + TestHEVDProblem(ca,cal,cau,n,threshold,herrors,failc,runs); +//--- Random diagonally dominant matrix with distinct eigenvalues + for(i=0;i<=n-1;i++) + { + for(j=i+1;j<=n-1;j++) + { + ra[i].Set(j,0.1*(2*CMath::RandomReal()-1)/n); + ca[i].SetRe(j,0.1*(2*CMath::RandomReal()-1)/n); + ca[i].SetIm(j,0.1*(2*CMath::RandomReal()-1)/n); + ra[j].Set(i,ra[i][j]); + ca[j].Set(i,CMath::Conj(ca[i][j])); + } + //--- change values + ra[i].Set(i,0.1*(2*CMath::RandomReal()-1)+i); + ca[i].Set(i,0.1*(2*CMath::RandomReal()-1)+i); + } +//--- function calls + RMatrixSymmetricSplit(ra,n,ral,rau); + CMatrixHermitianSplit(ca,n,cal,cau); + TestSEVDProblem(ra,ral,rau,n,threshold,serrors,failc,runs); + TestHEVDProblem(ca,cal,cau,n,threshold,herrors,failc,runs); + TestSEVDBiProblem(ra,ral,rau,n,true,bithreshold,sbierrors,failc,runs); + TestHEVDBiProblem(ca,cal,cau,n,true,bithreshold,hbierrors,failc,runs); +//--- Sparse matrices + RMatrixFillSparseA(ra,n,n,0.995); + CMatrixFillSparseA(ca,n,n,0.995); + for(i=0;i<=n-1;i++) + { + for(j=i+1;j<=n-1;j++) + { + ra[j].Set(i,ra[i][j]); + ca[j].Set(i,CMath::Conj(ca[i][j])); + } + ca[i].SetIm(i,0); + } +//--- function calls + RMatrixSymmetricSplit(ra,n,ral,rau); + CMatrixHermitianSplit(ca,n,cal,cau); + TestSEVDProblem(ra,ral,rau,n,threshold,serrors,failc,runs); + TestHEVDProblem(ca,cal,cau,n,threshold,herrors,failc,runs); + TestSEVDBiProblem(ra,ral,rau,n,false,bithreshold,sbierrors,failc,runs); + TestHEVDBiProblem(ca,cal,cau,n,false,bithreshold,hbierrors,failc,runs); +//--- testing tridiagonal problems + for(mkind=0;mkind<=7;mkind++) + { + //--- allocation + ArrayResize(d,n); + if(n>1) + ArrayResize(e,n-1); + //--- check + if(mkind==0) + { + //--- Zero matrix + for(i=0;i<=n-1;i++) + d[i]=0; + for(i=0;i<=n-2;i++) + e[i]=0; + } + //--- check + if(mkind==1) + { + //--- Diagonal matrix + for(i=0;i<=n-1;i++) + d[i]=2*CMath::RandomReal()-1; + for(i=0;i<=n-2;i++) + e[i]=0; + } + //--- check + if(mkind==2) + { + //--- Off-diagonal matrix + for(i=0;i<=n-1;i++) + d[i]=0; + for(i=0;i<=n-2;i++) + e[i]=2*CMath::RandomReal()-1; + } + //--- check + if(mkind==3) + { + //--- Dense matrix with blocks + for(i=0;i<=n-1;i++) + d[i]=2*CMath::RandomReal()-1; + for(i=0;i<=n-2;i++) + e[i]=2*CMath::RandomReal()-1; + //--- change values + j=1; + i=2; + while(j<=n-2) + { + e[j]=0; + j=j+i; + i=i+1; + } + } + //--- check + if(mkind==4) + { + //--- dense matrix + for(i=0;i<=n-1;i++) + d[i]=2*CMath::RandomReal()-1; + for(i=0;i<=n-2;i++) + e[i]=2*CMath::RandomReal()-1; + } + //--- check + if(mkind==5) + { + //--- Diagonal matrix with distinct eigenvalues + for(i=0;i<=n-1;i++) + d[i]=0.1*(2*CMath::RandomReal()-1)+i; + for(i=0;i<=n-2;i++) + e[i]=0; + } + //--- check + if(mkind==6) + { + //--- Off-diagonal matrix with distinct eigenvalues + for(i=0;i<=n-1;i++) + d[i]=0; + for(i=0;i<=n-2;i++) + e[i]=0.1*(2*CMath::RandomReal()-1)+i+1; + } + //--- check + if(mkind==7) + { + //--- dense matrix with distinct eigenvalues + for(i=0;i<=n-1;i++) + d[i]=0.1*(2*CMath::RandomReal()-1)+i+1; + for(i=0;i<=n-2;i++) + e[i]=0.1*(2*CMath::RandomReal()-1); + } + //--- function calls + TestTdEVDProblem(d,e,n,threshold,tderrors,failc,runs); + TestTdEVDBiProblem(d,e,n,(mkind==5 || mkind==6) || mkind==7,bithreshold,tdbierrors,failc,runs); + } +//--- Test non-symmetric problems +//--- Test non-symmetric problems: zero,random,sparse matrices. + ra.Resize(n,n); + ca.Resize(n,n); +//--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + ra[i].Set(j,0); + ca[i].Set(j,0); + } + } +//--- function call + TestNSEVDProblem(ra,n,threshold,nserrors,failc,runs); +//--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + ra[i].Set(j,2*CMath::RandomReal()-1); + ca[i].SetRe(j,2*CMath::RandomReal()-1); + ca[i].SetIm(j,2*CMath::RandomReal()-1); + } + } +//--- function calls + TestNSEVDProblem(ra,n,threshold,nserrors,failc,runs); + RMatrixFillSparseA(ra,n,n,0.995); + CMatrixFillSparseA(ca,n,n,0.995); + TestNSEVDProblem(ra,n,threshold,nserrors,failc,runs); + } +//+------------------------------------------------------------------+ +//| Testing class CMatGen | +//+------------------------------------------------------------------+ +class CTestMatGenUnit + { +private: + //--- private methods + static void Unset2D(CMatrixDouble &a); + static void Unset2DC(CMatrixComplex &a); + static bool IsSPD(CMatrixDouble &ca,const int n,const bool isupper); + static bool IsHPD(CMatrixComplex &ca,const int n); + static double SVDCond(CMatrixDouble &a,const int n); + static bool ObsoleteSVDDecomposition(CMatrixDouble &a,const int m,const int n,double &w[],CMatrixDouble &v); + static double ExtSign(const double a,const double b); + static double MyMax(const double a,const double b); + static double PyThag(const double a,const double b); +public: + //--- class constant + static const int m_maxsvditerations; + //--- constructor, destructor + CTestMatGenUnit(void); + ~CTestMatGenUnit(void); + //--- public method + static bool TestMatGen(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Initialize constant | +//+------------------------------------------------------------------+ +const int CTestMatGenUnit::m_maxsvditerations=60; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestMatGenUnit::CTestMatGenUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestMatGenUnit::~CTestMatGenUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CMatGen | +//+------------------------------------------------------------------+ +static bool CTestMatGenUnit::TestMatGen(const bool silent) + { +//--- create variables + int n=0; + int maxn=0; + int i=0; + int j=0; + int pass=0; + int passcount=0; + int equal_number=0; + bool waserrors; + double cond=0; + double threshold=0; + double vt=0; + complex ct=0; + double minw=0; + double maxw=0; + bool serr; + bool herr; + bool spderr; + bool hpderr; + bool rerr; + bool cerr; + int i_=0; +//--- create array + double w[]; +//--- create matrix + CMatrixDouble a; + CMatrixDouble b; + CMatrixDouble u; + CMatrixDouble v; + CMatrixComplex ca; + CMatrixComplex cb; + CMatrixDouble r1; + CMatrixDouble r2; + CMatrixComplex c1; + CMatrixComplex c2; +//--- initialization + rerr=false; + cerr=false; + serr=false; + herr=false; + spderr=false; + hpderr=false; + waserrors=false; + maxn=20; + passcount=15; + threshold=1000*CMath::m_machineepsilon; +//--- Testing orthogonal + for(n=1;n<=maxn;n++) + { + for(pass=1;pass<=passcount;pass++) + { + //--- allocation + r1.Resize(n,2*n); + r2.Resize(2*n,n); + c1.Resize(n,2*n); + c2.Resize(2*n,n); + //--- Random orthogonal,real + Unset2D(a); + Unset2D(b); + //--- function call + CMatGen::RMatrixRndOrthogonal(n,a); + //--- function call + CMatGen::RMatrixRndOrthogonal(n,b); + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- orthogonality test + vt=0.0; + for(i_=0;i_<=n-1;i_++) + vt+=a[i][i_]*a[j][i_]; + //--- check + if(i==j) + rerr=rerr || MathAbs(vt-1)>threshold; + else + rerr=rerr || MathAbs(vt)>threshold; + //--- change value + vt=0.0; + for(i_=0;i_<=n-1;i_++) + vt+=b[i][i_]*b[j][i_]; + //--- check + if(i==j) + rerr=rerr || MathAbs(vt-1)>threshold; + else + rerr=rerr || MathAbs(vt)>threshold; + //--- test for difference in A and B + if(n>=2) + rerr=rerr || a[i][j]==b[i][j]; + } + } + //--- Random orthogonal,complex + Unset2DC(ca); + Unset2DC(cb); + //--- function call + CMatGen::CMatrixRndOrthogonal(n,ca); + //--- function call + CMatGen::CMatrixRndOrthogonal(n,cb); + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- orthogonality test + ct=0.0; + for(i_=0;i_<=n-1;i_++) + ct+=ca[i][i_]*CMath::Conj(ca[j][i_]); + //--- check + if(i==j) + cerr=cerr || CMath::AbsComplex(ct-1)>threshold; + else + cerr=cerr || CMath::AbsComplex(ct)>threshold; + //--- change value + ct=0.0; + for(i_=0;i_<=n-1;i_++) + ct+=cb[i][i_]*CMath::Conj(cb[j][i_]); + //--- check + if(i==j) + cerr=cerr || CMath::AbsComplex(ct-1)>threshold; + else + cerr=cerr || CMath::AbsComplex(ct)>threshold; + //--- test for difference in A and B + if(n>=2) + cerr=cerr || ca[i][j]==cb[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) + Unset2D(a); + Unset2D(b); + //--- allocation + a.Resize(n,n); + b.Resize(n,n); + //--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + a[i].Set(j,0); + b[i].Set(j,0); + } + a[i].Set(i,1); + b[i].Set(i,1); + } + //--- function call + CMatGen::RMatrixRndOrthogonalFromTheRight(a,n,n); + //--- function call + CMatGen::RMatrixRndOrthogonalFromTheRight(b,n,n); + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- orthogonality test + vt=0.0; + for(i_=0;i_<=n-1;i_++) + vt+=a[i][i_]*a[j][i_]; + //--- check + if(i==j) + rerr=rerr || MathAbs(vt-1)>threshold; + else + rerr=rerr || MathAbs(vt)>threshold; + //--- change value + vt=0.0; + for(i_=0;i_<=n-1;i_++) + vt+=b[i][i_]*b[j][i_]; + //--- check + if(i==j) + rerr=rerr || MathAbs(vt-1)>threshold; + else + rerr=rerr || MathAbs(vt)>threshold; + //--- test for difference in A and B + if(n>=2) + rerr=rerr || a[i][j]==b[i][j]; + } + } + //--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + r2[i].Set(j,2*CMath::RandomReal()-1); + r2[i+n].Set(j,r2[i][j]); + } + } + //--- function call + CMatGen::RMatrixRndOrthogonalFromTheRight(r2,2*n,n); + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + rerr=rerr || MathAbs(r2[i+n][j]-r2[i][j])>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) + Unset2D(a); + Unset2D(b); + //--- allocation + a.Resize(n,n); + b.Resize(n,n); + //--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + a[i].Set(j,0); + b[i].Set(j,0); + } + a[i].Set(i,1); + b[i].Set(i,1); + } + //--- function call + CMatGen::RMatrixRndOrthogonalFromTheLeft(a,n,n); + //--- function call + CMatGen::RMatrixRndOrthogonalFromTheLeft(b,n,n); + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- orthogonality test + vt=0.0; + for(i_=0;i_<=n-1;i_++) + vt+=a[i][i_]*a[j][i_]; + //--- check + if(i==j) + rerr=rerr || MathAbs(vt-1)>threshold; + else + rerr=rerr || MathAbs(vt)>threshold; + //--- change value + vt=0.0; + for(i_=0;i_<=n-1;i_++) + vt+=b[i][i_]*b[j][i_]; + //--- check + if(i==j) + rerr=rerr || MathAbs(vt-1)>threshold; + else + rerr=rerr || MathAbs(vt)>threshold; + //--- test for difference in A and B + if(n>=2) + rerr=rerr || a[i][j]==b[i][j]; + } + } + //--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + r1[i].Set(j,2*CMath::RandomReal()-1); + r1[i].Set(j+n,r1[i][j]); + } + } + //--- function call + CMatGen::RMatrixRndOrthogonalFromTheLeft(r1,n,2*n); + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + rerr=rerr || MathAbs(r1[i][j]-r1[i][j+n])>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) + Unset2DC(ca); + Unset2DC(cb); + //--- allocation + ca.Resize(n,n); + cb.Resize(n,n); + //--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + ca[i].Set(j,0); + cb[i].Set(j,0); + } + ca[i].Set(i,1); + cb[i].Set(i,1); + } + //--- function call + CMatGen::CMatrixRndOrthogonalFromTheRight(ca,n,n); + //--- function call + CMatGen::CMatrixRndOrthogonalFromTheRight(cb,n,n); + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- orthogonality test + ct=0.0; + for(i_=0;i_<=n-1;i_++) + ct+=ca[i][i_]*CMath::Conj(ca[j][i_]); + //--- check + if(i==j) + cerr=cerr || CMath::AbsComplex(ct-1)>threshold; + else + cerr=cerr || CMath::AbsComplex(ct)>threshold; + //--- change value + ct=0.0; + for(i_=0;i_<=n-1;i_++) + ct+=cb[i][i_]*CMath::Conj(cb[j][i_]); + //--- check + if(i==j) + cerr=cerr || CMath::AbsComplex(ct-1)>threshold; + else + cerr=cerr || CMath::AbsComplex(ct)>threshold; + //--- test for difference in A and B + cerr=cerr || ca[i][j]==cb[i][j]; + } + } + //--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + c2[i].Set(j,2*CMath::RandomReal()-1); + c2[i+n].Set(j,c2[i][j]); + } + } + //--- function call + CMatGen::CMatrixRndOrthogonalFromTheRight(c2,2*n,n); + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + cerr=cerr || CMath::AbsComplex(c2[i+n][j]-c2[i][j])>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) + Unset2DC(ca); + Unset2DC(cb); + //--- allocation + ca.Resize(n,n); + cb.Resize(n,n); + //--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + ca[i].Set(j,0); + cb[i].Set(j,0); + } + ca[i].Set(i,1); + cb[i].Set(i,1); + } + //--- function call + CMatGen::CMatrixRndOrthogonalFromTheLeft(ca,n,n); + //--- function call + CMatGen::CMatrixRndOrthogonalFromTheLeft(cb,n,n); + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- orthogonality test + ct=0.0; + for(i_=0;i_<=n-1;i_++) + ct+=ca[i][i_]*CMath::Conj(ca[j][i_]); + //--- check + if(i==j) + cerr=cerr || CMath::AbsComplex(ct-1)>threshold; + else + cerr=cerr || CMath::AbsComplex(ct)>threshold; + //--- change value + ct=0.0; + for(i_=0;i_<=n-1;i_++) + ct+=cb[i][i_]*CMath::Conj(cb[j][i_]); + //--- check + if(i==j) + cerr=cerr || CMath::AbsComplex(ct-1)>threshold; + else + cerr=cerr || CMath::AbsComplex(ct)>threshold; + //--- test for difference in A and B + cerr=cerr || ca[i][j]==cb[i][j]; + } + } + //--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + c1[i].Set(j,2*CMath::RandomReal()-1); + c1[i].Set(j+n,c1[i][j]); + } + } + //--- function call + CMatGen::CMatrixRndOrthogonalFromTheLeft(c1,n,2*n); + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + cerr=cerr || CMath::AbsComplex(c1[i][j]-c1[i][j+n])>threshold; + } + } + } +//--- Testing GCond + for(n=2;n<=maxn;n++) + { + for(pass=1;pass<=passcount;pass++) + { + //--- real test + Unset2D(a); + cond=MathExp(MathLog(1000)*CMath::RandomReal()); + //--- function call + CMatGen::RMatrixRndCond(n,cond,a); + //--- allocation + b.Resize(n+1,n+1); + //--- change values + for(i=1;i<=n;i++) + { + for(j=1;j<=n;j++) + b[i].Set(j,a[i-1][j-1]); + } + //--- check + if(ObsoleteSVDDecomposition(b,n,n,w,v)) + { + maxw=w[1]; + minw=w[1]; + for(i=2;i<=n;i++) + { + //--- check + if(w[i]>maxw) + maxw=w[i]; + //--- check + if(w[i]MathLog(1+threshold)) + rerr=true; + } + } + } +//--- Symmetric/SPD +//--- N=2 .. 30 + for(n=2;n<=maxn;n++) + { + //--- SPD matrices + for(pass=1;pass<=passcount;pass++) + { + //--- Generate A + Unset2D(a); + cond=MathExp(MathLog(1000)*CMath::RandomReal()); + //--- function call + CMatGen::SPDMatrixRndCond(n,cond,a); + //--- test condition number + spderr=spderr || SVDCond(a,n)/cond-1>threshold; + //--- test SPD + spderr=spderr || !IsSPD(a,n,true); + //--- test that A is symmetic + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + spderr=spderr || MathAbs(a[i][j]-a[j][i])>threshold; + } + //--- test for difference between A and B (subsequent matrix) + Unset2D(b); + //--- function call + CMatGen::SPDMatrixRndCond(n,cond,b); + //--- check + if(n>=2) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + if(a[i][j]==b[i][j]) + equal_number++; + } + } + if(equal_number>2) + spderr=true; + } + } + //--- HPD matrices + for(pass=1;pass<=passcount;pass++) + { + //--- Generate A + Unset2DC(ca); + cond=MathExp(MathLog(1000)*CMath::RandomReal()); + //--- function call + CMatGen::HPDMatrixRndCond(n,cond,ca); + //--- test HPD + hpderr=hpderr || !IsHPD(ca,n); + //--- test that A is Hermitian + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + hpderr=hpderr || CMath::AbsComplex(ca[i][j]-CMath::Conj(ca[j][i]))>threshold; + } + //--- test for difference between A and B (subsequent matrix) + Unset2DC(cb); + //--- function call + CMatGen::HPDMatrixRndCond(n,cond,cb); + //--- check + if(n>=2) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + hpderr=hpderr || ca[i][j]==cb[i][j]; + } + } + } + } + //--- Symmetric matrices + for(pass=1;pass<=passcount;pass++) + { + //--- test condition number + Unset2D(a); + cond=MathExp(MathLog(1000)*CMath::RandomReal()); + //--- function call + CMatGen::SMatrixRndCond(n,cond,a); + serr=serr || SVDCond(a,n)/cond-1>threshold; + //--- test for difference between A and B + Unset2D(b); + //--- function call + CMatGen::SMatrixRndCond(n,cond,b); + //--- check + if(n>=2) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + serr=serr || a[i][j]==b[i][j]; + } + } + } + //--- Hermitian matrices + for(pass=1;pass<=passcount;pass++) + { + //--- Generate A + Unset2DC(ca); + cond=MathExp(MathLog(1000)*CMath::RandomReal()); + //--- function call + CMatGen::HMatrixRndCond(n,cond,ca); + //--- test that A is Hermitian + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + herr=herr || CMath::AbsComplex(ca[i][j]-CMath::Conj(ca[j][i]))>threshold; + } + //--- test for difference between A and B (subsequent matrix) + Unset2DC(cb); + //--- function call + CMatGen::HMatrixRndCond(n,cond,cb); + //--- check + if(n>=2) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + herr=herr || ca[i][j]==cb[i][j]; + } + } + } + } +//--- report + waserrors=((((rerr || cerr) || serr) || spderr) || herr) || hpderr; +//--- check + if(!silent) + { + Print("TESTING MATRIX GENERATOR"); + Print("REAL TEST: "); + //--- check + if(!rerr) + Print("OK"); + else + Print("FAILED"); + Print("COMPLEX TEST: "); + //--- check + if(!cerr) + Print("OK"); + else + Print("FAILED"); + Print("SYMMETRIC TEST: "); + //--- check + if(!serr) + Print("OK"); + else + Print("FAILED"); + Print("HERMITIAN TEST: "); + //--- check + if(!herr) + Print("OK"); + else + Print("FAILED"); + Print("SPD TEST: "); + //--- check + if(!spderr) + Print("OK"); + else + Print("FAILED"); + Print("HPD TEST: "); + //--- check + if(!hpderr) + Print("OK"); + else + Print("FAILED"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Unsets 2D array. | +//+------------------------------------------------------------------+ +static void CTestMatGenUnit::Unset2D(CMatrixDouble &a) + { +//--- allocation + a.Resize(1,1); +//--- change value + a[0].Set(0,2*CMath::RandomReal()-1); + } +//+------------------------------------------------------------------+ +//| Unsets 2D array. | +//+------------------------------------------------------------------+ +static void CTestMatGenUnit::Unset2DC(CMatrixComplex &a) + { +//--- allocation + a.Resize(1,1); +//--- change value + a[0].Set(0,2*CMath::RandomReal()-1); + } +//+------------------------------------------------------------------+ +//| Test whether matrix is SPD | +//+------------------------------------------------------------------+ +static bool CTestMatGenUnit::IsSPD(CMatrixDouble &ca,const int n,const bool isupper) + { +//--- create variables + bool result; + int i=0; + int j=0; + double ajj=0; + double v=0; + int i_=0; +//--- create matrix + CMatrixDouble a; +//--- copy + a=ca; +//--- Test the input parameters. + if(!CAp::Assert(n>=0,"Error in SMatrixCholesky: incorrect function arguments")) + return(false); +//--- Quick return if possible + result=true; + if(n<=0) + { + //--- return result + return(result); + } +//--- check + 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=0.0; + for(i_=0;i_<=j-1;i_++) + v+=a[i_][j]*a[i_][j]; + ajj=a[j][j]-v; + //--- check + if(ajj<=0.0) + { + //--- return result + return(false); + } + //--- change values + ajj=MathSqrt(ajj); + a[j].Set(j,ajj); + //--- Compute elements J+1:N of row J. + if(jmaxw) + maxw=w[i]; + } +//--- return result + return(maxw/minw); + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static bool CTestMatGenUnit::ObsoleteSVDDecomposition(CMatrixDouble &a, + const int m, + const int n, + double &w[], + CMatrixDouble &v) + { +//--- create variables + bool result; + int nm=0; + int minmn=0; + int l=0; + int k=0; + int j=0; + int jj=0; + int its=0; + int i=0; + double z=0; + double y=0; + double x=0; + double vscale=0; + double s=0; + double h=0; + double g=0; + double f=0; + double c=0; + double anorm=0; + bool flag; +//--- create array + double rv1[]; +//--- allocation + ArrayResize(rv1,n+1); + ArrayResize(w,n+1); + v.Resize(n+1,n+1); +//--- initialization + result=true; +//--- check + if(m=1;i--) + { + //--- check + if(i=1;i--) + { + l=i+1; + g=w[i]; + //--- check + if(i=1;k--) + { + for(its=1;its<=m_maxsvditerations;its++) + { + flag=true; + for(l=k;l>=1;l--) + { + nm=l-1; + //--- check + if(MathAbs(rv1[l])+anorm==anorm) + { + flag=false; + break; + } + //--- check + if(MathAbs(w[nm])+anorm==anorm) + break; + } + //--- check + if(flag) + { + c=0.0; + s=1.0; + //--- calculation + for(i=l;i<=k;i++) + { + f=s*rv1[i]; + //--- check + if(MathAbs(f)+anorm!=anorm) + { + //--- change values + g=w[i]; + h=PyThag(f,g); + w[i]=h; + h=1.0/h; + c=g*h; + s=-(f*h); + for(j=1;j<=m;j++) + { + y=a[j][nm]; + z=a[j][i]; + a[j].Set(nm,y*c+z*s); + a[j].Set(i,-(y*s)+z*c); + } + } + } + } + z=w[k]; + //--- check + if(l==k) + { + //--- check + if(z<0.0) + { + w[k]=-z; + for(j=1;j<=n;j++) + v[j].Set(k,-v[j][k]); + } + break; + } + //--- check + if(its==m_maxsvditerations) + { + //--- return result + return(false); + } + //--- change values + x=w[l]; + nm=k-1; + y=w[nm]; + g=rv1[nm]; + h=rv1[k]; + f=((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y); + g=PyThag(f,1); + f=((x-z)*(x+z)+h*(y/(f+ExtSign(g,f))-h))/x; + c=1.0; + s=1.0; + //--- calculation + for(j=l;j<=nm;j++) + { + i=j+1; + g=rv1[i]; + y=w[i]; + h=s*g; + g=c*g; + z=PyThag(f,h); + rv1[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[jj][j]; + z=v[jj][i]; + v[jj].Set(j,x*c+z*s); + v[jj].Set(i,-(x*s)+z*c); + } + z=PyThag(f,h); + w[j]=z; + //--- check + if(z!=0.0) + { + z=1.0/z; + c=f*z; + s=h*z; + } + //--- calculation + f=c*g+s*y; + x=-(s*g)+c*y; + for(jj=1;jj<=m;jj++) + { + y=a[jj][j]; + z=a[jj][i]; + a[jj].Set(j,y*c+z*s); + a[jj].Set(i,-(y*s)+z*c); + } + } + //--- change values + rv1[l]=0.0; + rv1[k]=f; + w[k]=x; + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static double CTestMatGenUnit::ExtSign(const double a,const double b) + { +//--- create a variable + double result=0; +//--- check + if(b>=0.0) + result=MathAbs(a); + else + result=-MathAbs(a); +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static double CTestMatGenUnit::MyMax(const double a,const double b) + { +//--- create a variable + double result=0; +//--- check + if(a>b) + result=a; + else + result=b; +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static double CTestMatGenUnit::PyThag(const double a,const double b) + { +//--- create a variable + double result=0; +//--- check + if(MathAbs(a)0.5) + n=mx; + else + m=mx; + //--- First,test on zero matrix + ra.Resize(m,n); + ca.Resize(m,n); + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + ra[i].Set(j,0); + ca[i].Set(j,0); + } + } + //--- function calls + TestCLUProblem(ca,m,n,threshold,cerr,properr); + TestRLUProblem(ra,m,n,threshold,rerr,properr); + //--- Second,random matrix with moderate condition number + ra.Resize(m,n); + ca.Resize(m,n); + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + ra[i].Set(j,0); + ca[i].Set(j,0); + } + } + //--- change values + for(i=0;i<=MathMin(m,n)-1;i++) + { + ra[i].Set(i,1+10*CMath::RandomReal()); + ca[i].Set(i,1+10*CMath::RandomReal()); + } + //--- function call + CMatGen::CMatrixRndOrthogonalFromTheLeft(ca,m,n); + //--- function call + CMatGen::CMatrixRndOrthogonalFromTheRight(ca,m,n); + //--- function call + CMatGen::RMatrixRndOrthogonalFromTheLeft(ra,m,n); + //--- function call + CMatGen::RMatrixRndOrthogonalFromTheRight(ra,m,n); + //--- function calls + TestCLUProblem(ca,m,n,threshold,cerr,properr); + TestRLUProblem(ra,m,n,threshold,rerr,properr); + } +//--- Test Cholesky + for(n=1;n<=maxmn;n++) + { + //--- Load CA (HPD matrix with low condition number), + //--- CAL and CAU - its lower and upper triangles + CMatGen::HPDMatrixRndCond(n,1+50*CMath::RandomReal(),ca); + //--- allocation + cal.Resize(n,n); + cau.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + cal[i].Set(j,i); + cau[i].Set(j,j); + } + } + //--- change values + for(i=0;i<=n-1;i++) + { + for(i_=0;i_<=i;i_++) + cal[i].Set(i_,ca[i][i_]); + for(i_=i;i_<=n-1;i_++) + cau[i].Set(i_,ca[i][i_]); + } + //--- Test HPDMatrixCholesky: + //--- 1. it must leave upper (lower) part unchanged + //--- 2. max(A-L*L^H) must be small + if(CTrFac::HPDMatrixCholesky(cal,n,false)) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(j>i) + hpderr=hpderr || cal[i][j]!=i; + else + { + vc=0.0; + for(i_=0;i_<=j;i_++) + vc+=cal[i][i_]*CMath::Conj(cal[j][i_]); + //--- search errors + hpderr=hpderr || CMath::AbsComplex(ca[i][j]-vc)>threshold; + } + } + } + } + else + hpderr=true; + //--- check + if(CTrFac::HPDMatrixCholesky(cau,n,true)) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(jthreshold; + } + } + } + } + else + hpderr=true; + //--- Load RA (SPD matrix with low condition number), + //--- RAL and RAU - its lower and upper triangles + CMatGen::SPDMatrixRndCond(n,1+50*CMath::RandomReal(),ra); + //--- allocation + ral.Resize(n,n); + rau.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + ral[i].Set(j,i); + rau[i].Set(j,j); + } + } + //--- change values + for(i=0;i<=n-1;i++) + { + for(i_=0;i_<=i;i_++) + ral[i].Set(i_,ra[i][i_]); + for(i_=i;i_<=n-1;i_++) + rau[i].Set(i_,ra[i][i_]); + } + //--- Test SPDMatrixCholesky: + //--- 1. it must leave upper (lower) part unchanged + //--- 2. max(A-L*L^H) must be small + if(CTrFac::SPDMatrixCholesky(ral,n,false)) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(j>i) + spderr=spderr || ral[i][j]!=i; + else + { + vr=0.0; + for(i_=0;i_<=j;i_++) + vr+=ral[i][i_]*ral[j][i_]; + //--- search errors + spderr=spderr || MathAbs(ra[i][j]-vr)>threshold; + } + } + } + } + else + spderr=true; + //--- check + if(CTrFac::SPDMatrixCholesky(rau,n,true)) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(jthreshold; + } + } + } + } + else + spderr=true; + } +//--- report + waserrors=(((rerr || spderr) || cerr) || hpderr) || properr; +//--- check + if(!silent) + { + Print("TESTING TRIANGULAR FACTORIZATIONS"); + Print("* REAL: "); + //--- check + if(rerr) + Print("FAILED"); + else + Print("OK"); + Print("* SPD: "); + //--- check + if(spderr) + Print("FAILED"); + else + Print("OK"); + Print("* COMPLEX: "); + //--- check + if(cerr) + Print("FAILED"); + else + Print("OK"); + Print("* HPD: "); + //--- check + if(hpderr) + Print("FAILED"); + else + Print("OK"); + Print("* OTHER PROPERTIES: "); + //--- check + if(properr) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestTrFacUnit::TestCLUProblem(CMatrixComplex &a,const int m, + const int n,const double threshold, + bool &err,bool &properr) + { +//--- create variables + int i=0; + int j=0; + int minmn=0; + complex v=0; + int i_=0; +//--- create arrays + complex ct[]; + int p[]; +//--- create matrix + CMatrixComplex ca; + CMatrixComplex cl; + CMatrixComplex cu; + CMatrixComplex ca2; +//--- initialization + minmn=MathMin(m,n); +//--- PLU test + ca.Resize(m,n); + for(i=0;i<=m-1;i++) + { + for(i_=0;i_<=n-1;i_++) + ca[i].Set(i_,a[i][i_]); + } +//--- function call + CTrFac::CMatrixPLU(ca,m,n,p); + for(i=0;i<=minmn-1;i++) + { + //--- check + if(p[i]=m) + { + properr=false; + return; + } + } +//--- allocation + cl.Resize(m,minmn); + for(j=0;j<=minmn-1;j++) + { + for(i=0;i<=j-1;i++) + cl[i].Set(j,0.0); + //--- change values + cl[j].Set(j,1.0); + for(i=j+1;i<=m-1;i++) + cl[i].Set(j,ca[i][j]); + } +//--- allocation + cu.Resize(minmn,n); +//--- change values + for(i=0;i<=minmn-1;i++) + { + for(j=0;j<=i-1;j++) + cu[i].Set(j,0.0); + for(j=i;j<=n-1;j++) + cu[i].Set(j,ca[i][j]); + } +//--- allocation + ca2.Resize(m,n); +//--- calculation + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=minmn-1;i_++) + v+=cl[i][i_]*cu[i_][j]; + ca2[i].Set(j,v); + } + } +//--- allocation + ArrayResize(ct,n); +//--- change values + for(i=minmn-1;i>=0;i--) + { + //--- check + if(i!=p[i]) + { + for(i_=0;i_<=n-1;i_++) + ct[i_]=ca2[i][i_]; + for(i_=0;i_<=n-1;i_++) + ca2[i].Set(i_,ca2[p[i]][i_]); + for(i_=0;i_<=n-1;i_++) + ca2[p[i]].Set(i_,ct[i_]); + } + } +//--- search errors + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + err=err || CMath::AbsComplex(a[i][j]-ca2[i][j])>threshold; + } +//--- LUP test + ca.Resize(m,n); + for(i=0;i<=m-1;i++) + { + for(i_=0;i_<=n-1;i_++) + ca[i].Set(i_,a[i][i_]); + } +//--- function call + CTrFac::CMatrixLUP(ca,m,n,p); + for(i=0;i<=minmn-1;i++) + { + //--- check + if(p[i]=n) + { + properr=false; + return; + } + } +//--- allocation + cl.Resize(m,minmn); +//--- change values + for(j=0;j<=minmn-1;j++) + { + for(i=0;i<=j-1;i++) + cl[i].Set(j,0.0); + for(i=j;i<=m-1;i++) + cl[i].Set(j,ca[i][j]); + } +//--- allocation + cu.Resize(minmn,n); +//--- change values + for(i=0;i<=minmn-1;i++) + { + for(j=0;j<=i-1;j++) + cu[i].Set(j,0.0); + cu[i].Set(i,1.0); + for(j=i+1;j<=n-1;j++) + cu[i].Set(j,ca[i][j]); + } +//--- allocation + ca2.Resize(m,n); +//--- calculation + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=minmn-1;i_++) + v+=cl[i][i_]*cu[i_][j]; + ca2[i].Set(j,v); + } + } +//--- allocation + ArrayResize(ct,m); +//--- change values + for(i=minmn-1;i>=0;i--) + { + //--- check + if(i!=p[i]) + { + for(i_=0;i_<=m-1;i_++) + ct[i_]=ca2[i_][i]; + for(i_=0;i_<=m-1;i_++) + ca2[i_].Set(i,ca2[i_][p[i]]); + for(i_=0;i_<=m-1;i_++) + ca2[i_].Set(p[i],ct[i_]); + } + } +//--- search errors + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + err=err || CMath::AbsComplex(a[i][j]-ca2[i][j])>threshold; + } + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestTrFacUnit::TestRLUProblem(CMatrixDouble &a,const int m, + const int n,const double threshold, + bool &err,bool &properr) + { +//--- create variables + int i=0; + int j=0; + int minmn=0; + double v=0; + int i_=0; +//--- create arrays + double ct[]; + int p[]; +//--- create matrix + CMatrixDouble ca; + CMatrixDouble cl; + CMatrixDouble cu; + CMatrixDouble ca2; +//--- initialization + minmn=MathMin(m,n); +//--- PLU test + ca.Resize(m,n); + for(i=0;i<=m-1;i++) + { + for(i_=0;i_<=n-1;i_++) + ca[i].Set(i_,a[i][i_]); + } +//--- function call + CTrFac::RMatrixPLU(ca,m,n,p); + for(i=0;i<=minmn-1;i++) + { + //--- check + if(p[i]=m) + { + properr=false; + return; + } + } +//--- allocation + cl.Resize(m,minmn); +//--- change values + for(j=0;j<=minmn-1;j++) + { + for(i=0;i<=j-1;i++) + cl[i].Set(j,0.0); + cl[j].Set(j,1.0); + for(i=j+1;i<=m-1;i++) + cl[i].Set(j,ca[i][j]); + } +//--- allocation + cu.Resize(minmn,n); +//--- change values + for(i=0;i<=minmn-1;i++) + { + for(j=0;j<=i-1;j++) + cu[i].Set(j,0.0); + for(j=i;j<=n-1;j++) + cu[i].Set(j,ca[i][j]); + } +//--- allocation + ca2.Resize(m,n); +//--- calculation + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=minmn-1;i_++) + v+=cl[i][i_]*cu[i_][j]; + ca2[i].Set(j,v); + } + } +//--- allocation + ArrayResize(ct,n); + for(i=minmn-1;i>=0;i--) + { + //--- check + if(i!=p[i]) + { + //--- change values + for(i_=0;i_<=n-1;i_++) + ct[i_]=ca2[i][i_]; + for(i_=0;i_<=n-1;i_++) + ca2[i].Set(i_,ca2[p[i]][i_]); + for(i_=0;i_<=n-1;i_++) + ca2[p[i]].Set(i_,ct[i_]); + } + } +//--- search errors + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + err=err || MathAbs(a[i][j]-ca2[i][j])>threshold; + } +//--- LUP test + ca.Resize(m,n); + for(i=0;i<=m-1;i++) + { + for(i_=0;i_<=n-1;i_++) + ca[i].Set(i_,a[i][i_]); + } +//--- function call + CTrFac::RMatrixLUP(ca,m,n,p); + for(i=0;i<=minmn-1;i++) + { + //--- check + if(p[i]=n) + { + properr=false; + return; + } + } +//--- allocation + cl.Resize(m,minmn); +//--- change values + for(j=0;j<=minmn-1;j++) + { + for(i=0;i<=j-1;i++) + cl[i].Set(j,0.0); + for(i=j;i<=m-1;i++) + cl[i].Set(j,ca[i][j]); + } +//--- allocation + cu.Resize(minmn,n); +//--- change values + for(i=0;i<=minmn-1;i++) + { + for(j=0;j<=i-1;j++) + cu[i].Set(j,0.0); + cu[i].Set(i,1.0); + for(j=i+1;j<=n-1;j++) + cu[i].Set(j,ca[i][j]); + } +//--- allocation + ca2.Resize(m,n); + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=minmn-1;i_++) + v+=cl[i][i_]*cu[i_][j]; + ca2[i].Set(j,v); + } + } +//--- allocation + ArrayResize(ct,m); + for(i=minmn-1;i>=0;i--) + { + //--- check + if(i!=p[i]) + { + //--- change values + for(i_=0;i_<=m-1;i_++) + ct[i_]=ca2[i_][i]; + for(i_=0;i_<=m-1;i_++) + ca2[i_].Set(i,ca2[i_][p[i]]); + for(i_=0;i_<=m-1;i_++) + ca2[i_].Set(p[i],ct[i_]); + } + } +//--- search errors + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + err=err || MathAbs(a[i][j]-ca2[i][j])>threshold; + } + } +//+------------------------------------------------------------------+ +//| Testing class CTrLinSolve | +//+------------------------------------------------------------------+ +class CTestTrLinSolveUnit + { +private: + //--- private method + static void MakeACopy(CMatrixDouble &a,const int m,const int n,CMatrixDouble &b); +public: + //--- constructor, destructor + CTestTrLinSolveUnit(void); + ~CTestTrLinSolveUnit(void); + //--- public method + static bool TestTrLinSolve(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestTrLinSolveUnit::CTestTrLinSolveUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestTrLinSolveUnit::~CTestTrLinSolveUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Main unittest subroutine | +//+------------------------------------------------------------------+ +static bool CTestTrLinSolveUnit::TestTrLinSolve(const bool silent) + { +//--- create variables + int maxmn=0; + int passcount=0; + double threshold=0; + int n=0; + int pass=0; + int i=0; + int j=0; + int cnts=0; + int cntu=0; + int cntt=0; + int cntm=0; + bool waserrors; + bool isupper; + bool istrans; + bool isunit; + double v=0; + double s=0; + int i_=0; +//--- create arrays + double xe[]; + double b[]; +//--- create matrix + CMatrixDouble aeffective; + CMatrixDouble aparam; +//--- initialization + waserrors=false; + maxmn=15; + passcount=15; + threshold=1000*CMath::m_machineepsilon; +//--- Different problems + for(n=1;n<=maxmn;n++) + { + //--- allocation + aeffective.Resize(n,n); + aparam.Resize(n,n); + ArrayResize(xe,n); + ArrayResize(b,n); + //--- calculation + 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[i].Set(j,0); + aparam[i].Set(j,0); + } + } + //--- Prepare matrices + if(isupper) + { + for(i=0;i<=n-1;i++) + { + for(j=i;j<=n-1;j++) + { + aeffective[i].Set(j,0.9*(2*CMath::RandomReal()-1)); + aparam[i].Set(j,aeffective[i][j]); + } + //--- change values + aeffective[i].Set(i,(2*CMath::RandomInteger(2)-1)*(0.8+CMath::RandomReal())); + aparam[i].Set(i,aeffective[i][i]); + } + } + else + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=i;j++) + { + aeffective[i].Set(j,0.9*(2*CMath::RandomReal()-1)); + aparam[i].Set(j,aeffective[i][j]); + } + //--- change values + aeffective[i].Set(i,(2*CMath::RandomInteger(2)-1)*(0.8+CMath::RandomReal())); + aparam[i].Set(i,aeffective[i][i]); + } + } + //--- check + if(isunit) + { + for(i=0;i<=n-1;i++) + { + aeffective[i].Set(i,1); + aparam[i].Set(i,0); + } + } + //--- check + if(istrans) + { + //--- check + if(isupper) + { + for(i=0;i<=n-1;i++) + { + for(j=i+1;j<=n-1;j++) + { + aeffective[j].Set(i,aeffective[i][j]); + aeffective[i].Set(j,0); + } + } + } + else + { + for(i=0;i<=n-1;i++) + { + for(j=i+1;j<=n-1;j++) + { + aeffective[i].Set(j,aeffective[j][i]); + aeffective[j].Set(i,0); + } + } + } + } + //--- Prepare task,solve,compare + for(i=0;i<=n-1;i++) + xe[i]=2*CMath::RandomReal()-1; + for(i=0;i<=n-1;i++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=aeffective[i][i_]*xe[i_]; + b[i]=v; + } + //--- function call + CTrLinSolve::RMatrixTrSafeSolve(aparam,n,b,s,isupper,istrans,isunit); + //--- calculation + for(i_=0;i_<=n-1;i_++) + xe[i_]=s*xe[i_]; + for(i_=0;i_<=n-1;i_++) + xe[i_]=xe[i_]-b[i_]; + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=xe[i_]*xe[i_]; + v=MathSqrt(v); + //--- search errors + waserrors=waserrors || v>threshold; + } + } + } + } + } + } +//--- report + if(!silent) + { + Print("TESTING RMatrixTrSafeSolve"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Copy | +//+------------------------------------------------------------------+ +static void CTestTrLinSolveUnit::MakeACopy(CMatrixDouble &a,const int m, + const int n,CMatrixDouble &b) + { +//--- create variables + int i=0; + int j=0; +//--- allocation + b.Resize(m,n); +//--- copy + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + b[i].Set(j,a[i][j]); + } + } +//+------------------------------------------------------------------+ +//| Testing class CSafeSolve | +//+------------------------------------------------------------------+ +class CTestSafeSolveUnit + { +private: + //--- private methods + static void RMatrixMakeACopy(CMatrixDouble &a,const int m,const int n,CMatrixDouble &b); + static void CMatrixMakeACopy(CMatrixComplex &a,const int m,const int n,CMatrixComplex &b); +public: + //--- constructor, destructor + CTestSafeSolveUnit(void); + ~CTestSafeSolveUnit(void); + //--- public method + static bool TestSafeSolve(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestSafeSolveUnit::CTestSafeSolveUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestSafeSolveUnit::~CTestSafeSolveUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Main unittest subroutine | +//+------------------------------------------------------------------+ +static bool CTestSafeSolveUnit::TestSafeSolve(const bool silent) + { +//--- create variables + int maxmn=0; + double threshold=0; + bool rerrors; + bool cerrors; + bool waserrors; + bool isupper; + int trans=0; + bool isunit; + double scalea=0; + double growth=0; + int i=0; + int j=0; + int n=0; + int j1=0; + int j2=0; + complex cv=0; + double rv=0; + int i_=0; +//--- create arrays + complex cxs[]; + complex cxe[]; + double rxs[]; + double rxe[]; +//--- create matrix + CMatrixComplex ca; + CMatrixComplex cea; + CMatrixComplex ctmpa; + CMatrixDouble ra; + CMatrixDouble rea; + CMatrixDouble rtmpa; +//--- initialization + maxmn=30; + threshold=100000*CMath::m_machineepsilon; + rerrors=false; + cerrors=false; + waserrors=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=CMath::RandomReal()>0.5; + trans=CMath::RandomInteger(3); + isunit=CMath::RandomReal()>0.5; + scalea=CMath::RandomReal()+0.5; + //--- allocation + ca.Resize(n,n); + //--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(i==j) + { + ca[i].SetRe(j,(2*CMath::RandomInteger(2)-1)*(5+CMath::RandomReal())); + ca[i].SetIm(j,(2*CMath::RandomInteger(2)-1)*(5+CMath::RandomReal())); + } + else + { + ca[i].SetRe(j,0.2*CMath::RandomReal()-0.1); + ca[i].SetIm(j,0.2*CMath::RandomReal()-0.1); + } + } + } + //--- function call + CMatrixMakeACopy(ca,n,n,ctmpa); + for(i=0;i<=n-1;i++) + { + //--- check + if(isupper) + { + j1=0; + j2=i-1; + } + else + { + j1=i+1; + j2=n-1; + } + for(j=j1;j<=j2;j++) + ctmpa[i].Set(j,0); + //--- check + if(isunit) + ctmpa[i].Set(i,1); + } + //--- allocation + cea.Resize(n,n); + for(i=0;i<=n-1;i++) + { + //--- check + if(trans==0) + { + for(i_=0;i_<=n-1;i_++) + cea[i].Set(i_,ctmpa[i][i_]*scalea); + } + //--- check + if(trans==1) + { + for(i_=0;i_<=n-1;i_++) + cea[i_].Set(i,ctmpa[i][i_]*scalea); + } + //--- check + if(trans==2) + { + for(i_=0;i_<=n-1;i_++) + cea[i_].Set(i,CMath::Conj(ctmpa[i][i_])*scalea); + } + } + //--- allocation + ArrayResize(cxe,n); + //--- change values + for(i=0;i<=n-1;i++) + { + cxe[i].re=2*CMath::RandomReal()-1; + cxe[i].im=2*CMath::RandomReal()-1; + } + //--- allocation + ArrayResize(cxs,n); + for(i=0;i<=n-1;i++) + { + //--- change value + cv=0.0; + for(i_=0;i_<=n-1;i_++) + cv+=cea[i][i_]*cxe[i_]; + cxs[i]=cv; + } + //--- check + if(CSafeSolve::CMatrixScaledTrSafeSolve(ca,scalea,n,cxs,isupper,trans,isunit,MathSqrt(CMath::m_maxrealnumber))) + { + for(i=0;i<=n-1;i++) + cerrors=cerrors || CMath::AbsComplex(cxs[i]-cxe[i])>threshold; + } + else + cerrors=true; + //--- same with real + isupper=CMath::RandomReal()>0.5; + trans=CMath::RandomInteger(2); + isunit=CMath::RandomReal()>0.5; + scalea=CMath::RandomReal()+0.5; + //--- allocation + ra.Resize(n,n); + //--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(i==j) + ra[i].Set(j,(2*CMath::RandomInteger(2)-1)*(5+CMath::RandomReal())); + else + ra[i].Set(j,0.2*CMath::RandomReal()-0.1); + } + } + //--- function call + RMatrixMakeACopy(ra,n,n,rtmpa); + //--- calculation + for(i=0;i<=n-1;i++) + { + //--- check + if(isupper) + { + j1=0; + j2=i-1; + } + else + { + j1=i+1; + j2=n-1; + } + for(j=j1;j<=j2;j++) + rtmpa[i].Set(j,0); + //--- check + if(isunit) + rtmpa[i].Set(i,1); + } + //--- allocation + rea.Resize(n,n); + //--- calculation + for(i=0;i<=n-1;i++) + { + //--- check + if(trans==0) + { + for(i_=0;i_<=n-1;i_++) + rea[i].Set(i_,scalea*rtmpa[i][i_]); + } + //--- check + if(trans==1) + { + for(i_=0;i_<=n-1;i_++) + rea[i_].Set(i,scalea*rtmpa[i][i_]); + } + } + //--- allocation + ArrayResize(rxe,n); + for(i=0;i<=n-1;i++) + rxe[i]=2*CMath::RandomReal()-1; + //--- allocation + ArrayResize(rxs,n); + for(i=0;i<=n-1;i++) + { + //--- change value + rv=0.0; + for(i_=0;i_<=n-1;i_++) + rv+=rea[i][i_]*rxe[i_]; + rxs[i]=rv; + } + //--- check + if(CSafeSolve::RMatrixScaledTrSafeSolve(ra,scalea,n,rxs,isupper,trans,isunit,MathSqrt(CMath::m_maxrealnumber))) + { + for(i=0;i<=n-1;i++) + rerrors=rerrors || MathAbs(rxs[i]-rxe[i])>threshold; + } + else + rerrors=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=10; +//--- allocation + ca.Resize(n,n); +//--- change values + ca[0].Set(0,1); + ca[0].Set(1,0); + ca[1].Set(0,0); + ca[1].Set(1,1/growth); +//--- allocation + ArrayResize(cxs,n); +//--- change values + cxs[0]=1.0; + cxs[1]=0.5; +//--- search errors + cerrors=cerrors || !CSafeSolve::CMatrixScaledTrSafeSolve(ca,1.0,n,cxs,CMath::RandomReal()>0.5,CMath::RandomInteger(3),false,1.05*MathMax(CMath::AbsComplex(cxs[1])*growth,1.0)); + cerrors=cerrors || !CSafeSolve::CMatrixScaledTrSafeSolve(ca,1.0,n,cxs,CMath::RandomReal()>0.5,CMath::RandomInteger(3),false,0.95*MathMax(CMath::AbsComplex(cxs[1])*growth,1.0)); +//--- allocation + ra.Resize(n,n); +//--- change values + ra[0].Set(0,1); + ra[0].Set(1,0); + ra[1].Set(0,0); + ra[1].Set(1,1/growth); +//--- allocation + ArrayResize(rxs,n); +//--- change values + rxs[0]=1.0; + rxs[1]=0.5; +//--- search errors + rerrors=rerrors || !CSafeSolve::RMatrixScaledTrSafeSolve(ra,1.0,n,rxs,CMath::RandomReal()>0.5,CMath::RandomInteger(2),false,1.05*MathMax(MathAbs(rxs[1])*growth,1.0)); + rerrors=rerrors || !CSafeSolve::RMatrixScaledTrSafeSolve(ra,1.0,n,rxs,CMath::RandomReal()>0.5,CMath::RandomInteger(2),false,0.95*MathMax(MathAbs(rxs[1])*growth,1.0)); +//--- 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; + ca.Resize(n,n); +//--- change values + ca[0].Set(0,1); + ca[0].Set(1,0); + ca[1].Set(0,0); + ca[1].Set(1,0); +//--- allocation + ArrayResize(cxs,n); +//--- change values + cxs[0]=1.0; + cxs[1]=0.5; +//--- search errors + cerrors=cerrors || CSafeSolve::CMatrixScaledTrSafeSolve(ca,1.0,n,cxs,CMath::RandomReal()>0.5,CMath::RandomInteger(3),false,MathSqrt(CMath::m_maxrealnumber)); +//--- allocation + ra.Resize(n,n); +//--- change values + ra[0].Set(0,1); + ra[0].Set(1,0); + ra[1].Set(0,0); + ra[1].Set(1,0); +//--- allocation + ArrayResize(rxs,n); +//--- change values + rxs[0]=1.0; + rxs[1]=0.5; +//--- search errors + rerrors=rerrors || CSafeSolve::RMatrixScaledTrSafeSolve(ra,1.0,n,rxs,CMath::RandomReal()>0.5,CMath::RandomInteger(2),false,MathSqrt(CMath::m_maxrealnumber)); +//--- report + waserrors=rerrors || cerrors; +//--- check + if(!silent) + { + Print("TESTING SAFE TR SOLVER"); + Print("REAL: "); + //--- check + if(!rerrors) + Print("OK"); + else + Print("FAILED"); + Print("COMPLEX: "); + //--- check + if(!cerrors) + Print("OK"); + else + Print("FAILED"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Copy | +//+------------------------------------------------------------------+ +static void CTestSafeSolveUnit::RMatrixMakeACopy(CMatrixDouble &a, + const int m,const int n, + CMatrixDouble &b) + { +//--- create variables + int i=0; + int j=0; +//--- allocation + b.Resize(m,n); +//--- copy + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + b[i].Set(j,a[i][j]); + } + } +//+------------------------------------------------------------------+ +//| Copy | +//+------------------------------------------------------------------+ +static void CTestSafeSolveUnit::CMatrixMakeACopy(CMatrixComplex &a, + const int m,const int n, + CMatrixComplex &b) + { +//--- create variables + int i=0; + int j=0; +//--- allocation + b.Resize(m,n); +//--- copy + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + b[i].Set(j,a[i][j]); + } + } +//+------------------------------------------------------------------+ +//| Testing class CRCond | +//+------------------------------------------------------------------+ +class CTestRCondUnit + { +private: + //--- private methods + static void RMatrixMakeACopy(CMatrixDouble &a,const int m,const int n,CMatrixDouble &b); + static void RMatrixDropHalf(CMatrixDouble &a,const int n,const bool droplower); + static void CMatrixDropHalf(CMatrixComplex &a,const int n,const bool droplower); + static void RMatrixGenZero(CMatrixDouble &a0,const int n); + static bool RMatrixInvMatTr(CMatrixDouble &a,const int n,const bool isupper,const bool isunittriangular); + static bool RMatrixInvMatLU(CMatrixDouble &a,int &pivots[],const int n); + static bool RMatrixInvMat(CMatrixDouble &a,const int n); + static void RMatrixRefRCond(CMatrixDouble &a,const int n,double &rc1,double &rcinf); + static void CMatrixMakeACopy(CMatrixComplex &a,const int m,const int n,CMatrixComplex &b); + static void CMatrixGenZero(CMatrixComplex &a0,const int n); + static bool CMatrixInvMatTr(CMatrixComplex &a,const int n,const bool isupper,const bool isunittriangular); + static bool CMatrixInvMatLU(CMatrixComplex &a,int &pivots[],const int n); + static bool CMatrixInvMat(CMatrixComplex &a,const int n); + static void CMatrixRefRCond(CMatrixComplex &a,const int n,double &rc1,double &rcinf); + static bool TestRMatrixTrRCond(const int maxn,const int passcount); + static bool TestCMatrixTrRCond(const int maxn,const int passcount); + static bool TestRMatrixRCond(const int maxn,const int passcount); + static bool TestSPDMatrixRCond(const int maxn,const int passcount); + static bool TestCMatrixRCond(const int maxn,const int passcount); + static bool TestHPDMatrixRCond(const int maxn,const int passcount); +public: + //--- class constants + static const double m_threshold50; + static const double m_threshold90; + //--- constructor, destructor + CTestRCondUnit(void); + ~CTestRCondUnit(void); + //--- public method + static bool TestRCond(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Initialize constants | +//+------------------------------------------------------------------+ +const double CTestRCondUnit::m_threshold50=0.25; +const double CTestRCondUnit::m_threshold90=0.10; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestRCondUnit::CTestRCondUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestRCondUnit::~CTestRCondUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CRCond | +//+------------------------------------------------------------------+ +static bool CTestRCondUnit::TestRCond(const bool silent) + { +//--- create variables + int maxn=0; + int passcount=0; + bool waserrors; + bool rtrerr; + bool ctrerr; + bool rerr; + bool cerr; + bool spderr; + bool hpderr; +//--- initialization + maxn=10; + passcount=100; +//--- report + rtrerr=!TestRMatrixTrRCond(maxn,passcount); + ctrerr=!TestCMatrixTrRCond(maxn,passcount); + rerr=!TestRMatrixRCond(maxn,passcount); + cerr=!TestCMatrixRCond(maxn,passcount); + spderr=!TestSPDMatrixRCond(maxn,passcount); + hpderr=!TestHPDMatrixRCond(maxn,passcount); + waserrors=((((rtrerr || ctrerr) || rerr) || cerr) || spderr) || hpderr; +//--- check + if(!silent) + { + Print("TESTING RCOND"); + Print("REAL TRIANGULAR: "); + //--- check + if(!rtrerr) + Print("OK"); + else + Print("FAILED"); + Print("COMPLEX TRIANGULAR: "); + //--- check + if(!ctrerr) + Print("OK"); + else + Print("FAILED"); + Print("REAL: "); + //--- check + if(!rerr) + Print("OK"); + else + Print("FAILED"); + Print("SPD: "); + //--- check + if(!spderr) + Print("OK"); + else + Print("FAILED"); + Print("HPD: "); + //--- check + if(!hpderr) + Print("OK"); + else + Print("FAILED"); + Print("COMPLEX: "); + //--- check + if(!cerr) + Print("OK"); + else + Print("FAILED"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Copy | +//+------------------------------------------------------------------+ +static void CTestRCondUnit::RMatrixMakeACopy(CMatrixDouble &a,const int m, + const int n,CMatrixDouble &b) + { +//--- create variables + int i=0; + int j=0; +//--- allocation + b.Resize(m,n); +//--- copy + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + b[i].Set(j,a[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 CTestRCondUnit::RMatrixDropHalf(CMatrixDouble &a,const int n, + const bool droplower) + { +//--- create variables + int i=0; + int j=0; +//--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if((droplower && i>j) || (!droplower && ij) || (!droplower && i0) + { + for(i_=0;i_<=j-1;i_++) + t[i_]=a[i_][j]; + for(i=0;i<=j-1;i++) + { + //--- check + if(i=0;j--) + { + //--- check + if(nounit) + { + //--- check + if(a[j][j]==0.0) + { + //--- return result + return(false); + } + a[j].Set(j,1/a[j][j]); + ajj=-a[j][j]; + } + else + ajj=-1; + //--- check + if(jj+1) + { + //--- change value + v=0.0; + for(i_=j+1;i_<=i-1;i_++) + v+=a[i][i_]*t[i_]; + } + else + v=0; + //--- check + if(nounit) + a[i].Set(j,v+a[i][i]*t[i]); + else + a[i].Set(j,v+t[i]); + } + //--- calculation + for(i_=j+1;i_<=n-1;i_++) + a[i_].Set(j,ajj*a[i_][j]); + } + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| LU inverse | +//+------------------------------------------------------------------+ +static bool CTestRCondUnit::RMatrixInvMatLU(CMatrixDouble &a,int &pivots[], + const int n) + { +//--- create variables + bool result; + int i=0; + int j=0; + int jp=0; + double v=0; + int i_=0; +//--- create array + double work[]; +//--- initialization + result=true; +//--- Quick return if possible + if(n==0) + { + //--- return result + return(result); + } +//--- allocation + ArrayResize(work,n); +//--- Form inv(U) + if(!RMatrixInvMatTr(a,n,true,false)) + { + //--- return result + return(false); + } +//--- 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[i]=a[i][j]; + a[i].Set(j,0); + } + //--- Compute current column of inv(A). + if(j=0;j--) + { + jp=pivots[j]; + //--- check + if(jp!=j) + { + for(i_=0;i_<=n-1;i_++) + work[i_]=a[i_][j]; + for(i_=0;i_<=n-1;i_++) + a[i_].Set(j,a[i_][jp]); + for(i_=0;i_<=n-1;i_++) + a[i_].Set(jp,work[i_]); + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Matrix inverse | +//+------------------------------------------------------------------+ +static bool CTestRCondUnit::RMatrixInvMat(CMatrixDouble &a,const int n) + { +//--- create array + int pivots[]; +//--- function call + CTrFac::RMatrixLU(a,n,n,pivots); +//--- return result + return(RMatrixInvMatLU(a,pivots,n)); + } +//+------------------------------------------------------------------+ +//| reference RCond | +//+------------------------------------------------------------------+ +static void CTestRCondUnit::RMatrixRefRCond(CMatrixDouble &a,const int n, + double &rc1,double &rcinf) + { +//--- create variables + double nrm1a=0; + double nrminfa=0; + double nrm1inva=0; + double nrminfinva=0; + double v=0; + int k=0; + int i=0; +//--- create matrix + CMatrixDouble inva; +//--- initialization + rc1=0; + rcinf=0; +//--- inv A + RMatrixMakeACopy(a,n,n,inva); +//--- check + if(!RMatrixInvMat(inva,n)) + { + rc1=0; + rcinf=0; + //--- exit the function + return; + } +//--- norm A + nrm1a=0; + nrminfa=0; +//--- calculation + for(k=0;k<=n-1;k++) + { + //--- change values + v=0; + for(i=0;i<=n-1;i++) + v=v+MathAbs(a[i][k]); + nrm1a=MathMax(nrm1a,v); + v=0; + for(i=0;i<=n-1;i++) + v=v+MathAbs(a[k][i]); + nrminfa=MathMax(nrminfa,v); + } +//--- norm inv A + nrm1inva=0; + nrminfinva=0; +//--- calculation + for(k=0;k<=n-1;k++) + { + //--- change values + v=0; + for(i=0;i<=n-1;i++) + v=v+MathAbs(inva[i][k]); + nrm1inva=MathMax(nrm1inva,v); + v=0; + for(i=0;i<=n-1;i++) + v=v+MathAbs(inva[k][i]); + nrminfinva=MathMax(nrminfinva,v); + } +//--- result + rc1=nrm1inva*nrm1a; + rcinf=nrminfinva*nrminfa; + } +//+------------------------------------------------------------------+ +//| Copy | +//+------------------------------------------------------------------+ +static void CTestRCondUnit::CMatrixMakeACopy(CMatrixComplex &a,const int m, + const int n,CMatrixComplex &b) + { +//--- create variables + int i=0; + int j=0; +//--- allocation + b.Resize(m,n); +//--- copy + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + b[i].Set(j,a[i][j]); + } + } +//+------------------------------------------------------------------+ +//| Generate matrix with given condition number C (2-norm) | +//+------------------------------------------------------------------+ +static void CTestRCondUnit::CMatrixGenZero(CMatrixComplex &a0,const int n) + { +//--- create variables + int i=0; + int j=0; +//--- allocation + a0.Resize(n,n); +//--- copy + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a0[i].Set(j,0); + } + } +//+------------------------------------------------------------------+ +//| triangular inverse | +//+------------------------------------------------------------------+ +static bool CTestRCondUnit::CMatrixInvMatTr(CMatrixComplex &a,const int n, + const bool isupper, + const bool isunittriangular) + { +//--- create variables + bool result; + bool nounit; + int i=0; + int j=0; + complex v=0; + complex ajj=0; + complex one=1; + int i_=0; +//--- create array + complex t[]; +//--- initialization + result=true; +//--- allocation + ArrayResize(t,n); +//--- Test the input parameters. + nounit=!isunittriangular; +//--- check + if(isupper) + { + //--- Compute inverse of upper triangular matrix. + for(j=0;j<=n-1;j++) + { + //--- check + if(nounit) + { + //--- check + if(a[j][j]==0) + { + //--- return result + return(false); + } + a[j].Set(j,one/a[j][j]); + ajj=-a[j][j]; + } + else + ajj=-1; + //--- Compute elements 1:j-1 of j-th column. + if(j>0) + { + for(i_=0;i_<=j-1;i_++) + t[i_]=a[i_][j]; + //--- calculation + for(i=0;i<=j-1;i++) + { + //--- check + if(i=0;j--) + { + //--- check + if(nounit) + { + //--- check + if(a[j][j]==0) + { + //--- return result + return(false); + } + a[j].Set(j,one/a[j][j]); + ajj=-a[j][j]; + } + else + ajj=-1; + //--- check + if(jj+1) + { + //--- change value + v=0.0; + for(i_=j+1;i_<=i-1;i_++) + v+=a[i][i_]*t[i_]; + } + else + v=0; + //--- check + if(nounit) + a[i].Set(j,v+a[i][i]*t[i]); + else + a[i].Set(j,v+t[i]); + } + for(i_=j+1;i_<=n-1;i_++) + a[i_].Set(j,ajj*a[i_][j]); + } + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| LU inverse | +//+------------------------------------------------------------------+ +static bool CTestRCondUnit::CMatrixInvMatLU(CMatrixComplex &a,int &pivots[], + const int n) + { +//--- create variables + bool result; + int i=0; + int j=0; + int jp=0; + complex v=0; + int i_=0; +//--- create array + complex work[]; +//--- initialization + result=true; +//--- Quick return if possible + if(n==0) + { + //--- return result + return(result); + } +//--- allocation + ArrayResize(work,n); +//--- Form inv(U) + if(!CMatrixInvMatTr(a,n,true,false)) + { + //--- return result + return(false); + } +//--- 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[i]=a[i][j]; + a[i].Set(j,0); + } + //--- Compute current column of inv(A). + if(j=0;j--) + { + jp=pivots[j]; + //--- check + if(jp!=j) + { + //--- change values + for(i_=0;i_<=n-1;i_++) + work[i_]=a[i_][j]; + for(i_=0;i_<=n-1;i_++) + a[i_].Set(j,a[i_][jp]); + for(i_=0;i_<=n-1;i_++) + a[i_].Set(jp,work[i_]); + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Matrix inverse | +//+------------------------------------------------------------------+ +static bool CTestRCondUnit::CMatrixInvMat(CMatrixComplex &a,const int n) + { +//--- create array + int pivots[]; +//--- function call + CTrFac::CMatrixLU(a,n,n,pivots); +//--- return result + return(CMatrixInvMatLU(a,pivots,n)); + } +//+------------------------------------------------------------------+ +//| reference RCond | +//+------------------------------------------------------------------+ +static void CTestRCondUnit::CMatrixRefRCond(CMatrixComplex &a,const int n, + double &rc1,double &rcinf) + { +//--- create variables + double nrm1a=0; + double nrminfa=0; + double nrm1inva=0; + double nrminfinva=0; + double v=0; + int k=0; + int i=0; +//--- create matrix + CMatrixComplex inva; +//--- initialization + rc1=0; + rcinf=0; +//--- inv A + CMatrixMakeACopy(a,n,n,inva); +//--- check + if(!CMatrixInvMat(inva,n)) + { + rc1=0; + rcinf=0; + //--- exit the function + return; + } +//--- norm A + nrm1a=0; + nrminfa=0; +//--- calculation + for(k=0;k<=n-1;k++) + { + v=0; + for(i=0;i<=n-1;i++) + v=v+CMath::AbsComplex(a[i][k]); + nrm1a=MathMax(nrm1a,v); + //--- change value + v=0; + for(i=0;i<=n-1;i++) + v=v+CMath::AbsComplex(a[k][i]); + nrminfa=MathMax(nrminfa,v); + } +//--- norm inv A + nrm1inva=0; + nrminfinva=0; +//--- calculation + for(k=0;k<=n-1;k++) + { + v=0; + for(i=0;i<=n-1;i++) + v=v+CMath::AbsComplex(inva[i][k]); + nrm1inva=MathMax(nrm1inva,v); + //--- change value + v=0; + for(i=0;i<=n-1;i++) + v=v+CMath::AbsComplex(inva[k][i]); + nrminfinva=MathMax(nrminfinva,v); + } +//--- result + rc1=nrm1inva*nrm1a; + rcinf=nrminfinva*nrminfa; + } +//+------------------------------------------------------------------+ +//| Returns True for successful test,False - for failed test | +//+------------------------------------------------------------------+ +static bool CTestRCondUnit::TestRMatrixTrRCond(const int maxn,const int passcount) + { +//--- create variables + bool result; + int n=0; + int i=0; + int j=0; + int j1=0; + int j2=0; + int pass=0; + bool err50; + bool err90; + bool errspec; + bool errless; + double erc1=0; + double ercinf=0; + double v=0; + bool isupper; + bool isunit; +//--- create arrays + int p[]; + double q50[]; + double q90[]; +//--- create matrix + CMatrixDouble a; + CMatrixDouble ea; +//--- initialization + err50=false; + err90=false; + errless=false; + errspec=false; +//--- allocation + ArrayResize(q50,2); + ArrayResize(q90,2); +//--- calculation + for(n=1;n<=maxn;n++) + { + //--- special test for zero matrix + RMatrixGenZero(a,n); + //--- search errors + errspec=errspec || CRCond::RMatrixTrRCond1(a,n,CMath::RandomReal()>0.5,false)!=0.0; + errspec=errspec || CRCond::RMatrixTrRCondInf(a,n,CMath::RandomReal()>0.5,false)!=0.0; + //--- general test + a.Resize(n,n); + for(i=0;i<=1;i++) + { + q50[i]=0; + q90[i]=0; + } + //--- calculation + for(pass=1;pass<=passcount;pass++) + { + //--- change values + isupper=CMath::RandomReal()>0.5; + isunit=CMath::RandomReal()>0.5; + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,CMath::RandomReal()-0.5); + } + for(i=0;i<=n-1;i++) + a[i].Set(i,1+CMath::RandomReal()); + //--- function call + RMatrixMakeACopy(a,n,n,ea); + for(i=0;i<=n-1;i++) + { + //--- check + if(isupper) + { + j1=0; + j2=i-1; + } + else + { + j1=i+1; + j2=n-1; + } + //--- change values + for(j=j1;j<=j2;j++) + ea[i].Set(j,0); + //--- check + if(isunit) + ea[i].Set(i,1); + } + //--- function call + RMatrixRefRCond(ea,n,erc1,ercinf); + //--- 1-norm + v=1/CRCond::RMatrixTrRCond1(a,n,isupper,isunit); + //--- check + if(v>=m_threshold50*erc1) + q50[0]=q50[0]+1.0/(double)passcount; + //--- check + if(v>=m_threshold90*erc1) + q90[0]=q90[0]+1.0/(double)passcount; + //--- search errors + errless=errless || v>erc1*1.001; + //--- Inf-norm + v=1/CRCond::RMatrixTrRCondInf(a,n,isupper,isunit); + //--- check + if(v>=m_threshold50*ercinf) + q50[1]=q50[1]+1.0/(double)passcount; + //--- check + if(v>=(double)(m_threshold90*ercinf)) + q90[1]=q90[1]+1.0/(double)passcount; + //--- search errors + errless=errless || v>ercinf*1.001; + } + //--- search errors + for(i=0;i<=1;i++) + { + err50=err50 || q50[i]<0.5; + err90=err90 || q90[i]<0.9; + } + //--- degenerate matrix test + if(n>=3) + { + //--- allocation + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,0.0); + } + a[0].Set(0,1); + a[n-1].Set(n-1,1); + //--- search errors + errspec=errspec || CRCond::RMatrixTrRCond1(a,n,CMath::RandomReal()>0.5,false)!=0.0; + errspec=errspec || CRCond::RMatrixTrRCondInf(a,n,CMath::RandomReal()>0.5,false)!=0.0; + } + //--- near-degenerate matrix test + if(n>=2) + { + //--- allocation + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,0.0); + } + //--- change values + for(i=0;i<=n-1;i++) + a[i].Set(i,1); + i=CMath::RandomInteger(n); + a[i].Set(i,0.1*CMath::m_maxrealnumber); + //--- search errors + errspec=errspec || CRCond::RMatrixTrRCond1(a,n,CMath::RandomReal()>0.5,false)!=0.0; + errspec=errspec || CRCond::RMatrixTrRCondInf(a,n,CMath::RandomReal()>0.5,false)!=0.0; + } + } +//--- report + result=!(((err50 || err90) || errless) || errspec); +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Returns True for successful test,False - for failed test | +//+------------------------------------------------------------------+ +static bool CTestRCondUnit::TestCMatrixTrRCond(const int maxn,const int passcount) + { +//--- create variables + bool result; + int n=0; + int i=0; + int j=0; + int j1=0; + int j2=0; + int pass=0; + bool err50; + bool err90; + bool errspec; + bool errless; + double erc1=0; + double ercinf=0; + double v=0; + bool isupper; + bool isunit; +//--- create arrays + int p[]; + double q50[]; + double q90[]; +//--- create matrix + CMatrixComplex a; + CMatrixComplex ea; +//--- initialization + err50=false; + err90=false; + errless=false; + errspec=false; +//--- allocation + ArrayResize(q50,2); + ArrayResize(q90,2); +//--- calculation + for(n=1;n<=maxn;n++) + { + //--- special test for zero matrix + CMatrixGenZero(a,n); + //--- search errors + errspec=errspec || CRCond::CMatrixTrRCond1(a,n,CMath::RandomReal()>0.5,false)!=0.0; + errspec=errspec || CRCond::CMatrixTrRCondInf(a,n,CMath::RandomReal()>0.5,false)!=0.0; + //--- general test + a.Resize(n,n); + for(i=0;i<=1;i++) + { + q50[i]=0; + q90[i]=0; + } + //--- calculation + for(pass=1;pass<=passcount;pass++) + { + //--- change values + isupper=CMath::RandomReal()>0.5; + isunit=CMath::RandomReal()>0.5; + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + a[i].SetRe(j,CMath::RandomReal()-0.5); + a[i].SetIm(j,CMath::RandomReal()-0.5); + } + } + //--- change values + for(i=0;i<=n-1;i++) + { + a[i].SetRe(i,1+CMath::RandomReal()); + a[i].SetIm(i,1+CMath::RandomReal()); + } + //--- function call + CMatrixMakeACopy(a,n,n,ea); + //--- change values + for(i=0;i<=n-1;i++) + { + //--- check + if(isupper) + { + j1=0; + j2=i-1; + } + else + { + j1=i+1; + j2=n-1; + } + for(j=j1;j<=j2;j++) + ea[i].Set(j,0); + //--- check + if(isunit) + ea[i].Set(i,1); + } + //--- function call + CMatrixRefRCond(ea,n,erc1,ercinf); + //--- 1-norm + v=1/CRCond::CMatrixTrRCond1(a,n,isupper,isunit); + if(v>=m_threshold50*erc1) + q50[0]=q50[0]+1.0/(double)passcount; + //--- check + if(v>=(double)(m_threshold90*erc1)) + q90[0]=q90[0]+1.0/(double)passcount; + //--- search errors + errless=errless || v>(double)(erc1*1.001); + //--- Inf-norm + v=1/CRCond::CMatrixTrRCondInf(a,n,isupper,isunit); + //--- check + if(v>=m_threshold50*ercinf) + q50[1]=q50[1]+1.0/(double)passcount; + //--- check + if(v>=(double)(m_threshold90*ercinf)) + q90[1]=q90[1]+1.0/(double)passcount; + //--- search errors + errless=errless || v>(double)(ercinf*1.001); + } + //--- search errors + for(i=0;i<=1;i++) + { + err50=err50 || q50[i]<0.5; + err90=err90 || q90[i]<0.9; + } + //--- degenerate matrix test + if(n>=3) + { + //--- allocation + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,0.0); + } + a[0].Set(0,1); + a[n-1].Set(n-1,1); + //--- search errors + errspec=errspec || CRCond::CMatrixTrRCond1(a,n,CMath::RandomReal()>0.5,false)!=0.0; + errspec=errspec || CRCond::CMatrixTrRCondInf(a,n,CMath::RandomReal()>0.5,false)!=0.0; + } + //--- near-degenerate matrix test + if(n>=2) + { + //--- allocation + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,0.0); + } + //--- change values + for(i=0;i<=n-1;i++) + a[i].Set(i,1); + i=CMath::RandomInteger(n); + a[i].Set(i,0.1*CMath::m_maxrealnumber); + //--- search errors + errspec=errspec || CRCond::CMatrixTrRCond1(a,n,CMath::RandomReal()>0.5,false)!=0.0; + errspec=errspec || CRCond::CMatrixTrRCondInf(a,n,CMath::RandomReal()>0.5,false)!=0.0; + } + } +//--- report + result=!(((err50 || err90) || errless) || errspec); +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Returns True for successful test,False - for failed test | +//+------------------------------------------------------------------+ +static bool CTestRCondUnit::TestRMatrixRCond(const int maxn,const int passcount) + { +//--- create variables + bool result; + int n=0; + int i=0; + int j=0; + int pass=0; + bool err50; + bool err90; + bool errspec; + bool errless; + double erc1=0; + double ercinf=0; + double v=0; +//--- create array + int p[]; + double q50[]; + double q90[]; +//--- create matrix + CMatrixDouble a; + CMatrixDouble lua; +//--- initialization + err50=false; + err90=false; + errless=false; + errspec=false; +//--- allocation + ArrayResize(q50,4); + ArrayResize(q90,4); +//--- calculation + for(n=1;n<=maxn;n++) + { + //--- special test for zero matrix + RMatrixGenZero(a,n); + RMatrixMakeACopy(a,n,n,lua); + CTrFac::RMatrixLU(lua,n,n,p); + //--- search errors + errspec=errspec || CRCond::RMatrixRCond1(a,n)!=0.0; + errspec=errspec || CRCond::RMatrixRCondInf(a,n)!=0.0; + errspec=errspec || CRCond::RMatrixLURCond1(lua,n)!=0.0; + errspec=errspec || CRCond::RMatrixLURCondInf(lua,n)!=0.0; + //--- general test + a.Resize(n,n); + for(i=0;i<=3;i++) + { + q50[i]=0; + q90[i]=0; + } + //--- calculation + for(pass=1;pass<=passcount;pass++) + { + //--- function call + CMatGen::RMatrixRndCond(n,MathExp(CMath::RandomReal()*MathLog(1000)),a); + RMatrixMakeACopy(a,n,n,lua); + CTrFac::RMatrixLU(lua,n,n,p); + RMatrixRefRCond(a,n,erc1,ercinf); + //--- 1-norm,normal + v=1/CRCond::RMatrixRCond1(a,n); + //--- check + if(v>=m_threshold50*erc1) + q50[0]=q50[0]+1.0/(double)passcount; + //--- check + if(v>=m_threshold90*erc1) + q90[0]=q90[0]+1.0/(double)passcount; + //--- search errors + errless=errless || v>(double)(erc1*1.001); + //--- 1-norm,LU + v=1/CRCond::RMatrixLURCond1(lua,n); + //--- check + if(v>=m_threshold50*erc1) + q50[1]=q50[1]+1.0/(double)passcount; + //--- check + if(v>=m_threshold90*erc1) + q90[1]=q90[1]+1.0/(double)passcount; + //--- search errors + errless=errless || v>erc1*1.001; + //--- Inf-norm,normal + v=1/CRCond::RMatrixRCondInf(a,n); + //--- check + if(v>=m_threshold50*ercinf) + q50[2]=q50[2]+1.0/(double)passcount; + //--- check + if(v>=m_threshold90*ercinf) + q90[2]=q90[2]+1.0/(double)passcount; + //--- search errors + errless=errless || v>ercinf*1.001; + //--- Inf-norm,LU + v=1/CRCond::RMatrixLURCondInf(lua,n); + //--- check + if(v>=m_threshold50*ercinf) + q50[3]=q50[3]+1.0/(double)passcount; + //--- check + if(v>=m_threshold90*ercinf) + q90[3]=q90[3]+1.0/(double)passcount; + //--- search errors + errless=errless || v>ercinf*1.001; + } + //--- search errors + for(i=0;i<=3;i++) + { + err50=err50 || q50[i]<0.5; + err90=err90 || q90[i]<0.9; + } + //--- degenerate matrix test + if(n>=3) + { + //--- allocation + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,0.0); + } + a[0].Set(0,1); + a[n-1].Set(n-1,1); + //--- search errors + errspec=errspec || CRCond::RMatrixRCond1(a,n)!=0.0; + errspec=errspec || CRCond::RMatrixRCondInf(a,n)!=0.0; + errspec=errspec || CRCond::RMatrixLURCond1(a,n)!=0.0; + errspec=errspec || CRCond::RMatrixLURCondInf(a,n)!=0.0; + } + //--- near-degenerate matrix test + if(n>=2) + { + //--- allocation + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,0.0); + } + //--- change values + for(i=0;i<=n-1;i++) + a[i].Set(i,1); + i=CMath::RandomInteger(n); + a[i].Set(i,0.1*CMath::m_maxrealnumber); + //--- search errors + errspec=errspec || CRCond::RMatrixRCond1(a,n)!=0.0; + errspec=errspec || CRCond::RMatrixRCondInf(a,n)!=0.0; + errspec=errspec || CRCond::RMatrixLURCond1(a,n)!=0.0; + errspec=errspec || CRCond::RMatrixLURCondInf(a,n)!=0.0; + } + } +//--- report + result=!(((err50 || err90) || errless) || errspec); +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Returns True for successful test,False - for failed test | +//+------------------------------------------------------------------+ +static bool CTestRCondUnit::TestSPDMatrixRCond(const int maxn,const int passcount) + { +//--- create variables + bool result; + int n=0; + int i=0; + int j=0; + int pass=0; + bool err50; + bool err90; + bool errspec; + bool errless; + bool isupper; + double erc1=0; + double ercinf=0; + double v=0; +//--- create arrays + int p[]; + double q50[]; + double q90[]; +//--- create matrix + CMatrixDouble a; + CMatrixDouble cha; +//--- initialization + err50=false; + err90=false; + errless=false; + errspec=false; +//--- allocation + ArrayResize(q50,2); + ArrayResize(q90,2); +//--- calculation + for(n=1;n<=maxn;n++) + { + isupper=CMath::RandomReal()>0.5; + //--- general test + a.Resize(n,n); + for(i=0;i<=1;i++) + { + q50[i]=0; + q90[i]=0; + } + //--- calculation + for(pass=1;pass<=passcount;pass++) + { + //--- function calls + CMatGen::SPDMatrixRndCond(n,MathExp(CMath::RandomReal()*MathLog(1000)),a); + RMatrixRefRCond(a,n,erc1,ercinf); + RMatrixDropHalf(a,n,isupper); + RMatrixMakeACopy(a,n,n,cha); + CTrFac::SPDMatrixCholesky(cha,n,isupper); + //--- normal + v=1/CRCond::SPDMatrixRCond(a,n,isupper); + //--- check + if(v>=m_threshold50*erc1) + q50[0]=q50[0]+1.0/(double)passcount; + //--- check + if(v>=m_threshold90*erc1) + q90[0]=q90[0]+1.0/(double)passcount; + //--- search errors + errless=errless || v>erc1*1.001; + //--- Cholesky + v=1/CRCond::SPDMatrixCholeskyRCond(cha,n,isupper); + if(v>=m_threshold50*erc1) + q50[1]=q50[1]+1.0/(double)passcount; + //--- check + if(v>=m_threshold90*erc1) + q90[1]=q90[1]+1.0/(double)passcount; + //--- search errors + errless=errless || v>erc1*1.001; + } + //--- search errors + for(i=0;i<=1;i++) + { + err50=err50 || q50[i]<0.5; + err90=err90 || q90[i]<0.9; + } + //--- degenerate matrix test + if(n>=3) + { + //--- allocation + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,0.0); + } + a[0].Set(0,1); + a[n-1].Set(n-1,1); + //--- search errors + errspec=errspec || CRCond::SPDMatrixRCond(a,n,isupper)!=-1.0; + errspec=errspec || CRCond::SPDMatrixCholeskyRCond(a,n,isupper)!=0.0; + } + //--- near-degenerate matrix test + if(n>=2) + { + //--- allocation + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,0.0); + } + //--- change values + for(i=0;i<=n-1;i++) + a[i].Set(i,1); + i=CMath::RandomInteger(n); + a[i].Set(i,0.1*CMath::m_maxrealnumber); + //--- search errors + errspec=errspec || CRCond::SPDMatrixRCond(a,n,isupper)!=0.0; + errspec=errspec || CRCond::SPDMatrixCholeskyRCond(a,n,isupper)!=0.0; + } + } +//--- report + result=!(((err50 || err90) || errless) || errspec); +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Returns True for successful test,False - for failed test | +//+------------------------------------------------------------------+ +static bool CTestRCondUnit::TestCMatrixRCond(const int maxn,const int passcount) + { +//--- create variables + bool result; + int n=0; + int i=0; + int j=0; + int pass=0; + bool err50; + bool err90; + bool errless; + bool errspec; + double erc1=0; + double ercinf=0; + double v=0; +//--- create arrays + int p[]; + double q50[]; + double q90[]; +//--- create matrix + CMatrixComplex a; + CMatrixComplex lua; +//--- allocation + ArrayResize(q50,4); + ArrayResize(q90,4); +//--- initialization + err50=false; + err90=false; + errless=false; + errspec=false; +//--- process + for(n=1;n<=maxn;n++) + { + //--- special test for zero matrix + CMatrixGenZero(a,n); + CMatrixMakeACopy(a,n,n,lua); + CTrFac::CMatrixLU(lua,n,n,p); + //--- search errors + errspec=errspec || CRCond::CMatrixRCond1(a,n)!=0.0; + errspec=errspec || CRCond::CMatrixRCondInf(a,n)!=0.0; + errspec=errspec || CRCond::CMatrixLURCond1(lua,n)!=0.0; + errspec=errspec || CRCond::CMatrixLURCondInf(lua,n)!=0.0; + //--- general test + a.Resize(n,n); + for(i=0;i<=3;i++) + { + q50[i]=0; + q90[i]=0; + } + //--- calculation + for(pass=1;pass<=passcount;pass++) + { + //--- function calls + CMatGen::CMatrixRndCond(n,MathExp(CMath::RandomReal()*MathLog(1000)),a); + CMatrixMakeACopy(a,n,n,lua); + CTrFac::CMatrixLU(lua,n,n,p); + CMatrixRefRCond(a,n,erc1,ercinf); + //--- 1-norm,normal + v=1/CRCond::CMatrixRCond1(a,n); + //--- check + if(v>=m_threshold50*erc1) + q50[0]=q50[0]+1.0/(double)passcount; + //--- check + if(v>=m_threshold90*erc1) + q90[0]=q90[0]+1.0/(double)passcount; + //--- search errors + errless=errless || v>erc1*1.001; + //--- 1-norm,LU + v=1/CRCond::CMatrixLURCond1(lua,n); + //--- check + if(v>=m_threshold50*erc1) + q50[1]=q50[1]+1.0/(double)passcount; + //--- check + if(v>=m_threshold90*erc1) + q90[1]=q90[1]+1.0/(double)passcount; + //--- search errors + errless=errless || v>erc1*1.001; + //--- Inf-norm,normal + v=1/CRCond::CMatrixRCondInf(a,n); + //--- check + if(v>=m_threshold50*ercinf) + q50[2]=q50[2]+1.0/(double)passcount; + //--- check + if(v>=m_threshold90*ercinf) + q90[2]=q90[2]+1.0/(double)passcount; + //--- search errors + errless=errless || v>ercinf*1.001; + //--- Inf-norm,LU + v=1/CRCond::CMatrixLURCondInf(lua,n); + //--- check + if(v>=m_threshold50*ercinf) + q50[3]=q50[3]+1.0/(double)passcount; + //--- check + if(v>=m_threshold90*ercinf) + q90[3]=q90[3]+1.0/(double)passcount; + //--- search errors + errless=errless || v>ercinf*1.001; + } + //--- search errors + for(i=0;i<=3;i++) + { + err50=err50 || q50[i]<0.5; + err90=err90 || q90[i]<0.9; + } + //--- degenerate matrix test + if(n>=3) + { + //--- allocation + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,0.0); + } + a[0].Set(0,1); + a[n-1].Set(n-1,1); + //--- search errors + errspec=errspec || CRCond::CMatrixRCond1(a,n)!=0.0; + errspec=errspec || CRCond::CMatrixRCondInf(a,n)!=0.0; + errspec=errspec || CRCond::CMatrixLURCond1(a,n)!=0.0; + errspec=errspec || CRCond::CMatrixLURCondInf(a,n)!=0.0; + } + //--- near-degenerate matrix test + if(n>=2) + { + //--- allocation + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,0.0); + } + //--- change values + for(i=0;i<=n-1;i++) + a[i].Set(i,1); + i=CMath::RandomInteger(n); + a[i].Set(i,0.1*CMath::m_maxrealnumber); + //--- search errors + errspec=errspec || CRCond::CMatrixRCond1(a,n)!=0.0; + errspec=errspec || CRCond::CMatrixRCondInf(a,n)!=0.0; + errspec=errspec || CRCond::CMatrixLURCond1(a,n)!=0.0; + errspec=errspec || CRCond::CMatrixLURCondInf(a,n)!=0.0; + } + } +//--- report + result=!(((err50 || err90) || errless) || errspec); +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Returns True for successful test,False - for failed test | +//+------------------------------------------------------------------+ +static bool CTestRCondUnit::TestHPDMatrixRCond(const int maxn,const int passcount) + { +//--- create variables + bool result; + int n=0; + int i=0; + int j=0; + int pass=0; + bool err50; + bool err90; + bool errspec; + bool errless; + bool isupper; + double erc1=0; + double ercinf=0; + double v=0; +//--- create arrays + int p[]; + double q50[]; + double q90[]; +//--- create matrix + CMatrixComplex a; + CMatrixComplex cha; +//--- initialization + err50=false; + err90=false; + errless=false; + errspec=false; +//--- allocation + ArrayResize(q50,2); + ArrayResize(q90,2); + for(n=1;n<=maxn;n++) + { + isupper=CMath::RandomReal()>0.5; + //--- general test + a.Resize(n,n); + for(i=0;i<=1;i++) + { + q50[i]=0; + q90[i]=0; + } + //--- calculation + for(pass=1;pass<=passcount;pass++) + { + //--- function calls + CMatGen::HPDMatrixRndCond(n,MathExp(CMath::RandomReal()*MathLog(1000)),a); + CMatrixRefRCond(a,n,erc1,ercinf); + CMatrixDropHalf(a,n,isupper); + CMatrixMakeACopy(a,n,n,cha); + CTrFac::HPDMatrixCholesky(cha,n,isupper); + //--- normal + v=1/CRCond::HPDMatrixRCond(a,n,isupper); + //--- check + if(v>=m_threshold50*erc1) + q50[0]=q50[0]+1.0/(double)passcount; + //--- check + if(v>=m_threshold90*erc1) + q90[0]=q90[0]+1.0/(double)passcount; + //--- search errors + errless=errless || v>erc1*1.001; + //--- Cholesky + v=1/CRCond::HPDMatrixCholeskyRCond(cha,n,isupper); + //--- check + if(v>=m_threshold50*erc1) + q50[1]=q50[1]+1.0/(double)passcount; + //--- check + if(v>=m_threshold90*erc1) + q90[1]=q90[1]+1.0/(double)passcount; + //--- search errors + errless=errless || v>erc1*1.001; + } + //--- search errors + for(i=0;i<=1;i++) + { + err50=err50 || q50[i]<0.5; + err90=err90 || q90[i]<0.9; + } + //--- degenerate matrix test + if(n>=3) + { + //--- allocation + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,0.0); + } + a[0].Set(0,1); + a[n-1].Set(n-1,1); + //--- search errors + errspec=errspec || CRCond::HPDMatrixRCond(a,n,isupper)!=-1.0; + errspec=errspec || CRCond::HPDMatrixCholeskyRCond(a,n,isupper)!=0.0; + } + //--- near-degenerate matrix test + if(n>=2) + { + //--- allocation + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,0.0); + } + //--- change values + for(i=0;i<=n-1;i++) + a[i].Set(i,1); + i=CMath::RandomInteger(n); + a[i].Set(i,0.1*CMath::m_maxrealnumber); + //--- search errors + errspec=errspec || CRCond::HPDMatrixRCond(a,n,isupper)!=0.0; + errspec=errspec || CRCond::HPDMatrixCholeskyRCond(a,n,isupper)!=0.0; + } + } +//--- report + result=!(((err50 || err90) || errless) || errspec); +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Testing class CMatInv | +//+------------------------------------------------------------------+ +class CTestMatInvUnit + { +private: + //--- private methods + static void RMatrixMakeACopy(CMatrixDouble &a,const int m,const int n,CMatrixDouble &b); + static void CMatrixMakeACopy(CMatrixComplex &a,const int m,const int n,CMatrixComplex &b); + static bool RMatrixCheckInverse(CMatrixDouble &a,CMatrixDouble &inva,const int n,const double threshold,const int info,CMatInvReport &rep); + static bool SPDMatrixCheckInverse(CMatrixDouble &ca,CMatrixDouble &cinva,const bool isupper,const int n,const double threshold,const int info,CMatInvReport &rep); + static bool HPDMatrixCheckInverse(CMatrixComplex &ca,CMatrixComplex &cinva,const bool isupper,const int n,const double threshold,const int info,CMatInvReport &rep); + static bool RMatrixCheckInverseSingular(CMatrixDouble &inva,const int n,const double threshold,const int info,CMatInvReport &rep); + static bool CMatrixCheckInverse(CMatrixComplex &a,CMatrixComplex &inva,const int n,const double threshold,const int info,CMatInvReport &rep); + static bool CMatrixCheckInverseSingular(CMatrixComplex &inva,const int n,const double threshold,const int info,CMatInvReport &rep); + static void RMatrixDropHalf(CMatrixDouble &a,const int n,const bool droplower); + static void CMatrixDropHalf(CMatrixComplex &a,const int n,const bool droplower); + static void TestRTRInv(const int maxn,const int passcount,const double threshold,bool &rtrerrors); + static void TestCTRInv(const int maxn,const int passcount,const double threshold,bool &ctrerrors); + static void TesTrInv(const int maxn,const int passcount,const double threshold,bool &rerrors); + static void TestCInv(const int maxn,const int passcount,const double threshold,bool &cerrors); + static void TestSPDInv(const int maxn,const int passcount,const double threshold,bool &spderrors); + static void TestHPDInv(const int maxn,const int passcount,const double threshold,bool &hpderrors); + static void Unset2D(CMatrixDouble &x); + static void Unset1D(double &x[]); + static void CUnset2D(CMatrixComplex &x); + static void CUnset1D(double &x[]); + static void UnsetRep(CMatInvReport &r); +public: + //--- constructor, destructor + CTestMatInvUnit(void); + ~CTestMatInvUnit(void); + //--- public method + static bool TestMatInv(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestMatInvUnit::CTestMatInvUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestMatInvUnit::~CTestMatInvUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Test | +//+------------------------------------------------------------------+ +static bool CTestMatInvUnit::TestMatInv(const bool silent) + { +//--- create variables + int maxrn=0; + int maxcn=0; + int passcount=0; + double threshold=0; + double rcondtol=0; + bool rtrerrors; + bool ctrerrors; + bool rerrors; + bool cerrors; + bool spderrors; + bool hpderrors; + bool waserrors; +//--- create matrix + CMatrixDouble emptyra; + CMatrixDouble emptyca; +//--- initialization + maxrn=3*CAblas::AblasBlockSize()+1; + maxcn=3*CAblas::AblasBlockSize()+1; + passcount=1; + threshold=10000*CMath::m_machineepsilon; + rcondtol=0.01; + rtrerrors=false; + ctrerrors=false; + rerrors=false; + cerrors=false; + spderrors=false; + hpderrors=false; +//--- function calls + TestRTRInv(maxrn,passcount,threshold,rtrerrors); + TestCTRInv(maxcn,passcount,threshold,ctrerrors); + TesTrInv(maxrn,passcount,threshold,rerrors); + TestSPDInv(maxrn,passcount,threshold,spderrors); + TestCInv(maxcn,passcount,threshold,cerrors); + TestHPDInv(maxcn,passcount,threshold,hpderrors); +//--- search errors + waserrors=((((rtrerrors || ctrerrors) || rerrors) || cerrors) || spderrors) || hpderrors; +//--- check + if(!silent) + { + Print("TESTING MATINV"); + Print("* REAL TRIANGULAR: "); + //--- check + if(rtrerrors) + Print("FAILED"); + else + Print("OK"); + Print("* COMPLEX TRIANGULAR: "); + //--- check + if(ctrerrors) + Print("FAILED"); + else + Print("OK"); + Print("* REAL: "); + //--- check + if(rerrors) + Print("FAILED"); + else + Print("OK"); + Print("* COMPLEX: "); + //--- check + if(cerrors) + Print("FAILED"); + else + Print("OK"); + Print("* SPD: "); + //--- check + if(spderrors) + Print("FAILED"); + else + Print("OK"); + Print("* HPD: "); + //--- check + if(hpderrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Copy | +//+------------------------------------------------------------------+ +static void CTestMatInvUnit::RMatrixMakeACopy(CMatrixDouble &a, + const int m,const int n, + CMatrixDouble &b) + { +//--- create variables + int i=0; + int j=0; +//--- allocation + b.Resize(m,n); +//--- copy + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + b[i].Set(j,a[i][j]); + } + } +//+------------------------------------------------------------------+ +//| Copy | +//+------------------------------------------------------------------+ +static void CTestMatInvUnit::CMatrixMakeACopy(CMatrixComplex &a, + const int m,const int n, + CMatrixComplex &b) + { +//--- create variables + int i=0; + int j=0; +//--- allocation + b.Resize(m,n); +//--- copy + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + b[i].Set(j,a[i][j]); + } + } +//+------------------------------------------------------------------+ +//| Checks whether inverse is correct | +//| Returns True on success. | +//+------------------------------------------------------------------+ +static bool CTestMatInvUnit::RMatrixCheckInverse(CMatrixDouble &a, + CMatrixDouble &inva, + const int n, + const double threshold, + const int info, + CMatInvReport &rep) + { +//--- create variables + bool result; + int i=0; + int j=0; + double v=0; + int i_=0; +//--- initialization + result=true; +//--- check + if(info<=0) + result=false; + else + { + result=result && !(rep.m_r1<100*CMath::m_machineepsilon || rep.m_r1>1+1000*CMath::m_machineepsilon); + result=result && !(rep.m_rinf<100*CMath::m_machineepsilon || rep.m_rinf>1+1000*CMath::m_machineepsilon); + //--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a[i][i_]*inva[i_][j]; + //--- check + if(i==j) + v=v-1; + result=result && MathAbs(v)<=threshold; + } + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Checks whether inverse is correct | +//| Returns True on success. | +//+------------------------------------------------------------------+ +static bool CTestMatInvUnit::SPDMatrixCheckInverse(CMatrixDouble &ca, + CMatrixDouble &cinva, + const bool isupper, + const int n, + const double threshold, + const int info, + CMatInvReport &rep) + { +//--- create variables + bool result; + int i=0; + int j=0; + double v=0; + int i_=0; +//--- create matrix + CMatrixDouble a; + CMatrixDouble inva; +//--- copy + a=ca; + inva=cinva; +//--- calculation + for(i=0;i<=n-2;i++) + { + //--- check + if(isupper) + { + //--- change values + for(i_=i+1;i_<=n-1;i_++) + a[i_].Set(i,a[i][i_]); + for(i_=i+1;i_<=n-1;i_++) + inva[i_].Set(i,inva[i][i_]); + } + else + { + //--- change values + for(i_=i+1;i_<=n-1;i_++) + a[i].Set(i_,a[i_][i]); + for(i_=i+1;i_<=n-1;i_++) + inva[i].Set(i_,inva[i_][i]); + } + } +//--- change value + result=true; +//--- check + if(info<=0) + result=false; + else + { + result=result && !(rep.m_r1<100*CMath::m_machineepsilon || rep.m_r1>1+1000*CMath::m_machineepsilon); + result=result && !(rep.m_rinf<100*CMath::m_machineepsilon || rep.m_rinf>1+1000*CMath::m_machineepsilon); + //--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a[i][i_]*inva[i_][j]; + //--- check + if(i==j) + v=v-1; + result=result && MathAbs(v)<=threshold; + } + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Checks whether inverse is correct | +//| Returns True on success. | +//+------------------------------------------------------------------+ +static bool CTestMatInvUnit::HPDMatrixCheckInverse(CMatrixComplex &ca, + CMatrixComplex &cinva, + const bool isupper, + const int n, + const double threshold, + const int info, + CMatInvReport &rep) + { +//--- create variables + bool result; + int i=0; + int j=0; + complex v=0; + int i_=0; +//--- create matrix + CMatrixComplex a; + CMatrixComplex inva; +//--- copy + a=ca; + inva=cinva; +//--- calculation + for(i=0;i<=n-2;i++) + { + //--- check + if(isupper) + { + //--- change values + for(i_=i+1;i_<=n-1;i_++) + a[i_].Set(i,CMath::Conj(a[i][i_])); + for(i_=i+1;i_<=n-1;i_++) + inva[i_].Set(i,CMath::Conj(inva[i][i_])); + } + else + { + //--- change values + for(i_=i+1;i_<=n-1;i_++) + a[i].Set(i_,CMath::Conj(a[i_][i])); + for(i_=i+1;i_<=n-1;i_++) + inva[i].Set(i_,CMath::Conj(inva[i_][i])); + } + } +//--- change value + result=true; +//--- check + if(info<=0) + result=false; + else + { + result=result && !(rep.m_r1<100*CMath::m_machineepsilon || rep.m_r1>1+1000*CMath::m_machineepsilon); + result=result && !(rep.m_rinf<100*CMath::m_machineepsilon || rep.m_rinf>1+1000*CMath::m_machineepsilon); + //--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a[i][i_]*inva[i_][j]; + //--- check + if(i==j) + v=v-1; + result=result && CMath::AbsComplex(v)<=threshold; + } + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Checks whether inversion result indicate singular matrix | +//| Returns True on success. | +//+------------------------------------------------------------------+ +static bool CTestMatInvUnit::RMatrixCheckInverseSingular(CMatrixDouble &inva, + const int n, + const double threshold, + const int info, + CMatInvReport &rep) + { +//--- create variables + bool result; + int i=0; + int j=0; +//--- initialization + result=true; +//--- check + if(info!=-3 && info!=1) + result=false; + else + { + result=result && !(rep.m_r1<0.0 || rep.m_r1>1000*CMath::m_machineepsilon); + result=result && !(rep.m_rinf<0.0 || rep.m_rinf>1000*CMath::m_machineepsilon); + //--- check + if(info==-3) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + result=result && inva[i][j]==0.0; + } + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Checks whether inverse is correct | +//| Returns True on success. | +//+------------------------------------------------------------------+ +static bool CTestMatInvUnit::CMatrixCheckInverse(CMatrixComplex &a, + CMatrixComplex &inva, + const int n, + const double threshold, + const int info, + CMatInvReport &rep) + { +//--- create variables + bool result; + int i=0; + int j=0; + complex v=0; + int i_=0; +//--- initialization + result=true; +//--- check + if(info<=0) + result=false; + else + { + result=result && !(rep.m_r1<100*CMath::m_machineepsilon || rep.m_r1>1+1000*CMath::m_machineepsilon); + result=result && !(rep.m_rinf<100*CMath::m_machineepsilon || rep.m_rinf>1+1000*CMath::m_machineepsilon); + //--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a[i][i_]*inva[i_][j]; + //--- check + if(i==j) + v=v-1; + result=result && CMath::AbsComplex(v)<=threshold; + } + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Checks whether inversion result indicate singular matrix | +//| Returns True on success. | +//+------------------------------------------------------------------+ +static bool CTestMatInvUnit::CMatrixCheckInverseSingular(CMatrixComplex &inva, + const int n, + const double threshold, + const int info, + CMatInvReport &rep) + { +//--- create variables + bool result; + int i=0; + int j=0; +//--- initialization + result=true; +//--- check + if(info!=-3 && info!=1) + result=false; + else + { + result=result && !(rep.m_r1<0.0 || rep.m_r1>1000*CMath::m_machineepsilon); + result=result && !(rep.m_rinf<0.0 || rep.m_rinf>1000*CMath::m_machineepsilon); + //--- check + if(info==-3) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + result=result && inva[i][j]==0; + } + } + } +//--- return result + 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 CTestMatInvUnit::RMatrixDropHalf(CMatrixDouble &a,const int n, + const bool droplower) + { +//--- create variables + int i=0; + int j=0; +//--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if((droplower && i>j) || (!droplower && ij) || (!droplower && ii && !isupper)) + { + a[i].Set(j,0); + b[i].Set(j,0); + } + } + } + //--- check + if(isunit) + { + for(i=0;i<=n-1;i++) + { + a[i].Set(i,1); + b[i].Set(i,1); + } + } + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a[i][i_]*b[i_][j]; + //--- check + if(j!=i) + rtrerrors=rtrerrors || MathAbs(v)>threshold; + else + rtrerrors=rtrerrors || MathAbs(v-1)>threshold; + } + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Complex TR inverse | +//+------------------------------------------------------------------+ +static void CTestMatInvUnit::TestCTRInv(const int maxn,const int passcount, + const double threshold,bool &ctrerrors) + { +//--- create variables + int n=0; + int pass=0; + int i=0; + int j=0; + int task=0; + bool isupper; + bool isunit; + complex v=0; + bool waserrors; + int info=0; + int i_=0; +//--- create arrays + CMatrixComplex a; + CMatrixComplex b; +//--- object of class + CMatInvReport rep; +//--- initialization + waserrors=false; +//--- Test + for(n=1;n<=maxn;n++) + { + //--- allocation + a.Resize(n,n); + b.Resize(n,n); + //--- calculation + 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++) + { + //--- check + if(i==j) + { + a[i].SetRe(i,1+CMath::RandomReal()); + a[i].SetIm(i,1+CMath::RandomReal()); + } + else + { + a[i].SetRe(j,0.2*CMath::RandomReal()-0.1); + a[i].SetIm(j,0.2*CMath::RandomReal()-0.1); + } + b[i].Set(j,a[i][j]); + } + } + //--- Inverse + CMatInv::CMatrixTrInverse(b,n,isupper,isunit,info,rep); + //--- check + if(info<=0) + { + ctrerrors=true; + return; + } + //--- Structural test + if(isunit) + { + for(i=0;i<=n-1;i++) + ctrerrors=ctrerrors || a[i][i]!=b[i][i]; + } + //--- check + if(isupper) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=i-1;j++) + ctrerrors=ctrerrors || a[i][j]!=b[i][j]; + } + } + else + { + for(i=0;i<=n-1;i++) + { + for(j=i+1;j<=n-1;j++) + ctrerrors=ctrerrors || a[i][j]!=b[i][j]; + } + } + //--- Inverse test + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if((ji && !isupper)) + { + a[i].Set(j,0); + b[i].Set(j,0); + } + } + } + //--- check + if(isunit) + { + for(i=0;i<=n-1;i++) + { + a[i].Set(i,1); + b[i].Set(i,1); + } + } + //--- search errors + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a[i][i_]*b[i_][j]; + //--- check + if(j!=i) + ctrerrors=ctrerrors || CMath::AbsComplex(v)>threshold; + else + ctrerrors=ctrerrors || CMath::AbsComplex(v-1)>threshold; + } + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Real test | +//+------------------------------------------------------------------+ +static void CTestMatInvUnit::TesTrInv(const int maxn,const int passcount, + const double threshold,bool &rerrors) + { +//--- create variables + int i=0; + int j=0; + int k=0; + int n=0; + int pass=0; + int taskkind=0; + int info=0; + int i_=0; +//--- create array + int p[]; +//--- create matrix + CMatrixDouble a; + CMatrixDouble lua; + CMatrixDouble inva; + CMatrixDouble invlua; +//--- object of class + CMatInvReport rep; +//--- General square matrices: +//--- * test general solvers +//--- * test least squares solver + for(pass=1;pass<=passcount;pass++) + { + for(n=1;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 + CMatGen::RMatrixRndCond(n,1000,a); + RMatrixMakeACopy(a,n,n,lua); + CTrFac::RMatrixLU(lua,n,n,p); + RMatrixMakeACopy(a,n,n,inva); + RMatrixMakeACopy(lua,n,n,invlua); + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + CMatInv::RMatrixInverse(inva,n,info,rep); + //--- search errors + rerrors=rerrors || !RMatrixCheckInverse(a,inva,n,threshold,info,rep); + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + CMatInv::RMatrixLUInverse(invlua,p,n,info,rep); + //--- search errors + rerrors=rerrors || !RMatrixCheckInverse(a,invlua,n,threshold,info,rep); + //--- ******************************************************** + //--- 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++) + { + Unset2D(a); + //--- check + if(taskkind==0) + { + //--- all zeros + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,0); + } + } + //--- check + if(taskkind==1) + { + //--- there is zero column + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,2*CMath::RandomReal()-1); + } + //--- change values + k=CMath::RandomInteger(n); + for(i_=0;i_<=n-1;i_++) + a[i_].Set(k,0*a[i_][k]); + } + //--- check + if(taskkind==2) + { + //--- there is zero row + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,2*CMath::RandomReal()-1); + } + //--- change values + k=CMath::RandomInteger(n); + for(i_=0;i_<=n-1;i_++) + a[k].Set(i_,0*a[k][i_]); + } + //--- check + if(taskkind==3) + { + //--- equal columns + if(n<2) + continue; + //--- allocation + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,2*CMath::RandomReal()-1); + } + //--- change values + k=1+CMath::RandomInteger(n-1); + for(i_=0;i_<=n-1;i_++) + a[i_].Set(0,a[i_][k]); + } + //--- check + if(taskkind==4) + { + //--- equal rows + if(n<2) + continue; + //--- allocation + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,2*CMath::RandomReal()-1); + } + //--- change values + k=1+CMath::RandomInteger(n-1); + for(i_=0;i_<=n-1;i_++) + a[0].Set(i_,a[k][i_]); + } + //--- function calls + RMatrixMakeACopy(a,n,n,lua); + CTrFac::RMatrixLU(lua,n,n,p); + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + CMatInv::RMatrixInverse(a,n,info,rep); + //--- search errors + rerrors=rerrors || !RMatrixCheckInverseSingular(a,n,threshold,info,rep); + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + CMatInv::RMatrixLUInverse(lua,p,n,info,rep); + //--- search errors + rerrors=rerrors || !RMatrixCheckInverseSingular(lua,n,threshold,info,rep); + } + } + } + } +//+------------------------------------------------------------------+ +//| Complex test | +//+------------------------------------------------------------------+ +static void CTestMatInvUnit::TestCInv(const int maxn,const int passcount, + const double threshold,bool &cerrors) + { +//--- create variables + int i=0; + int j=0; + int k=0; + int n=0; + int pass=0; + int taskkind=0; + int info=0; + int i_=0; +//--- create array + int p[]; +//--- create matrix + CMatrixComplex a; + CMatrixComplex lua; + CMatrixComplex inva; + CMatrixComplex invlua; +//--- object of class + CMatInvReport rep; +//--- General square matrices: +//--- * test general solvers +//--- * test least squares solver + for(pass=1;pass<=passcount;pass++) + { + for(n=1;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 + CMatGen::CMatrixRndCond(n,1000,a); + CMatrixMakeACopy(a,n,n,lua); + CTrFac::CMatrixLU(lua,n,n,p); + CMatrixMakeACopy(a,n,n,inva); + CMatrixMakeACopy(lua,n,n,invlua); + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + CMatInv::CMatrixInverse(inva,n,info,rep); + //--- search errors + cerrors=cerrors || !CMatrixCheckInverse(a,inva,n,threshold,info,rep); + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + CMatInv::CMatrixLUInverse(invlua,p,n,info,rep); + //--- search errors + cerrors=cerrors || !CMatrixCheckInverse(a,invlua,n,threshold,info,rep); + //--- ******************************************************** + //--- 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++) + { + CUnset2D(a); + //--- check + if(taskkind==0) + { + //--- all zeros + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,0); + } + } + //--- check + if(taskkind==1) + { + //--- there is zero column + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + a[i].SetRe(j,2*CMath::RandomReal()-1); + a[i].SetIm(j,2*CMath::RandomReal()-1); + } + } + //--- change values + k=CMath::RandomInteger(n); + for(i_=0;i_<=n-1;i_++) + a[i_].Set(k,a[i_][k]*0); + } + //--- check + if(taskkind==2) + { + //--- there is zero row + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + a[i].SetRe(j,2*CMath::RandomReal()-1); + a[i].SetIm(j,2*CMath::RandomReal()-1); + } + } + //--- change values + k=CMath::RandomInteger(n); + for(i_=0;i_<=n-1;i_++) + a[k].Set(i_,a[k][i_]*0); + } + //--- check + if(taskkind==3) + { + //--- equal columns + if(n<2) + continue; + //--- allocation + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + a[i].SetRe(j,2*CMath::RandomReal()-1); + a[i].SetIm(j,2*CMath::RandomReal()-1); + } + } + //--- change values + k=1+CMath::RandomInteger(n-1); + for(i_=0;i_<=n-1;i_++) + a[i_].Set(0,a[i_][k]); + } + //--- check + if(taskkind==4) + { + //--- equal rows + if(n<2) + continue; + //--- allocation + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + a[i].SetRe(j,2*CMath::RandomReal()-1); + a[i].SetIm(j,2*CMath::RandomReal()-1); + } + } + //--- change value + k=1+CMath::RandomInteger(n-1); + for(i_=0;i_<=n-1;i_++) + a[0].Set(i_,a[k][i_]); + } + //--- function calls + CMatrixMakeACopy(a,n,n,lua); + CTrFac::CMatrixLU(lua,n,n,p); + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + CMatInv::CMatrixInverse(a,n,info,rep); + //--- search errors + cerrors=cerrors || !CMatrixCheckInverseSingular(a,n,threshold,info,rep); + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + CMatInv::CMatrixLUInverse(lua,p,n,info,rep); + //--- search errors + cerrors=cerrors || !CMatrixCheckInverseSingular(lua,n,threshold,info,rep); + } + } + } + } +//+------------------------------------------------------------------+ +//| SPD test | +//+------------------------------------------------------------------+ +static void CTestMatInvUnit::TestSPDInv(const int maxn,const int passcount, + const double threshold,bool &spderrors) + { +//--- create variables + bool isupper; + int i=0; + int j=0; + int k=0; + int n=0; + int pass=0; + int taskkind=0; + int info=0; + int i_=0; +//--- create matrix + CMatrixDouble a; + CMatrixDouble cha; + CMatrixDouble inva; + CMatrixDouble invcha; +//--- object of class + CMatInvReport rep; +//--- General square matrices: +//--- * test general solvers +//--- * test least squares solver + for(pass=1;pass<=passcount;pass++) + { + for(n=1;n<=maxn;n++) + { + isupper=CMath::RandomReal()>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 + CMatGen::SPDMatrixRndCond(n,1000,a); + RMatrixDropHalf(a,n,isupper); + RMatrixMakeACopy(a,n,n,cha); + //--- check + if(!CTrFac::SPDMatrixCholesky(cha,n,isupper)) + continue; + //--- function calls + RMatrixMakeACopy(a,n,n,inva); + RMatrixMakeACopy(cha,n,n,invcha); + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + CMatInv::SPDMatrixInverse(inva,n,isupper,info,rep); + //--- search errors + spderrors=spderrors || !SPDMatrixCheckInverse(a,inva,isupper,n,threshold,info,rep); + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + CMatInv::SPDMatrixCholeskyInverse(invcha,n,isupper,info,rep); + //--- search errors + spderrors=spderrors || !SPDMatrixCheckInverse(a,invcha,isupper,n,threshold,info,rep); + //--- ******************************************************** + //--- 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++) + { + Unset2D(a); + //--- check + if(taskkind==0) + { + //--- all zeros + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,0); + } + } + //--- check + if(taskkind==1) + { + //--- there is zero column + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,2*CMath::RandomReal()-1); + } + //--- change values + k=CMath::RandomInteger(n); + for(i_=0;i_<=n-1;i_++) + a[i_].Set(k,0*a[i_][k]); + } + //--- check + if(taskkind==2) + { + //--- there is zero row + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,2*CMath::RandomReal()-1); + } + //--- change values + k=CMath::RandomInteger(n); + for(i_=0;i_<=n-1;i_++) + a[k].Set(i_,0*a[k][i_]); + } + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + CMatInv::SPDMatrixCholeskyInverse(a,n,isupper,info,rep); + //--- check + if(info!=-3 && info!=1) + spderrors=true; + else + { + spderrors=(spderrors || rep.m_r1<0.0) || rep.m_r1>1000*CMath::m_machineepsilon; + spderrors=(spderrors || rep.m_rinf<0.0) || rep.m_rinf>1000*CMath::m_machineepsilon; + } + } + } + } + } +//+------------------------------------------------------------------+ +//| HPD test | +//+------------------------------------------------------------------+ +static void CTestMatInvUnit::TestHPDInv(const int maxn,const int passcount, + const double threshold,bool &hpderrors) + { +//--- create variables + bool isupper; + int i=0; + int j=0; + int k=0; + int n=0; + int pass=0; + int taskkind=0; + int info=0; + int i_=0; +//--- create matrix + CMatrixComplex a; + CMatrixComplex cha; + CMatrixComplex inva; + CMatrixComplex invcha; +//--- object of class + CMatInvReport rep; +//--- General square matrices: +//--- * test general solvers +//--- * test least squares solver + for(pass=1;pass<=passcount;pass++) + { + for(n=1;n<=maxn;n++) + { + isupper=CMath::RandomReal()>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 + CMatGen::HPDMatrixRndCond(n,1000,a); + CMatrixDropHalf(a,n,isupper); + CMatrixMakeACopy(a,n,n,cha); + //--- check + if(!CTrFac::HPDMatrixCholesky(cha,n,isupper)) + continue; + //--- function calls + CMatrixMakeACopy(a,n,n,inva); + CMatrixMakeACopy(cha,n,n,invcha); + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + CMatInv::HPDMatrixInverse(inva,n,isupper,info,rep); + //--- search errors + hpderrors=hpderrors || !HPDMatrixCheckInverse(a,inva,isupper,n,threshold,info,rep); + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + CMatInv::HPDMatrixCholeskyInverse(invcha,n,isupper,info,rep); + //--- search errors + hpderrors=hpderrors || !HPDMatrixCheckInverse(a,invcha,isupper,n,threshold,info,rep); + //--- ******************************************************** + //--- 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++) + { + CUnset2D(a); + //--- check + if(taskkind==0) + { + //--- all zeros + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,0); + } + } + //--- check + if(taskkind==1) + { + //--- there is zero column + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + a[i].SetRe(j,2*CMath::RandomReal()-1); + a[i].SetIm(j,2*CMath::RandomReal()-1); + } + } + //--- change values + k=CMath::RandomInteger(n); + for(i_=0;i_<=n-1;i_++) + a[i_].Set(k,a[i_][k]*0); + for(i_=0;i_<=n-1;i_++) + a[k].Set(i_,a[k][i_]*0); + } + //--- check + if(taskkind==2) + { + //--- there is zero row + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + a[i].SetRe(j,2*CMath::RandomReal()-1); + a[i].SetIm(j,2*CMath::RandomReal()-1); + } + } + //--- change values + k=CMath::RandomInteger(n); + for(i_=0;i_<=n-1;i_++) + a[k].Set(i_,a[k][i_]*0); + for(i_=0;i_<=n-1;i_++) + a[i_].Set(k,a[i_][k]*0); + } + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + CMatInv::HPDMatrixCholeskyInverse(a,n,isupper,info,rep); + //--- check + if(info!=-3 && info!=1) + hpderrors=true; + else + { + hpderrors=(hpderrors || rep.m_r1<0.0) || rep.m_r1>1000*CMath::m_machineepsilon; + hpderrors=(hpderrors || rep.m_rinf<0.0) || rep.m_rinf>1000*CMath::m_machineepsilon; + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Unsets real matrix | +//+------------------------------------------------------------------+ +static void CTestMatInvUnit::Unset2D(CMatrixDouble &x) + { +//--- allocation + x.Resize(1,1); +//--- change value + x[0].Set(0,2*CMath::RandomReal()-1); + } +//+------------------------------------------------------------------+ +//| Unsets real matrix | +//+------------------------------------------------------------------+ +static void CTestMatInvUnit::Unset1D(double &x[]) + { +//--- allocation + ArrayResize(x,1); +//--- change value + x[0]=2*CMath::RandomReal()-1; + } +//+------------------------------------------------------------------+ +//| Unsets real matrix | +//+------------------------------------------------------------------+ +static void CTestMatInvUnit::CUnset2D(CMatrixComplex &x) + { +//--- allocation + x.Resize(1,1); +//--- change value + x[0].Set(0,2*CMath::RandomReal()-1); + } +//+------------------------------------------------------------------+ +//| Unsets real vector | +//+------------------------------------------------------------------+ +static void CTestMatInvUnit::CUnset1D(double &x[]) + { +//--- allocation + ArrayResize(x,1); +//--- change value + x[0]=2*CMath::RandomReal()-1; + } +//+------------------------------------------------------------------+ +//| Unsets report | +//+------------------------------------------------------------------+ +static void CTestMatInvUnit::UnsetRep(CMatInvReport &r) + { +//--- change values + r.m_r1=-1; + r.m_rinf=-1; + } +//+------------------------------------------------------------------+ +//| Testing class CLDA | +//+------------------------------------------------------------------+ +class CTestLDAUnit + { +private: + //--- private methods + static void GenSimpleSet(const int nfeatures,const int nclasses,const int nsamples,const int axis,CMatrixDouble &xy); + static void GenDeg1Set(const int nfeatures,const int nclasses,const int nsamples,int axis,CMatrixDouble &xy); + static double GenerateNormal(const double mean,const double sigma); + static bool TestWN(CMatrixDouble &xy,CMatrixDouble &wn,const int ns,const int nf,const int nc,const int ndeg); + static double CalcJ(const int nf,CMatrixDouble &st,CMatrixDouble &sw,double &w[],double &p,double &q); + static void Fishers(CMatrixDouble &xy,int npoints,const int nfeatures,const int nclasses,CMatrixDouble &st,CMatrixDouble &sw); +public: + //--- constructor, destructor + CTestLDAUnit(void); + ~CTestLDAUnit(void); + //--- public method + static bool TestLDA(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestLDAUnit::CTestLDAUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestLDAUnit::~CTestLDAUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CLDA | +//+------------------------------------------------------------------+ +static bool CTestLDAUnit::TestLDA(const bool silent) + { +//--- create variables + int maxnf=0; + int maxns=0; + int maxnc=0; + int passcount=0; + bool ldanerrors; + bool lda1errors; + bool waserrors; + int nf=0; + int nc=0; + int ns=0; + int i=0; + int info=0; + int pass=0; + int axis=0; +//--- create array + double w1[]; +//--- create matrix + CMatrixDouble xy; + CMatrixDouble wn; +//--- Primary settings + maxnf=10; + maxns=1000; + maxnc=5; + passcount=1; + waserrors=false; + ldanerrors=false; + lda1errors=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=CMath::RandomInteger(nf); + ns=maxns/2+CMath::RandomInteger(maxns/2); + //--- function calls + GenSimpleSet(nf,nc,ns,axis,xy); + CLDA::FisherLDAN(xy,ns,nf,nc,info,wn); + //--- check + if(info!=1) + { + ldanerrors=true; + continue; + } + //--- search errors + ldanerrors=ldanerrors || !TestWN(xy,wn,ns,nf,nc,0); + ldanerrors=ldanerrors || MathAbs(wn[axis][0])<=0.75; + //--- function call + CLDA::FisherLDA(xy,ns,nf,nc,info,w1); + //--- search errors + for(i=0;i<=nf-1;i++) + lda1errors=lda1errors || w1[i]!=wn[i][0]; + //--- Degenerate test for LDA-N + if(nf>=3) + { + ns=maxns/2+CMath::RandomInteger(maxns/2); + //--- there are two duplicate features, + //--- axis is oriented along non-duplicate feature + axis=CMath::RandomInteger(nf-2); + GenDeg1Set(nf,nc,ns,axis,xy); + CLDA::FisherLDAN(xy,ns,nf,nc,info,wn); + //--- check + if(info!=2) + { + ldanerrors=true; + continue; + } + //--- function calls + ldanerrors=ldanerrors || wn[axis][0]<=0.75; + CLDA::FisherLDA(xy,ns,nf,nc,info,w1); + //--- search errors + for(i=0;i<=nf-1;i++) + lda1errors=lda1errors || w1[i]!=wn[i][0]; + } + } + } + } +//--- Final report + waserrors=ldanerrors || lda1errors; +//--- check + if(!silent) + { + Print("LDA TEST"); + Print("FISHER LDA-N: "); + //--- check + if(!ldanerrors) + Print("OK"); + else + Print("FAILED"); + Print("FISHER LDA-1: "); + //--- check + if(!lda1errors) + Print("OK"); + else + Print("FAILED"); + //--- check + if(waserrors) + Print("TEST SUMMARY: FAILED"); + else + Print("TEST SUMMARY: PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Generates 'simple' set - a sequence of unit 'balls' at | +//| (0,0),(1,0),(2,0) and so on. | +//+------------------------------------------------------------------+ +static void CTestLDAUnit::GenSimpleSet(const int nfeatures,const int nclasses, + const int nsamples,const int axis, + CMatrixDouble &xy) + { +//--- create variables + int i=0; + int j=0; + int c=0; +//--- check + if(!CAp::Assert(axis>=0 && axis=3. | +//+------------------------------------------------------------------+ +static void CTestLDAUnit::GenDeg1Set(const int nfeatures,const int nclasses, + const int nsamples,int axis, + CMatrixDouble &xy) + { +//--- create variables + int i=0; + int j=0; + int c=0; +//--- check + if(!CAp::Assert(axis>=0 && axis=3,"GenDeg1Set: wrong NFeatures!")) + return; +//--- allocation + xy.Resize(nsamples,nfeatures+1); +//--- check + if(axis>=nfeatures-2) + axis=nfeatures-3; +//--- calculation + for(i=0;i<=nsamples-1;i++) + { + for(j=0;j<=nfeatures-2;j++) + xy[i].Set(j,GenerateNormal(0.0,1.0)); + //--- change values + xy[i].Set(nfeatures-1,xy[i][nfeatures-2]); + c=i%nclasses; + xy[i].Set(axis,xy[i][axis]+c); + xy[i].Set(nfeatures,c); + } + } +//+------------------------------------------------------------------+ +//| Normal random number | +//+------------------------------------------------------------------+ +static double CTestLDAUnit::GenerateNormal(const double mean,const double sigma) + { +//--- create variables + double result=0; + double u=0; + double v=0; + double sum=0; +//--- initialization + result=mean; +//--- calculation + while(true) + { + //--- change values + u=(2*CMath::RandomInteger(2)-1)*CMath::RandomReal(); + v=(2*CMath::RandomInteger(2)-1)*CMath::RandomReal(); + sum=u*u+v*v; + //--- check + if(sum<1.0 && sum>0.0) + { + sum=MathSqrt(-(2*MathLog(sum)/sum)); + result=sigma*u*sum+mean; + //--- return result + return(result); + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Tests WN for correctness | +//+------------------------------------------------------------------+ +static bool CTestLDAUnit::TestWN(CMatrixDouble &xy,CMatrixDouble &wn, + const int ns,const int nf, + const int nc,const int ndeg) + { +//--- create variables + bool result; + int i=0; + int j=0; + double v=0; + double wprev=0; + double tol=0; + double p=0; + double q=0; + int i_=0; +//--- create arrays + double tx[]; + double jp[]; + double jq[]; + double work[]; +//--- create matrix + CMatrixDouble st; + CMatrixDouble sw; + CMatrixDouble a; + CMatrixDouble z; +//--- initialization + tol=10000; + result=true; + Fishers(xy,ns,nf,nc,st,sw); +//--- Test for decreasing of J + ArrayResize(tx,nf); + ArrayResize(jp,nf); + ArrayResize(jq,nf); +//--- calculation + for(j=0;j<=nf-1;j++) + { + for(i_=0;i_<=nf-1;i_++) + tx[i_]=wn[i_][j]; + v=CalcJ(nf,st,sw,tx,p,q); + jp[j]=p; + jq[j]=q; + } +//--- calculation + for(i=1;i<=nf-1-ndeg;i++) + result=result && jp[i-1]/jq[i-1]>=(1-tol*CMath::m_machineepsilon)*jp[i]/jq[i]; + for(i=nf-1-ndeg+1;i<=nf-1;i++) + result=result && jp[i]<=tol*CMath::m_machineepsilon*jp[0]; +//--- Test for J optimality + for(i_=0;i_<=nf-1;i_++) + tx[i_]=wn[i_][0]; + v=CalcJ(nf,st,sw,tx,p,q); +//--- calculation + for(i=0;i<=nf-1;i++) + { + wprev=tx[i]; + tx[i]=wprev+0.01; + result=result && v>=(1-tol*CMath::m_machineepsilon)*CalcJ(nf,st,sw,tx,p,q); + tx[i]=wprev-0.01; + result=result && v>=(1-tol*CMath::m_machineepsilon)*CalcJ(nf,st,sw,tx,p,q); + tx[i]=wprev; + } +//--- Test for linear independence of W + ArrayResize(work,nf+1); + a.Resize(nf,nf); +//--- function call + CBlas::MatrixMatrixMultiply(wn,0,nf-1,0,nf-1,false,wn,0,nf-1,0,nf-1,true,1.0,a,0,nf-1,0,nf-1,0.0,work); +//--- check + if(CEigenVDetect::SMatrixEVD(a,nf,1,true,tx,z)) + result=result && tx[0]>tx[nf-1]*1000*CMath::m_machineepsilon; +//--- Test for other properties + for(j=0;j<=nf-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=nf-1;i_++) + v+=wn[i_][j]*wn[i_][j]; + //--- change values + v=MathSqrt(v); + result=result && MathAbs(v-1)<=1000*CMath::m_machineepsilon; + v=0; + for(i=0;i<=nf-1;i++) + v=v+wn[i][j]; + result=result && v>=0.0; + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Calculates J | +//+------------------------------------------------------------------+ +static double CTestLDAUnit::CalcJ(const int nf,CMatrixDouble &st, + CMatrixDouble &sw,double &w[], + double &p,double &q) + { +//--- create variables + double result=0; + int i=0; + double v=0; + int i_=0; +//--- create array + double tx[]; +//--- initialization + p=0; + q=0; +//--- allocation + ArrayResize(tx,nf); +//--- calculation + for(i=0;i<=nf-1;i++) + { + //--- change value + v=0.0; + for(i_=0;i_<=nf-1;i_++) + v+=st[i][i_]*w[i_]; + tx[i]=v; + } +//--- change value + v=0.0; + for(i_=0;i_<=nf-1;i_++) + v+=w[i_]*tx[i_]; + p=v; + for(i=0;i<=nf-1;i++) + { + //--- change value + v=0.0; + for(i_=0;i_<=nf-1;i_++) + v+=sw[i][i_]*w[i_]; + tx[i]=v; + } +//--- change value + v=0.0; + for(i_=0;i_<=nf-1;i_++) + v+=w[i_]*tx[i_]; + q=v; + result=p/q; +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Calculates ST/SW | +//+------------------------------------------------------------------+ +static void CTestLDAUnit::Fishers(CMatrixDouble &xy,int npoints, + const int nfeatures,const int nclasses, + CMatrixDouble &st,CMatrixDouble &sw) + { +//--- create variables + int i=0; + int j=0; + int k=0; + double v=0; + int i_=0; +//--- create arrays + int c[]; + double mu[]; + int nc[]; + double tf[]; + double work[]; +//--- create matrix + CMatrixDouble muc; +//--- Prepare temporaries + ArrayResize(tf,nfeatures); + ArrayResize(work,nfeatures+1); +//--- Convert class labels from reals to integers (just for convenience) + ArrayResize(c,npoints); + for(i=0;i<=npoints-1;i++) + c[i]=(int)MathRound(xy[i][nfeatures]); +//--- Calculate class sizes and means + ArrayResize(mu,nfeatures); + muc.Resize(nclasses,nfeatures); + ArrayResize(nc,nclasses); +//--- change values + for(j=0;j<=nfeatures-1;j++) + mu[j]=0; + for(i=0;i<=nclasses-1;i++) + { + nc[i]=0; + for(j=0;j<=nfeatures-1;j++) + muc[i].Set(j,0); + } +//--- calculation + for(i=0;i<=npoints-1;i++) + { + for(i_=0;i_<=nfeatures-1;i_++) + mu[i_]=mu[i_]+xy[i][i_]; + for(i_=0;i_<=nfeatures-1;i_++) + muc[c[i]].Set(i_,muc[c[i]][i_]+xy[i][i_]); + nc[c[i]]=nc[c[i]]+1; + } +//--- calculation + for(i=0;i<=nclasses-1;i++) + { + v=1.0/(double)nc[i]; + for(i_=0;i_<=nfeatures-1;i_++) + muc[i].Set(i_,v*muc[i][i_]); + } +//--- change values + v=1.0/(double)npoints; + for(i_=0;i_<=nfeatures-1;i_++) + mu[i_]=v*mu[i_]; +//--- Create ST matrix + st.Resize(nfeatures,nfeatures); +//--- change values + for(i=0;i<=nfeatures-1;i++) + { + for(j=0;j<=nfeatures-1;j++) + st[i].Set(j,0); + } +//--- calculation + for(k=0;k<=npoints-1;k++) + { + for(i_=0;i_<=nfeatures-1;i_++) + tf[i_]=xy[k][i_]; + for(i_=0;i_<=nfeatures-1;i_++) + tf[i_]=tf[i_]-mu[i_]; + //--- calculation + for(i=0;i<=nfeatures-1;i++) + { + v=tf[i]; + for(i_=0;i_<=nfeatures-1;i_++) + st[i].Set(i_,st[i][i_]+v*tf[i_]); + } + } +//--- Create SW matrix + sw.Resize(nfeatures,nfeatures); + for(i=0;i<=nfeatures-1;i++) + { + for(j=0;j<=nfeatures-1;j++) + sw[i].Set(j,0); + } +//--- calculation + for(k=0;k<=npoints-1;k++) + { + for(i_=0;i_<=nfeatures-1;i_++) + tf[i_]=xy[k][i_]; + for(i_=0;i_<=nfeatures-1;i_++) + tf[i_]=tf[i_]-muc[c[k]][i_]; + //--- calculation + for(i=0;i<=nfeatures-1;i++) + { + v=tf[i]; + for(i_=0;i_<=nfeatures-1;i_++) + sw[i].Set(i_,sw[i][i_]+v*tf[i_]); + } + } + } +//+------------------------------------------------------------------+ +//| Testing class CGammaFunc | +//+------------------------------------------------------------------+ +class CTestGammaFuncUnit + { +public: + //--- constructor, destructor + CTestGammaFuncUnit(void); + ~CTestGammaFuncUnit(void); + //--- public method + static bool TestGammaFunc(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestGammaFuncUnit::CTestGammaFuncUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestGammaFuncUnit::~CTestGammaFuncUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CGammaFunc | +//+------------------------------------------------------------------+ +static bool CTestGammaFuncUnit::TestGammaFunc(const bool silent) + { +//--- create variables + double threshold=0; + double v=0; + double s=0; + bool waserrors; + bool gammaerrors; + bool lngammaerrors; +//--- initialization + gammaerrors=false; + lngammaerrors=false; + waserrors=false; + threshold=100*CMath::m_machineepsilon; +//--- search errors + gammaerrors=gammaerrors || MathAbs(CGammaFunc::GammaFunc(0.5)-MathSqrt(M_PI))>threshold; + gammaerrors=gammaerrors || MathAbs(CGammaFunc::GammaFunc(1.5)-0.5*MathSqrt(M_PI))>threshold; +//--- function call + v=CGammaFunc::LnGamma(0.5,s); +//--- search errors + lngammaerrors=(lngammaerrors || MathAbs(v-MathLog(MathSqrt(M_PI)))>threshold) || s!=1.0; +//--- function call + v=CGammaFunc::LnGamma(1.5,s); +//--- search errors + lngammaerrors=(lngammaerrors || MathAbs(v-MathLog(0.5*MathSqrt(M_PI)))>threshold) || s!=1.0; +//--- report + waserrors=gammaerrors || lngammaerrors; +//--- check + if(!silent) + { + Print("TESTING GAMMA FUNCTION"); + Print("GAMMA: "); + //--- check + if(gammaerrors) + Print("FAILED"); + else + Print("OK"); + Print("LN GAMMA: "); + //--- check + if(lngammaerrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- end +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Testing class CBdSingValueDecompose | +//+------------------------------------------------------------------+ +class CTestBdSVDUnit + { +private: + //--- private methods + static void FillIdentity(CMatrixDouble &a,const int n); + static void FillSparseDE(double &d[],double &e[],const int n,const double sparcity); + static void GetBdSVDError(double &d[],double &e[],const int n,const bool isupper,CMatrixDouble &u,CMatrixDouble &c,double &w[],CMatrixDouble &vt,double &materr,double &orterr,bool &wsorted); + static void TestBdSVDProblem(double &d[],double &e[],const int n,double &materr,double &orterr,bool &wsorted,bool &wfailed,int &failcount,int &succcount); +public: + //--- constructor, destructor + CTestBdSVDUnit(void); + ~CTestBdSVDUnit(void); + //--- public method + static bool TestBdSVD(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestBdSVDUnit::CTestBdSVDUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestBdSVDUnit::~CTestBdSVDUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing bidiagonal SVD decomposition subroutine | +//+------------------------------------------------------------------+ +static bool CTestBdSVDUnit::TestBdSVD(const bool silent) + { +//--- create variables + int n=0; + int maxn=0; + int i=0; + int pass=0; + bool waserrors; + bool wsorted; + bool wfailed; + bool failcase; + double materr=0; + double orterr=0; + double threshold=0; + double failthreshold=0; + double failr=0; + int failcount=0; + int succcount=0; +//--- create arrays + double d[]; + double e[]; +//--- create matrix + CMatrixDouble mempty; +//--- initialization + failcount=0; + succcount=0; + materr=0; + orterr=0; + wsorted=true; + wfailed=false; + waserrors=false; + maxn=15; + threshold=5*100*CMath::m_machineepsilon; + failthreshold=1.0E-2; +//--- allocation + ArrayResize(d,maxn); + ArrayResize(e,maxn-1); +//--- special case: fail matrix + n=5; + d[0]=-8.27448347422711894000e-01; + d[1]=-8.16705832087160854600e-01; + d[2]=-2.53974358904729382800e-17; + d[3]=-1.24626684881972815700e+00; + d[4]=-4.64744131545637651000e-01; + e[0]=-3.25785088656270038800e-01; + e[1]=-1.03732413708914436580e-01; + e[2]=-9.57365642262031357700e-02; + e[3]=-2.71564153973817390400e-01; + failcase=CBdSingValueDecompose::RMatrixBdSVD(d,e,n,true,false,mempty,0,mempty,0,mempty,0); +//--- special case: zero divide matrix +//--- unfixed LAPACK routine should fail on this problem + n=7; + d[0]=-6.96462904751731892700e-01; + d[1]=0.00000000000000000000e+00; + d[2]=-5.73827770385971991400e-01; + d[3]=-6.62562624399371191700e-01; + d[4]=5.82737148001782223600e-01; + d[5]=3.84825263580925003300e-01; + d[6]=9.84087420830525472200e-01; + e[0]=-7.30307931760612871800e-02; + e[1]=-2.30079042939542843800e-01; + e[2]=-6.87824621739351216300e-01; + e[3]=-1.77306437707837570600e-02; + e[4]=1.78285126526551632000e-15; + e[5]=-4.89434737751289969400e-02; + CBdSingValueDecompose::RMatrixBdSVD(d,e,n,true,false,mempty,0,mempty,0,mempty,0); +//--- zero matrix,several cases + for(i=0;i<=maxn-1;i++) + d[i]=0; + for(i=0;i<=maxn-2;i++) + e[i]=0; + for(n=1;n<=maxn;n++) + TestBdSVDProblem(d,e,n,materr,orterr,wsorted,wfailed,failcount,succcount); +//--- Dense matrix + for(n=1;n<=maxn;n++) + { + for(pass=1;pass<=10;pass++) + { + for(i=0;i<=maxn-1;i++) + d[i]=2*CMath::RandomReal()-1; + for(i=0;i<=maxn-2;i++) + e[i]=2*CMath::RandomReal()-1; + //--- function call + TestBdSVDProblem(d,e,n,materr,orterr,wsorted,wfailed,failcount,succcount); + } + } +//--- Sparse matrices,very sparse matrices,incredible sparse matrices + for(n=1;n<=maxn;n++) + { + for(pass=1;pass<=10;pass++) + { + //--- function calls + FillSparseDE(d,e,n,0.5); + TestBdSVDProblem(d,e,n,materr,orterr,wsorted,wfailed,failcount,succcount); + FillSparseDE(d,e,n,0.8); + TestBdSVDProblem(d,e,n,materr,orterr,wsorted,wfailed,failcount,succcount); + FillSparseDE(d,e,n,0.9); + TestBdSVDProblem(d,e,n,materr,orterr,wsorted,wfailed,failcount,succcount); + FillSparseDE(d,e,n,0.95); + TestBdSVDProblem(d,e,n,materr,orterr,wsorted,wfailed,failcount,succcount); + } + } +//--- report + failr=(double)failcount/(double)(succcount+failcount); + waserrors=((materr>threshold || orterr>threshold) || !wsorted) || failr>failthreshold; +//--- check + if(!silent) + { + Print("TESTING BIDIAGONAL SVD DECOMPOSITION"); + Print("SVD decomposition error: "); + Print("{0,5:E3}",materr); + Print("SVD orthogonality error: "); + Print("{0,5:E3}",orterr); + Print("Singular values order: "); + //--- check + if(wsorted) + Print("OK"); + else + Print("FAILED"); + Print("Always converged: "); + //--- check + if(!wfailed) + Print("YES"); + else + { + Print("NO"); + Print("Fail ratio: "); + Print("{0,5:F3}",failr); + } + Print("Fail matrix test: "); + //--- check + if(!failcase) + Print("AS EXPECTED"); + else + Print("CONVERGED (UNEXPECTED)"); + Print("Threshold: "); + Print("{0,5:E3}",threshold); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestBdSVDUnit::FillIdentity(CMatrixDouble &a,const int n) + { +//--- create variables + int i=0; + int j=0; +//--- allocation + a.Resize(n,n); +//--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(i==j) + a[i].Set(j,1); + else + a[i].Set(j,0); + } + } + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestBdSVDUnit::FillSparseDE(double &d[],double &e[], + const int n,const double sparcity) + { +//--- create a variable + int i=0; +//--- allocation + ArrayResize(d,n); + ArrayResize(e,(int)(MathMax(0,n-2))+1); +//--- change values + for(i=0;i<=n-1;i++) + { + //--- check + if(CMath::RandomReal()>=sparcity) + d[i]=2*CMath::RandomReal()-1; + else + d[i]=0; + } +//--- change values + for(i=0;i<=n-2;i++) + { + //--- check + if(CMath::RandomReal()>=sparcity) + e[i]=2*CMath::RandomReal()-1; + else + e[i]=0; + } + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestBdSVDUnit::GetBdSVDError(double &d[],double &e[], + const int n,const bool isupper, + CMatrixDouble &u,CMatrixDouble &c, + double &w[],CMatrixDouble &vt, + double &materr,double &orterr, + bool &wsorted) + { +//--- create variables + int i=0; + int j=0; + int k=0; + double locerr=0; + double sm=0; + int i_=0; +//--- decomposition error + locerr=0; + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + sm=0; + for(k=0;k<=n-1;k++) + sm=sm+w[k]*u[i][k]*vt[k][j]; + //--- check + if(isupper) + { + //--- check + if(i==j) + locerr=MathMax(locerr,MathAbs(d[i]-sm)); + else + { + //--- check + if(i==j-1) + locerr=MathMax(locerr,MathAbs(e[i]-sm)); + else + locerr=MathMax(locerr,MathAbs(sm)); + } + } + else + { + //--- check + if(i==j) + locerr=MathMax(locerr,MathAbs(d[i]-sm)); + else + { + //--- check + if(i-1==j) + locerr=MathMax(locerr,MathAbs(e[j]-sm)); + else + locerr=MathMax(locerr,MathAbs(sm)); + } + } + } + } +//--- change value + materr=MathMax(materr,locerr); +//--- check for C=U' +//--- we consider it as decomposition error + locerr=0; + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + locerr=MathMax(locerr,MathAbs(u[i][j]-c[j][i])); + } + materr=MathMax(materr,locerr); +//--- orthogonality error + locerr=0; + for(i=0;i<=n-1;i++) + { + for(j=i;j<=n-1;j++) + { + //--- change value + sm=0.0; + for(i_=0;i_<=n-1;i_++) + sm+=u[i_][i]*u[i_][j]; + //--- check + if(i!=j) + locerr=MathMax(locerr,MathAbs(sm)); + else + locerr=MathMax(locerr,MathAbs(sm-1)); + //--- change value + sm=0.0; + for(i_=0;i_<=n-1;i_++) + sm+=vt[i][i_]*vt[j][i_]; + //--- check + if(i!=j) + locerr=MathMax(locerr,MathAbs(sm)); + else + locerr=MathMax(locerr,MathAbs(sm-1)); + } + } + orterr=MathMax(orterr,locerr); +//--- values order error + for(i=1;i<=n-1;i++) + { + //--- check + if(w[i]>w[i-1]) + wsorted=false; + } + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestBdSVDUnit::TestBdSVDProblem(double &d[],double &e[], + const int n,double &materr, + double &orterr,bool &wsorted, + bool &wfailed,int &failcount, + int &succcount) + { +//--- create variables + int i=0; + double mx=0; +//--- create array + double w[]; +//--- create matrix + CMatrixDouble u; + CMatrixDouble vt; + CMatrixDouble c; +//--- change value + mx=0; + for(i=0;i<=n-1;i++) + { + //--- check + if(MathAbs(d[i])>mx) + mx=MathAbs(d[i]); + } + for(i=0;i<=n-2;i++) + { + //--- check + if(MathAbs(e[i])>mx) + mx=MathAbs(e[i]); + } +//--- check + if(mx==0.0) + mx=1; +//--- Upper BDSVD tests + ArrayResize(w,n); + FillIdentity(u,n); + FillIdentity(vt,n); + FillIdentity(c,n); + for(i=0;i<=n-1;i++) + w[i]=d[i]; +//--- check + if(!CBdSingValueDecompose::RMatrixBdSVD(w,e,n,true,false,u,n,c,n,vt,n)) + { + failcount=failcount+1; + wfailed=true; + return; + } +//--- function calls + GetBdSVDError(d,e,n,true,u,c,w,vt,materr,orterr,wsorted); + FillIdentity(u,n); + FillIdentity(vt,n); + FillIdentity(c,n); +//--- copy + for(i=0;i<=n-1;i++) + w[i]=d[i]; +//--- check + if(!CBdSingValueDecompose::RMatrixBdSVD(w,e,n,true,true,u,n,c,n,vt,n)) + { + failcount=failcount+1; + wfailed=true; + return; + } +//--- function call + GetBdSVDError(d,e,n,true,u,c,w,vt,materr,orterr,wsorted); +//--- Lower BDSVD tests + ArrayResize(w,n); + FillIdentity(u,n); + FillIdentity(vt,n); + FillIdentity(c,n); +//--- copy + for(i=0;i<=n-1;i++) + w[i]=d[i]; +//--- check + if(!CBdSingValueDecompose::RMatrixBdSVD(w,e,n,false,false,u,n,c,n,vt,n)) + { + failcount=failcount+1; + wfailed=true; + return; + } +//--- function calls + GetBdSVDError(d,e,n,false,u,c,w,vt,materr,orterr,wsorted); + FillIdentity(u,n); + FillIdentity(vt,n); + FillIdentity(c,n); +//--- copy + for(i=0;i<=n-1;i++) + w[i]=d[i]; +//--- check + if(!CBdSingValueDecompose::RMatrixBdSVD(w,e,n,false,true,u,n,c,n,vt,n)) + { + failcount=failcount+1; + wfailed=true; + return; + } +//--- function call + GetBdSVDError(d,e,n,false,u,c,w,vt,materr,orterr,wsorted); +//--- update counter + succcount=succcount+1; + } +//+------------------------------------------------------------------+ +//| Testing class CSingValueDecompose | +//+------------------------------------------------------------------+ +class CTestSVDUnit + { +private: + //--- private methods + static void FillsParseA(CMatrixDouble &a,const int m,const int n,const double sparcity); + static void GetSVDError(CMatrixDouble &a,const int m,const int n,CMatrixDouble &u,double &w[],CMatrixDouble &vt,double &materr,double &orterr,bool &wsorted); + static void TestSVDProblem(CMatrixDouble &a,const int m,const int n,double &materr,double &orterr,double &othererr,bool &wsorted,bool &wfailed,int &failcount,int &succcount); +public: + //--- constructor, destructor + CTestSVDUnit(void); + ~CTestSVDUnit(void); + //--- public method + static bool TestSVD(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestSVDUnit::CTestSVDUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestSVDUnit::~CTestSVDUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing SVD decomposition subroutine | +//+------------------------------------------------------------------+ +static bool CTestSVDUnit::TestSVD(const bool silent) + { +//--- create variables + int m=0; + int n=0; + int maxmn=0; + int i=0; + int j=0; + int gpass=0; + int pass=0; + bool waserrors; + bool wsorted; + bool wfailed; + double materr=0; + double orterr=0; + double othererr=0; + double threshold=0; + double failthreshold=0; + double failr=0; + int failcount=0; + int succcount=0; +//--- create matrix + CMatrixDouble a; +//--- initialization + failcount=0; + succcount=0; + materr=0; + orterr=0; + othererr=0; + wsorted=true; + wfailed=false; + waserrors=false; + maxmn=30; + threshold=5*100*CMath::m_machineepsilon; + failthreshold=5.0E-3; +//--- allocation + a.Resize(maxmn,maxmn); +//--- 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[i].Set(j,0); + } + //--- function calls + for(i=1;i<=MathMin(5,maxmn);i++) + { + for(j=1;j<=MathMin(5,maxmn);j++) + TestSVDProblem(a,i,j,materr,orterr,othererr,wsorted,wfailed,failcount,succcount); + } + //--- Long dense matrix + for(i=0;i<=maxmn-1;i++) + { + for(j=0;j<=MathMin(5,maxmn)-1;j++) + a[i].Set(j,2*CMath::RandomReal()-1); + } + //--- function calls + for(i=1;i<=maxmn;i++) + { + for(j=1;j<=MathMin(5,maxmn);j++) + TestSVDProblem(a,i,j,materr,orterr,othererr,wsorted,wfailed,failcount,succcount); + } + //--- change values + for(i=0;i<=MathMin(5,maxmn)-1;i++) + { + for(j=0;j<=maxmn-1;j++) + a[i].Set(j,2*CMath::RandomReal()-1); + } + //--- function calls + for(i=1;i<=MathMin(5,maxmn);i++) + { + for(j=1;j<=maxmn;j++) + TestSVDProblem(a,i,j,materr,orterr,othererr,wsorted,wfailed,failcount,succcount); + } + //--- Dense matrices + for(m=1;m<=MathMin(10,maxmn);m++) + { + for(n=1;n<=MathMin(10,maxmn);n++) + { + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,2*CMath::RandomReal()-1); + } + //--- function call + TestSVDProblem(a,m,n,materr,orterr,othererr,wsorted,wfailed,failcount,succcount); + } + } + //--- 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++) + { + //--- function calls + FillsParseA(a,m,n,0.8); + TestSVDProblem(a,m,n,materr,orterr,othererr,wsorted,wfailed,failcount,succcount); + FillsParseA(a,m,n,0.9); + TestSVDProblem(a,m,n,materr,orterr,othererr,wsorted,wfailed,failcount,succcount); + FillsParseA(a,m,n,0.95); + TestSVDProblem(a,m,n,materr,orterr,othererr,wsorted,wfailed,failcount,succcount); + } + } + } + } +//--- report + failr=(double)failcount/(double)(succcount+failcount); + waserrors=(((materr>threshold || orterr>threshold) || othererr>threshold) || !wsorted) || failr>failthreshold; +//--- check + if(!silent) + { + Print("TESTING SVD DECOMPOSITION"); + Print("SVD decomposition error: "); + Print("{0,5:E3}",materr); + Print("SVD orthogonality error: "); + Print("{0,5:E3}",orterr); + Print("SVD with different parameters error: "); + Print("{0,5:E3}",othererr); + Print("Singular values order: "); + //--- check + if(wsorted) + Print("OK"); + else + Print("FAILED"); + Print("Always converged: "); + //--- check + if(!wfailed) + Print("YES"); + else + { + Print("NO"); + Print("Fail ratio: "); + Print("{0,5:F3}",failr); + } + Print("Threshold: "); + Print("{0,5:E3}",threshold); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestSVDUnit::FillsParseA(CMatrixDouble &a,const int m, + const int n,const double sparcity) + { +//--- create variables + int i=0; + int j=0; +//--- change values + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(CMath::RandomReal()>=sparcity) + a[i].Set(j,2*CMath::RandomReal()-1); + else + a[i].Set(j,0); + } + } + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestSVDUnit::GetSVDError(CMatrixDouble &a,const int m, + const int n,CMatrixDouble &u, + double &w[],CMatrixDouble &vt, + double &materr,double &orterr, + bool &wsorted) + { +//--- create variables + int i=0; + int j=0; + int k=0; + int minmn=0; + double locerr=0; + double sm=0; + int i_=0; +//--- initialization + minmn=MathMin(m,n); +//--- decomposition error + locerr=0; + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + sm=0; + for(k=0;k<=minmn-1;k++) + sm=sm+w[k]*u[i][k]*vt[k][j]; + locerr=MathMax(locerr,MathAbs(a[i][j]-sm)); + } + } + materr=MathMax(materr,locerr); +//--- orthogonality error + locerr=0; + for(i=0;i<=minmn-1;i++) + { + for(j=i;j<=minmn-1;j++) + { + //--- change value + sm=0.0; + for(i_=0;i_<=m-1;i_++) + sm+=u[i_][i]*u[i_][j]; + //--- check + if(i!=j) + locerr=MathMax(locerr,MathAbs(sm)); + else + locerr=MathMax(locerr,MathAbs(sm-1)); + //--- change value + sm=0.0; + for(i_=0;i_<=n-1;i_++) + sm+=vt[i][i_]*vt[j][i_]; + //--- check + if(i!=j) + locerr=MathMax(locerr,MathAbs(sm)); + else + locerr=MathMax(locerr,MathAbs(sm-1)); + } + } + orterr=MathMax(orterr,locerr); +//--- values order error + for(i=1;i<=minmn-1;i++) + { + //--- check + if(w[i]>w[i-1]) + wsorted=false; + } + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestSVDUnit::TestSVDProblem(CMatrixDouble &a,const int m, + const int n,double &materr, + double &orterr,double &othererr, + bool &wsorted,bool &wfailed, + int &failcount,int &succcount) + { +//--- create variables + int i=0; + int j=0; + int ujob=0; + int vtjob=0; + int memjob=0; + int ucheck=0; + int vtcheck=0; +//--- create arrays + double w[]; + double w2[]; +//--- create matrix + CMatrixDouble u; + CMatrixDouble vt; + CMatrixDouble u2; + CMatrixDouble vt2; +//--- Main SVD test + if(!CSingValueDecompose::RMatrixSVD(a,m,n,2,2,2,w,u,vt)) + { + failcount=failcount+1; + wfailed=true; + //--- exit the function + return; + } +//--- function call + GetSVDError(a,m,n,u,w,vt,materr,orterr,wsorted); +//--- Additional SVD tests + for(ujob=0;ujob<=2;ujob++) + { + for(vtjob=0;vtjob<=2;vtjob++) + { + for(memjob=0;memjob<=2;memjob++) + { + //--- check + if(!CSingValueDecompose::RMatrixSVD(a,m,n,ujob,vtjob,memjob,w2,u2,vt2)) + { + failcount=failcount+1; + wfailed=true; + //--- exit the function + return; + } + //--- change value + ucheck=0; + //--- check + if(ujob==1) + ucheck=MathMin(m,n); + //--- check + if(ujob==2) + ucheck=m; + //--- change value + vtcheck=0; + //--- check + if(vtjob==1) + vtcheck=MathMin(m,n); + //--- check + if(vtjob==2) + vtcheck=n; + //--- search errors + for(i=0;i<=m-1;i++) + { + for(j=0;j<=ucheck-1;j++) + othererr=MathMax(othererr,MathAbs(u[i][j]-u2[i][j])); + } + //--- search errors + for(i=0;i<=vtcheck-1;i++) + { + for(j=0;j<=n-1;j++) + othererr=MathMax(othererr,MathAbs(vt[i][j]-vt2[i][j])); + } + //--- search errors + for(i=0;i<=MathMin(m,n)-1;i++) + othererr=MathMax(othererr,MathAbs(w[i]-w2[i])); + } + } + } +//--- update counter + succcount=succcount+1; + } +//+------------------------------------------------------------------+ +//| Testing class CLinReg | +//+------------------------------------------------------------------+ +class CTestLinRegUnit + { +public: + //--- constructor, destructor + CTestLinRegUnit(void); + ~CTestLinRegUnit(void); + //--- public methods + static bool TestLinReg(const bool silent); + static void GenerateRandomTask(const double xl,const double xr,const bool randomx,const double ymin,const double ymax,const double smin,const double smax,const int n,CMatrixDouble &xy,double &s[]); + static void GenerateTask(const double a,const double b,const double xl,const double xr,const bool randomx,const double smin,const double smax,const int n,CMatrixDouble &xy,double &s[]); + static void FillTaskWithY(const double a,const double b,const int n,CMatrixDouble &xy,double &s[]); + static double GenerateNormal(const double mean,const double sigma); + static void CalculateMV(double &x[],const int n,double &mean,double &means,double &stddev,double &stddevs); + static void UnsetLR(CLinearModel &lr); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestLinRegUnit::CTestLinRegUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestLinRegUnit::~CTestLinRegUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CLinReg | +//+------------------------------------------------------------------+ +static bool CTestLinRegUnit::TestLinReg(const bool silent) + { +//--- create variables + double sigmathreshold=0; + int maxn=0; + int maxm=0; + int passcount=0; + int estpasscount=0; + double threshold=0; + int n=0; + int i=0; + int j=0; + int k=0; + int tmpi=0; + int pass=0; + int epass=0; + int m=0; + int tasktype=0; + int modeltype=0; + int m1=0; + int m2=0; + int n1=0; + int n2=0; + int info=0; + int info2=0; + double y1=0; + double y2=0; + bool allsame; + double ea=0; + double eb=0; + double varatested=0; + double varbtested=0; + double a=0; + double b=0; + double vara=0; + double varb=0; + double a2=0; + double b2=0; + double covab=0; + double corrab=0; + double p=0; + int qcnt=0; + double f=0; + double fp=0; + double fm=0; + double v=0; + double vv=0; + double cvrmserror=0; + double cvavgerror=0; + double cvavgrelerror=0; + double rmserror=0; + double avgerror=0; + double avgrelerror=0; + bool nondefect; + double sinshift=0; + double tasklevel=0; + double noiselevel=0; + double hstep=0; + double sigma=0; + double mean=0; + double means=0; + double stddev=0; + double stddevs=0; + bool slcerrors; + bool slerrors; + bool grcoverrors; + bool gropterrors; + bool gresterrors; + bool grothererrors; + bool grconverrors; + bool waserrors; + int i_=0; +//--- create arrays + double s[]; + double s2[]; + double w2[]; + double x[]; + double ta[]; + double tb[]; + double tc[]; + double xy0[]; + double tmpweights[]; + double x1[]; + double x2[]; + double qtbl[]; + double qvals[]; + double qsigma[]; +//--- create matrix + CMatrixDouble xy; + CMatrixDouble xy2; +//--- objects of classes + CLinearModel w; + CLinearModel wt; + CLinearModel wt2; + CLRReport ar; + CLRReport ar2; +//--- Primary settings + maxn=40; + maxm=5; + passcount=3; + estpasscount=1000; + sigmathreshold=7; + threshold=1000000*CMath::m_machineepsilon; + slerrors=false; + slcerrors=false; + grcoverrors=false; + gropterrors=false; + gresterrors=false; + grothererrors=false; + grconverrors=false; + waserrors=false; +//--- Quantiles table setup + qcnt=5; + ArrayResize(qtbl,qcnt); + ArrayResize(qvals,qcnt); + ArrayResize(qsigma,qcnt); + qtbl[0]=0.5; + qtbl[1]=0.25; + qtbl[2]=0.10; + qtbl[3]=0.05; + qtbl[4]=0.025; + for(i=0;i<=qcnt-1;i++) + qsigma[i]=MathSqrt(qtbl[i]*(1-qtbl[i])/estpasscount); +//--- Other setup + ArrayResize(ta,estpasscount); + ArrayResize(tb,estpasscount); +//--- Test straight line regression + for(n=2;n<=maxn;n++) + { + //--- Fail/pass test + GenerateRandomTask(-1,1,false,-1,1,1,2,n,xy,s); + CLinReg::LRLines(xy,s,n,info,a,b,vara,varb,covab,corrab,p); + //--- search errors + slcerrors=slcerrors || info!=1; + //--- function calls + GenerateRandomTask(1,1,false,-1,1,1,2,n,xy,s); + CLinReg::LRLines(xy,s,n,info,a,b,vara,varb,covab,corrab,p); + //--- search errors + slcerrors=slcerrors || info!=-3; + //--- function calls + GenerateRandomTask(-1,1,false,-1,1,-1,-1,n,xy,s); + CLinReg::LRLines(xy,s,n,info,a,b,vara,varb,covab,corrab,p); + //--- search errors + slcerrors=slcerrors || info!=-2; + //--- function calls + GenerateRandomTask(-1,1,false,-1,1,2,1,2,xy,s); + CLinReg::LRLines(xy,s,1,info,a,b,vara,varb,covab,corrab,p); + //--- search errors + slcerrors=slcerrors || info!=-1; + //--- Multipass tests + for(pass=1;pass<=passcount;pass++) + { + //--- Test S variant against non-S variant + ea=2*CMath::RandomReal()-1; + eb=2*CMath::RandomReal()-1; + //--- function calls + GenerateTask(ea,eb,-(5*CMath::RandomReal()),5*CMath::RandomReal(),CMath::RandomReal()>0.5,1,1,n,xy,s); + CLinReg::LRLines(xy,s,n,info,a,b,vara,varb,covab,corrab,p); + CLinReg::LRLine(xy,n,info2,a2,b2); + //--- check + if(info!=1 || info2!=1) + slcerrors=true; + else + slerrors=(slerrors || MathAbs(a-a2)>threshold) || MathAbs(b-b2)>threshold; + //--- Test for A/B + //--- Generate task with exact,non-perturbed y[i], + //--- then make non-zero s[i] + ea=2*CMath::RandomReal()-1; + eb=2*CMath::RandomReal()-1; + GenerateTask(ea,eb,-(5*CMath::RandomReal()),5*CMath::RandomReal(),n>4,0.0,0.0,n,xy,s); + for(i=0;i<=n-1;i++) + s[i]=1+CMath::RandomReal(); + //--- function call + CLinReg::LRLines(xy,s,n,info,a,b,vara,varb,covab,corrab,p); + //--- check + if(info!=1) + slcerrors=true; + else + slerrors=(slerrors || MathAbs(a-ea)>0.001) || MathAbs(b-eb)>0.001; + //--- Test for VarA,VarB,P (P is being tested only for N>2) + for(i=0;i<=qcnt-1;i++) + qvals[i]=0; + ea=2*CMath::RandomReal()-1; + eb=2*CMath::RandomReal()-1; + //--- function calls + GenerateTask(ea,eb,-(5*CMath::RandomReal()),5*CMath::RandomReal(),n>4,1.0,2.0,n,xy,s); + CLinReg::LRLines(xy,s,n,info,a,b,vara,varb,covab,corrab,p); + //--- check + if(info!=1) + { + slcerrors=true; + continue; + } + //--- change values + varatested=vara; + varbtested=varb; + //--- calculation + for(epass=0;epass<=estpasscount-1;epass++) + { + //--- Generate + FillTaskWithY(ea,eb,n,xy,s); + CLinReg::LRLines(xy,s,n,info,a,b,vara,varb,covab,corrab,p); + //--- check + if(info!=1) + { + slcerrors=true; + continue; + } + //--- A,B,P + //--- (P is being tested for uniformity,additional p-tests are below) + ta[epass]=a; + tb[epass]=b; + for(i=0;i<=qcnt-1;i++) + { + //--- check + if(p<=qtbl[i]) + qvals[i]=qvals[i]+1.0/(double)estpasscount; + } + } + //--- function call + CalculateMV(ta,estpasscount,mean,means,stddev,stddevs); + //--- search errors + slerrors=slerrors || MathAbs(mean-ea)/means>=sigmathreshold; + slerrors=slerrors || MathAbs(stddev-MathSqrt(varatested))/stddevs>=sigmathreshold; + //--- function call + CalculateMV(tb,estpasscount,mean,means,stddev,stddevs); + //--- search errors + slerrors=slerrors || MathAbs(mean-eb)/means>=sigmathreshold; + slerrors=slerrors || MathAbs(stddev-MathSqrt(varbtested))/stddevs>=sigmathreshold; + //--- check + if(n>2) + { + for(i=0;i<=qcnt-1;i++) + { + //--- check + if(MathAbs(qtbl[i]-qvals[i])/qsigma[i]>sigmathreshold) + slerrors=true; + } + } + //--- Additional tests for P: correlation with fit quality + if(n>2) + { + GenerateTask(ea,eb,-(5*CMath::RandomReal()),5*CMath::RandomReal(),false,0.0,0.0,n,xy,s); + for(i=0;i<=n-1;i++) + s[i]=1+CMath::RandomReal(); + //--- function call + CLinReg::LRLines(xy,s,n,info,a,b,vara,varb,covab,corrab,p); + //--- check + if(info!=1) + { + slcerrors=true; + continue; + } + //--- search errors + slerrors=slerrors || p<(double)(0.999); + //--- function call + GenerateTask(0,0,-(5*CMath::RandomReal()),5*CMath::RandomReal(),false,1.0,1.0,n,xy,s); + for(i=0;i<=n-1;i++) + { + //--- check + if(i%2==0) + xy[i].Set(1,5.0); + else + xy[i].Set(1,-5.0); + } + //--- check + if(n%2!=0) + xy[n-1].Set(1,0); + //--- function call + CLinReg::LRLines(xy,s,n,info,a,b,vara,varb,covab,corrab,p); + //--- check + if(info!=1) + { + slcerrors=true; + continue; + } + //--- search errors + slerrors=slerrors || p>0.001; + } + } + } +//--- General regression tests: +//--- Simple linear tests (small sample,optimum point,covariance) + for(n=3;n<=maxn;n++) + { + ArrayResize(s,n); + //--- Linear tests: + //--- a. random points,sigmas + //--- b. no sigmas + xy.Resize(n,2); + for(i=0;i<=n-1;i++) + { + xy[i].Set(0,2*CMath::RandomReal()-1); + xy[i].Set(1,2*CMath::RandomReal()-1); + s[i]=1+CMath::RandomReal(); + } + //--- function call + CLinReg::LRBuildS(xy,s,n,1,info,wt,ar); + //--- check + if(info!=1) + { + grconverrors=true; + continue; + } + //--- function calls + CLinReg::LRUnpack(wt,tmpweights,tmpi); + //--- search errors + CLinReg::LRLines(xy,s,n,info2,a,b,vara,varb,covab,corrab,p); + gropterrors=gropterrors || MathAbs(a-tmpweights[1])>threshold; + gropterrors=gropterrors || MathAbs(b-tmpweights[0])>threshold; + grcoverrors=grcoverrors || MathAbs(vara-ar.m_c[1][1])>threshold; + grcoverrors=grcoverrors || MathAbs(varb-ar.m_c[0][0])>threshold; + grcoverrors=grcoverrors || MathAbs(covab-ar.m_c[1][0])>threshold; + grcoverrors=grcoverrors || MathAbs(covab-ar.m_c[0][1])>threshold; + //--- function call + CLinReg::LRBuild(xy,n,1,info,wt,ar); + //--- check + if(info!=1) + { + grconverrors=true; + continue; + } + //--- function calls + CLinReg::LRUnpack(wt,tmpweights,tmpi); + CLinReg::LRLine(xy,n,info2,a,b); + //--- search errors + gropterrors=gropterrors || MathAbs(a-tmpweights[1])>threshold; + gropterrors=gropterrors || MathAbs(b-tmpweights[0])>threshold; + } +//--- S covariance versus S-less covariance. +//--- Slightly skewed task,large sample size. +//--- Will S-less subroutine estimate covariance matrix good enough? + n=1000+CMath::RandomInteger(3000); + sigma=0.1+CMath::RandomReal()*1.9; +//--- allocation + xy.Resize(n,2); + ArrayResize(s,n); +//--- change values + for(i=0;i<=n-1;i++) + { + xy[i].Set(0,1.5*CMath::RandomReal()-0.5); + xy[i].Set(1,1.2*xy[i][0]-0.3+GenerateNormal(0,sigma)); + s[i]=sigma; + } +//--- function calls + CLinReg::LRBuild(xy,n,1,info,wt,ar); + CLinReg::LRLines(xy,s,n,info2,a,b,vara,varb,covab,corrab,p); +//--- check + if(info!=1 || info2!=1) + grconverrors=true; + else + { + grcoverrors=grcoverrors || MathAbs(MathLog(ar.m_c[0][0]/varb))>MathLog(1.2); + grcoverrors=grcoverrors || MathAbs(MathLog(ar.m_c[1][1]/vara))>MathLog(1.2); + grcoverrors=grcoverrors || MathAbs(MathLog(ar.m_c[0][1]/covab))>MathLog(1.2); + grcoverrors=grcoverrors || MathAbs(MathLog(ar.m_c[1][0]/covab))>MathLog(1.2); + } +//--- 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. + for(modeltype=0;modeltype<=1;modeltype++) + { + for(tasktype=0;tasktype<=3;tasktype++) + { + //--- check + if(tasktype==0) + { + m1=1; + m2=3; + } + //--- check + if(tasktype==1) + { + m1=9; + m2=9; + } + //--- check + if(tasktype==2 || tasktype==3) + { + m1=9; + m2=9; + } + //--- calculation + for(m=m1;m<=m2;m++) + { + //--- check + if(tasktype==0) + { + n1=m+3; + n2=m+20; + } + //--- check + if(tasktype==1) + { + n1=70+CMath::RandomInteger(70); + n2=n1; + } + //--- check + if(tasktype==2 || tasktype==3) + { + n1=100; + n2=n1; + } + for(n=n1;n<=n2;n++) + { + //--- allocation + xy.Resize(n,m+1); + ArrayResize(xy0,n); + ArrayResize(s,n); + hstep=0.001; + noiselevel=0.2; + //--- Prepare task + if(tasktype==0) + { + for(i=0;i<=n-1;i++) + xy[i].Set(0,2*CMath::RandomReal()-1); + for(i=0;i<=n-1;i++) + { + for(j=1;j<=m-1;j++) + xy[i].Set(j,xy[i][0]*xy[i][j-1]); + } + sinshift=CMath::RandomReal()*M_PI; + //--- calculation + for(i=0;i<=n-1;i++) + { + xy0[i]=MathSin(sinshift+M_PI*0.5*(xy[i][0]+1)); + xy[i].Set(m,xy0[i]+noiselevel*GenerateNormal(0,1)); + } + } + //--- check + if(tasktype==1) + { + //--- check + if(!CAp::Assert(m==9)) + return(false); + //--- allocation + ArrayResize(ta,9); + //--- change values + ta[0]=1; + ta[1]=2; + ta[2]=3; + ta[3]=0.25; + ta[4]=0.5; + ta[5]=0.75; + ta[6]=0.06; + ta[7]=0.12; + ta[8]=0.18; + //--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + xy[i].Set(j,0); + xy[i].Set(i%3,1); + xy[i].Set(3+i/3%3,1); + xy[i].Set(6+i/9%3,1); + //--- change value + v=0.0; + for(i_=0;i_<=8;i_++) + v+=xy[i][i_]*ta[i_]; + xy0[i]=v; + xy[i].Set(m,v+noiselevel*GenerateNormal(0,1)); + } + } + //--- check + if(tasktype==2 || tasktype==3) + { + //--- check + if(!CAp::Assert(m==9)) + return(false); + //--- allocation + ArrayResize(ta,9); + //--- change values + ta[0]=1; + ta[1]=-2; + ta[2]=3; + ta[3]=0.25; + ta[4]=-0.5; + ta[5]=0.75; + ta[6]=-0.06; + ta[7]=0.12; + ta[8]=-0.18; + //--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + { + //--- check + if(tasktype==2) + xy[i].Set(j,1+GenerateNormal(0,3)); + else + xy[i].Set(j,1+GenerateNormal(0,0.05)); + } + //--- change value + v=0.0; + for(i_=0;i_<=8;i_++) + v+=xy[i][i_]*ta[i_]; + xy0[i]=v; + xy[i].Set(m,v+noiselevel*GenerateNormal(0,1)); + } + } + for(i=0;i<=n-1;i++) + s[i]=1+CMath::RandomReal(); + //--- Solve (using S-variant,non-S-variant is not tested) + if(modeltype==0) + CLinReg::LRBuildS(xy,s,n,m,info,wt,ar); + else + CLinReg::LRBuildZS(xy,s,n,m,info,wt,ar); + //--- check + if(info!=1) + { + grconverrors=true; + continue; + } + //--- function call + CLinReg::LRUnpack(wt,tmpweights,tmpi); + //--- LRProcess test + ArrayResize(x,m); + //--- change values + v=tmpweights[m]; + for(i=0;i<=m-1;i++) + { + x[i]=2*CMath::RandomReal()-1; + v=v+tmpweights[i]*x[i]; + } + //--- search errors + grothererrors=grothererrors || MathAbs(v-CLinReg::LRProcess(wt,x))/MathMax(MathAbs(v),1)>threshold; + //--- LRPack test + CLinReg::LRPack(tmpweights,m,wt2); + ArrayResize(x,m); + for(i=0;i<=m-1;i++) + x[i]=2*CMath::RandomReal()-1; + v=CLinReg::LRProcess(wt,x); + grothererrors=grothererrors || MathAbs(v-CLinReg::LRProcess(wt2,x))/MathAbs(v)>threshold; + //--- Optimality test + for(k=0;k<=m;k++) + { + //--- check + 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; + } + //--- change values + f=0; + fp=0; + fm=0; + //--- calculation + for(i=0;i<=n-1;i++) + { + v=tmpweights[m]; + for(j=0;j<=m-1;j++) + v=v+xy[i][j]*tmpweights[j]; + f=f+CMath::Sqr((v-xy[i][m])/s[i]); + //--- check + if(kfp) || f>fm; + } + //--- Covariance matrix test: + //--- generate random vector,project coefficients on it, + //--- compare variance of projection with estimate provided + //--- by cov.matrix + ArrayResize(ta,estpasscount); + ArrayResize(tb,m+1); + ArrayResize(tc,m+1); + xy2.Resize(n,m+1); + for(i=0;i<=m;i++) + tb[i]=GenerateNormal(0,1); + //--- calculation + for(epass=0;epass<=estpasscount-1;epass++) + { + for(i=0;i<=n-1;i++) + { + for(i_=0;i_<=m-1;i_++) + xy2[i].Set(i_,xy[i][i_]); + xy2[i].Set(m,xy0[i]+s[i]*GenerateNormal(0,1)); + } + //--- check + if(modeltype==0) + CLinReg::LRBuildS(xy2,s,n,m,info,wt,ar2); + else + CLinReg::LRBuildZS(xy2,s,n,m,info,wt,ar2); + //--- check + if(info!=1) + { + ta[epass]=0; + grconverrors=true; + continue; + } + //--- function call + CLinReg::LRUnpack(wt,w2,tmpi); + //--- change value + v=0.0; + for(i_=0;i_<=m;i_++) + v+=tb[i_]*w2[i_]; + ta[epass]=v; + } + //--- function call + CalculateMV(ta,estpasscount,mean,means,stddev,stddevs); + for(i=0;i<=m;i++) + { + //--- change value + v=0.0; + for(i_=0;i_<=m;i_++) + v+=tb[i_]*ar.m_c[i_][i]; + tc[i]=v; + } + //--- change value + v=0.0; + for(i_=0;i_<=m;i_++) + v+=tc[i_]*tb[i_]; + //--- search errors + grcoverrors=grcoverrors || MathAbs((MathSqrt(v)-stddev)/stddevs)>=sigmathreshold; + //--- Test for the fast CV error: + //--- calculate CV error by definition (leaving out N + //--- points and recalculating solution). + //--- Test for the training set error + cvrmserror=0; + cvavgerror=0; + cvavgrelerror=0; + rmserror=0; + avgerror=0; + avgrelerror=0; + xy2.Resize(n-1,m+1); + ArrayResize(s2,n-1); + //--- change values + for(i=0;i<=n-2;i++) + { + for(i_=0;i_<=m;i_++) + xy2[i].Set(i_,xy[i+1][i_]); + s2[i]=s[i+1]; + } + //--- calculation + for(i=0;i<=n-1;i++) + { + //--- Trn + v=0.0; + for(i_=0;i_<=m-1;i_++) + v+=xy[i][i_]*tmpweights[i_]; + v=v+tmpweights[m]; + //--- search errors + rmserror=rmserror+CMath::Sqr(v-xy[i][m]); + avgerror=avgerror+MathAbs(v-xy[i][m]); + avgrelerror=avgrelerror+MathAbs((v-xy[i][m])/xy[i][m]); + //--- CV: non-defect vectors only + nondefect=true; + for(k=0;k<=ar.m_ncvdefects-1;k++) + { + //--- check + if(ar.m_cvdefects[k]==i) + nondefect=false; + } + //--- check + if(nondefect) + { + //--- check + if(modeltype==0) + CLinReg::LRBuildS(xy2,s2,n-1,m,info2,wt,ar2); + else + CLinReg::LRBuildZS(xy2,s2,n-1,m,info2,wt,ar2); + //--- check + if(info2!=1) + { + grconverrors=true; + continue; + } + //--- function call + CLinReg::LRUnpack(wt,w2,tmpi); + //--- change value + v=0.0; + for(i_=0;i_<=m-1;i_++) + v+=xy[i][i_]*w2[i_]; + v=v+w2[m]; + //--- search errors + cvrmserror=cvrmserror+CMath::Sqr(v-xy[i][m]); + cvavgerror=cvavgerror+MathAbs(v-xy[i][m]); + cvavgrelerror=cvavgrelerror+MathAbs((v-xy[i][m])/xy[i][m]); + } + //--- Next set + if(i!=n-1) + { + for(i_=0;i_<=m;i_++) + xy2[i].Set(i_,xy[i][i_]); + s2[i]=s[i]; + } + } + //--- search errors + cvrmserror=MathSqrt(cvrmserror/(n-ar.m_ncvdefects)); + cvavgerror=cvavgerror/(n-ar.m_ncvdefects); + cvavgrelerror=cvavgrelerror/(n-ar.m_ncvdefects); + rmserror=MathSqrt(rmserror/n); + avgerror=avgerror/n; + avgrelerror=avgrelerror/n; + gresterrors=gresterrors || MathAbs(MathLog(ar.m_cvrmserror/cvrmserror))>MathLog(1+1.0E-5); + gresterrors=gresterrors || MathAbs(MathLog(ar.m_cvavgerror/cvavgerror))>MathLog(1+1.0E-5); + gresterrors=gresterrors || MathAbs(MathLog(ar.m_cvavgrelerror/cvavgrelerror))>MathLog(1+1.0E-5); + gresterrors=gresterrors || MathAbs(MathLog(ar.m_rmserror/rmserror))>MathLog(1+1.0E-5); + gresterrors=gresterrors || MathAbs(MathLog(ar.m_avgerror/avgerror))>MathLog(1+1.0E-5); + gresterrors=gresterrors || MathAbs(MathLog(ar.m_avgrelerror/avgrelerror))>MathLog(1+1.0E-5); + } + } + } + } +//--- Additional subroutines + for(pass=1;pass<=50;pass++) + { + n=2; + //--- cycle + do + { + noiselevel=CMath::RandomReal()+0.1; + tasklevel=2*CMath::RandomReal()-1; + } + while(MathAbs(noiselevel-tasklevel)<=0.05); + //--- allocation + xy.Resize(3*n,2); + //--- change values + for(i=0;i<=n-1;i++) + { + xy[3*i+0].Set(0,i); + xy[3*i+1].Set(0,i); + xy[3*i+2].Set(0,i); + xy[3*i+0].Set(1,tasklevel-noiselevel); + xy[3*i+1].Set(1,tasklevel); + xy[3*i+2].Set(1,tasklevel+noiselevel); + } + //--- function call + CLinReg::LRBuild(xy,3*n,1,info,wt,ar); + //--- check + if(info==1) + { + //--- function calls + CLinReg::LRUnpack(wt,tmpweights,tmpi); + v=CLinReg::LRRMSError(wt,xy,3*n); + //--- search errors + grothererrors=grothererrors || MathAbs(v-noiselevel*MathSqrt(2.0/3.0))>threshold; + //--- function call + v=CLinReg::LRAvgError(wt,xy,3*n); + //--- search errors + grothererrors=grothererrors || MathAbs(v-noiselevel*(2.0/3.0))>threshold; + //--- function call + v=CLinReg::LRAvgRelError(wt,xy,3*n); + vv=(MathAbs(noiselevel/(tasklevel-noiselevel))+MathAbs(noiselevel/(tasklevel+noiselevel)))/3; + //--- search errors + grothererrors=grothererrors || MathAbs(v-vv)>threshold*vv; + } + else + grothererrors=true; + //--- change values + for(i=0;i<=n-1;i++) + { + xy[3*i+0].Set(0,i); + xy[3*i+1].Set(0,i); + xy[3*i+2].Set(0,i); + xy[3*i+0].Set(1,-noiselevel); + xy[3*i+1].Set(1,0); + xy[3*i+2].Set(1,noiselevel); + } + //--- function call + CLinReg::LRBuild(xy,3*n,1,info,wt,ar); + //--- check + if(info==1) + { + //--- function calls + CLinReg::LRUnpack(wt,tmpweights,tmpi); + v=CLinReg::LRAvgRelError(wt,xy,3*n); + //--- search errors + grothererrors=grothererrors || MathAbs(v-1)>threshold; + } + else + grothererrors=true; + } +//--- calculation + for(pass=1;pass<=10;pass++) + { + m=1+CMath::RandomInteger(5); + n=10+CMath::RandomInteger(10); + //--- allocation + xy.Resize(n,m+1); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m;j++) + xy[i].Set(j,2*CMath::RandomReal()-1); + } + //--- function call + CLinReg::LRBuild(xy,n,m,info,w,ar); + //--- check + if(info<0) + { + grothererrors=true; + break; + } + //--- allocation + ArrayResize(x1,m); + ArrayResize(x2,m); + //--- Same inputs on original leads to same outputs + //--- on copy created using LRCopy + UnsetLR(wt); + CLinReg::LRCopy(w,wt); + //--- change values + for(i=0;i<=m-1;i++) + { + x1[i]=2*CMath::RandomReal()-1; + x2[i]=x1[i]; + } + //--- change values + y1=CLinReg::LRProcess(w,x1); + y2=CLinReg::LRProcess(wt,x2); + allsame=y1==y2; + //--- search errors + grothererrors=grothererrors || !allsame; + } +//--- TODO: Degenerate tests (when design matrix and right part are zero) +//--- Final report + waserrors=(((((slerrors || slcerrors) || gropterrors) || grcoverrors) || gresterrors) || grothererrors) || grconverrors; +//--- check + if(!silent) + { + Print("REGRESSION TEST"); + Print("STRAIGHT LINE REGRESSION: "); + //--- check + if(!slerrors) + Print("OK"); + else + Print("FAILED"); + Print("STRAIGHT LINE REGRESSION CONVERGENCE: "); + //--- check + if(!slcerrors) + Print("OK"); + else + Print("FAILED"); + Print("GENERAL LINEAR REGRESSION: "); + //--- check + if(!((((gropterrors || grcoverrors) || gresterrors) || grothererrors) || grconverrors)) + Print("OK"); + else + Print("FAILED"); + Print("* OPTIMALITY: "); + //--- check + if(!gropterrors) + Print("OK"); + else + Print("FAILED"); + Print("* COV. MATRIX: "); + //--- check + if(!grcoverrors) + Print("OK"); + else + Print("FAILED"); + Print("* ERROR ESTIMATES: "); + //--- check + if(!gresterrors) + Print("OK"); + else + Print("FAILED"); + Print("* CONVERGENCE: "); + //--- check + if(!grconverrors) + Print("OK"); + else + Print("FAILED"); + Print("* OTHER SUBROUTINES: "); + //--- check + if(!grothererrors) + Print("OK"); + else + Print("FAILED"); + //--- check + if(waserrors) + Print("TEST SUMMARY: FAILED"); + else + Print("TEST SUMMARY: PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Task generation. Meaningless task,just random numbers. | +//+------------------------------------------------------------------+ +static void CTestLinRegUnit::GenerateRandomTask(const double xl,const double xr, + const bool randomx,const double ymin, + const double ymax,const double smin, + const double smax,const int n, + CMatrixDouble &xy,double &s[]) + { +//--- create a variable + int i=0; +//--- allocation + xy.Resize(n,2); + ArrayResize(s,n); +//--- calculation + for(i=0;i<=n-1;i++) + { + //--- check + if(randomx) + xy[i].Set(0,xl+(xr-xl)*CMath::RandomReal()); + else + xy[i].Set(0,xl+(xr-xl)*i/(n-1)); + //--- calculation + xy[i].Set(1,ymin+(ymax-ymin)*CMath::RandomReal()); + s[i]=smin+(smax-smin)*CMath::RandomReal(); + } + } +//+------------------------------------------------------------------+ +//| Task generation. | +//+------------------------------------------------------------------+ +static void CTestLinRegUnit::GenerateTask(const double a,const double b, + const double xl,const double xr, + const bool randomx,const double smin, + const double smax,const int n, + CMatrixDouble &xy,double &s[]) + { +//--- create a variable + int i=0; +//--- allocation + xy.Resize(n,2); + ArrayResize(s,n); +//--- calculation + for(i=0;i<=n-1;i++) + { + //--- check + if(randomx) + xy[i].Set(0,xl+(xr-xl)*CMath::RandomReal()); + else + xy[i].Set(0,xl+(xr-xl)*i/(n-1)); + //--- change values + s[i]=smin+(smax-smin)*CMath::RandomReal(); + xy[i].Set(1,a+b*xy[i][0]+GenerateNormal(0,s[i])); + } + } +//+------------------------------------------------------------------+ +//| Task generation. | +//| y[i] are filled based on A,B,X[I],S[I] | +//+------------------------------------------------------------------+ +static void CTestLinRegUnit::FillTaskWithY(const double a,const double b, + const int n,CMatrixDouble &xy, + double &s[]) + { +//--- create variables + int i=0; +//--- change values + for(i=0;i<=n-1;i++) + xy[i].Set(1,a+b*xy[i][0]+GenerateNormal(0,s[i])); + } +//+------------------------------------------------------------------+ +//| Normal random numbers | +//+------------------------------------------------------------------+ +static double CTestLinRegUnit::GenerateNormal(const double mean,const double sigma) + { +//--- create variables + double result=0; + double u=0; + double v=0; + double sum=0; +//--- initialization + result=mean; +//--- calculation + while(true) + { + //--- change values + u=(2*CMath::RandomInteger(2)-1)*CMath::RandomReal(); + v=(2*CMath::RandomInteger(2)-1)*CMath::RandomReal(); + sum=u*u+v*v; + //--- check + if(sum<1.0 && sum>0.0) + { + sum=MathSqrt(-(2*MathLog(sum)/sum)); + result=sigma*u*sum+mean; + //--- return result + return(result); + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Moments estimates and their errors | +//+------------------------------------------------------------------+ +static void CTestLinRegUnit::CalculateMV(double &x[],const int n,double &mean, + double &means,double &stddev, + double &stddevs) + { +//--- create variables + int i=0; + double v1=0; + double v2=0; + double variance=0; +//--- initialization + mean=0; + means=1; + stddev=0; + stddevs=1; + variance=0; +//--- check + if(n<=1) + return; +//--- Mean + for(i=0;i<=n-1;i++) + mean=mean+x[i]; + mean=mean/n; +//--- Variance (using corrected two-pass algorithm) + if(n!=1) + { + //--- change value + v1=0; + for(i=0;i<=n-1;i++) + v1=v1+CMath::Sqr(x[i]-mean); + //--- change value + v2=0; + for(i=0;i<=n-1;i++) + v2=v2+(x[i]-mean); + v2=CMath::Sqr(v2)/n; + //--- calculation + variance=(v1-v2)/(n-1); + //--- check + if(variance<0.0) + variance=0; + stddev=MathSqrt(variance); + } +//--- Errors + means=stddev/MathSqrt(n); + stddevs=stddev*MathSqrt(2)/MathSqrt(n-1); + } +//+------------------------------------------------------------------+ +//| Unsets LR | +//+------------------------------------------------------------------+ +static void CTestLinRegUnit::UnsetLR(CLinearModel &lr) + { +//--- create variables + int info=0; + int i=0; +//--- create matrix + CMatrixDouble xy; +//--- object of class + CLRReport rep; +//--- allocation + xy.Resize(6,2); +//--- change values + for(i=0;i<=5;i++) + { + xy[i].Set(0,0); + xy[i].Set(1,0); + } +//--- function call + CLinReg::LRBuild(xy,6,1,info,lr,rep); +//--- check + if(!CAp::Assert(info>0)) + return; + } +//+------------------------------------------------------------------+ +//| Testing class CXblas | +//+------------------------------------------------------------------+ +class CTestXBlasUnit + { +public: + //--- constructor, destructor + CTestXBlasUnit(void); + ~CTestXBlasUnit(void); + //--- public method + static bool TestXBlas(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestXBlasUnit::CTestXBlasUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestXBlasUnit::~CTestXBlasUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CXblas | +//+------------------------------------------------------------------+ +static bool CTestXBlasUnit::TestXBlas(const bool silent) + { +//--- create variables + bool approxerrors; + bool exactnesserrors; + bool waserrors; + double approxthreshold=0; + int maxn=0; + int passcount=0; + int n=0; + int i=0; + int pass=0; + double rv1=0; + double rv2=0; + double rv2err=0; + complex cv1=0; + complex cv2=0; + double cv2err=0; + double s=0; + int i_=0; +//--- create arrays + double rx[]; + double ry[]; + complex cx[]; + complex cy[]; + double temp[]; +//--- initialization + approxerrors=false; + exactnesserrors=false; + waserrors=false; + approxthreshold=1000*CMath::m_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 + ArrayResize(rx,n); + ArrayResize(ry,n); + ArrayResize(temp,n); + //--- change values + for(i=0;i<=n-1;i++) + { + //--- check + if(CMath::RandomReal()>0.2) + rx[i]=2*CMath::RandomReal()-1; + else + rx[i]=0; + //--- check + if(CMath::RandomReal()>0.2) + ry[i]=2*CMath::RandomReal()-1; + else + ry[i]=0; + } + //--- change value + rv1=0.0; + for(i_=0;i_<=n-1;i_++) + rv1+=rx[i_]*ry[i_]; + //--- function call + CXblas::XDot(rx,ry,n,temp,rv2,rv2err); + //--- search errors + approxerrors=approxerrors || MathAbs(rv1-rv2)>approxthreshold; + //--- ability to approximately calculate complex dot product + ArrayResize(cx,n); + ArrayResize(cy,n); + ArrayResize(temp,2*n); + //--- change values + for(i=0;i<=n-1;i++) + { + //--- check + if(CMath::RandomReal()>0.2) + { + cx[i].re=2*CMath::RandomReal()-1; + cx[i].im=2*CMath::RandomReal()-1; + } + else + cx[i]=0; + //--- check + if(CMath::RandomReal()>0.2) + { + cy[i].re=2*CMath::RandomReal()-1; + cy[i].im=2*CMath::RandomReal()-1; + } + else + cy[i]=0; + } + //--- change value + cv1=0.0; + for(i_=0;i_<=n-1;i_++) + cv1+=cx[i_]*cy[i_]; + //--- function call + CXblas::XCDot(cx,cy,n,temp,cv2,cv2err); + //--- search errors + approxerrors=approxerrors || CMath::AbsComplex(cv1-cv2)>approxthreshold; + } + } +//--- test of precision: real + n=50000; + ArrayResize(rx,n); + ArrayResize(ry,n); + ArrayResize(temp,n); +//--- calculation + for(pass=0;pass<=passcount-1;pass++) + { + //--- check + if(!CAp::Assert(n%2==0)) + return(false); + //--- First test: X + X + ... + X - X - X - ... - X=1*X + s=MathExp(MathMax(pass,50)); + //--- check + if(pass==passcount-1 && pass>1) + s=1E300; + //--- change values + ry[0]=(2*CMath::RandomReal()-1)*s*MathSqrt(2*CMath::RandomReal()); + for(i=1;i<=n-1;i++) + ry[i]=ry[0]; + for(i=0;i<=n/2-1;i++) + rx[i]=1; + for(i=n/2;i<=n-2;i++) + rx[i]=-1; + rx[n-1]=0; + //--- function call + CXblas::XDot(rx,ry,n,temp,rv2,rv2err); + //--- search errors + exactnesserrors=exactnesserrors || rv2err<0.0; + exactnesserrors=exactnesserrors || rv2err>4*CMath::m_machineepsilon*MathAbs(ry[0]); + exactnesserrors=exactnesserrors || MathAbs(rv2-ry[0])>rv2err; + //--- First test: X + X + ... + X=N*X + s=MathExp(MathMax(pass,50)); + //--- check + if(pass==passcount-1 && pass>1) + s=1E300; + //--- change values + ry[0]=(2*CMath::RandomReal()-1)*s*MathSqrt(2*CMath::RandomReal()); + for(i=1;i<=n-1;i++) + ry[i]=ry[0]; + for(i=0;i<=n-1;i++) + rx[i]=1; + //--- function call + CXblas::XDot(rx,ry,n,temp,rv2,rv2err); + //--- search errors + exactnesserrors=exactnesserrors || rv2err<0.0; + exactnesserrors=exactnesserrors || rv2err>4*CMath::m_machineepsilon*MathAbs(ry[0])*n; + exactnesserrors=exactnesserrors || MathAbs(rv2-n*ry[0])>rv2err; + } +//--- test of precision: complex + n=50000; + ArrayResize(cx,n); + ArrayResize(cy,n); + ArrayResize(temp,2*n); +//--- calculation + for(pass=0;pass<=passcount-1;pass++) + { + //--- check + if(!CAp::Assert(n%2==0)) + return(false); + //--- First test: X + X + ... + X - X - X - ... - X=1*X + s=MathExp(MathMax(pass,50)); + //--- check + if(pass==passcount-1 && pass>1) + s=1E300; + //--- change values + cy[0].re=(2*CMath::RandomReal()-1)*s*MathSqrt(2*CMath::RandomReal()); + cy[0].im=(2*CMath::RandomReal()-1)*s*MathSqrt(2*CMath::RandomReal()); + for(i=1;i<=n-1;i++) + cy[i]=cy[0]; + for(i=0;i<=n/2-1;i++) + cx[i]=1; + for(i=n/2;i<=n-2;i++) + cx[i]=-1; + cx[n-1]=0; + //--- function call + CXblas::XCDot(cx,cy,n,temp,cv2,cv2err); + //--- search errors + exactnesserrors=exactnesserrors || cv2err<0.0; + exactnesserrors=exactnesserrors || cv2err>4*CMath::m_machineepsilon*CMath::AbsComplex(cy[0]); + exactnesserrors=exactnesserrors || CMath::AbsComplex(cv2-cy[0])>cv2err; + //--- First test: X + X + ... + X=N*X + s=MathExp(MathMax(pass,50)); + //--- check + if(pass==passcount-1 && pass>1) + s=1E300; + //--- change values + cy[0]=(2*CMath::RandomReal()-1)*s*MathSqrt(2*CMath::RandomReal()); + for(i=1;i<=n-1;i++) + cy[i]=cy[0]; + for(i=0;i<=n-1;i++) + cx[i]=1; + //--- function call + CXblas::XCDot(cx,cy,n,temp,cv2,cv2err); + //--- search errors + exactnesserrors=exactnesserrors || cv2err<0.0; + exactnesserrors=exactnesserrors || cv2err>4*CMath::m_machineepsilon*CMath::AbsComplex(cy[0])*n; + exactnesserrors=exactnesserrors || CMath::AbsComplex(cv2-cy[0]*n)>cv2err; + } +//--- report + waserrors=approxerrors || exactnesserrors; +//--- check + if(!silent) + { + Print("TESTING XBLAS"); + Print("APPROX.TESTS: "); + //--- check + if(approxerrors) + Print("FAILED"); + else + Print("OK"); + Print("EXACT TESTS: "); + //--- check + if(exactnesserrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- end +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Testing class CDenseSolver | +//+------------------------------------------------------------------+ +class CTestDenseSolverUnit + { +private: + //--- private methods + static bool RMatrixCheckSolutionM(CMatrixDouble &xe,const int n,const int m,const double threshold,const int info,CDenseSolverReport &rep,CMatrixDouble &xs); + static bool RMatrixCheckSolution(CMatrixDouble &xe,const int n,const double threshold,const int info,CDenseSolverReport &rep,double &xs[]); + static bool RMatrixCheckSingularM(const int n,const int m,const int info,CDenseSolverReport &rep,CMatrixDouble &xs); + static bool RMatrixCheckSingular(const int n,const int info,CDenseSolverReport &rep,double &xs[]); + static bool CMatrixCheckSolutionM(CMatrixComplex &xe,const int n,const int m,const double threshold,const int info,CDenseSolverReport &rep,CMatrixComplex &xs); + static bool CMatrixCheckSolution(CMatrixComplex &xe,const int n,const double threshold,const int info,CDenseSolverReport &rep,complex &xs[]); + static bool CMatrixCheckSingularM(const int n,const int m,const int info,CDenseSolverReport &rep,CMatrixComplex &xs); + static bool CMatrixCheckSingular(const int n,const int info,CDenseSolverReport &rep,complex &xs[]); + static void RMatrixMakeACopy(CMatrixDouble &a,const int m,const int n,CMatrixDouble &b); + static void CMatrixMakeACopy(CMatrixComplex &a,const int m,const int n,CMatrixComplex &b); + static void RMatrixDropHalf(CMatrixDouble &a,const int n,const bool droplower); + static void CMatrixDropHalf(CMatrixComplex &a,const int n,const bool droplower); + static void TestRSolver(const int maxn,const int maxm,const int passcount,const double threshold,bool &rerrors,bool &rfserrors); + static void TestSPDSolver(const int maxn,const int maxm,const int passcount,const double threshold,bool &spderrors,bool &rfserrors); + static void TestCSolver(const int maxn,const int maxm,const int passcount,const double threshold,bool &cerrors,bool &rfserrors); + static void TestHPDSolver(const int maxn,const int maxm,const int passcount,const double threshold,bool &hpderrors,bool &rfserrors); + static void Unset2D(CMatrixDouble &x); + static void Unset1D(double &x[]); + static void CUnset2D(CMatrixComplex &x); + static void CUnset1D(complex &x[]); + static void UnsetRep(CDenseSolverReport &r); + static void UnsetLSRep(CDenseSolverLSReport &r); +public: + //--- constructor, destructor + CTestDenseSolverUnit(void); + ~CTestDenseSolverUnit(void); + //--- public method + static bool TestDenseSolver(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestDenseSolverUnit::CTestDenseSolverUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestDenseSolverUnit::~CTestDenseSolverUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Test | +//+------------------------------------------------------------------+ +static bool CTestDenseSolverUnit::TestDenseSolver(const bool silent) + { +//--- create variables + int maxn=0; + int maxm=0; + int passcount=0; + double threshold=0; + bool rerrors; + bool cerrors; + bool spderrors; + bool hpderrors; + bool rfserrors; + bool waserrors; +//--- initialization + maxn=10; + maxm=5; + passcount=5; + threshold=10000*CMath::m_machineepsilon; + rfserrors=false; + rerrors=false; + cerrors=false; + spderrors=false; + hpderrors=false; +//--- function calls + TestRSolver(maxn,maxm,passcount,threshold,rerrors,rfserrors); + TestSPDSolver(maxn,maxm,passcount,threshold,spderrors,rfserrors); + TestCSolver(maxn,maxm,passcount,threshold,cerrors,rfserrors); + TestHPDSolver(maxn,maxm,passcount,threshold,hpderrors,rfserrors); +//--- search errors + waserrors=(((rerrors || cerrors) || spderrors) || hpderrors) || rfserrors; +//--- check + if(!silent) + { + Print("TESTING DENSE SOLVER"); + Print("* REAL: "); + //--- check + if(rerrors) + Print("FAILED"); + else + Print("OK"); + Print("* COMPLEX: "); + //--- check + if(cerrors) + Print("FAILED"); + else + Print("OK"); + Print("* SPD: "); + //--- check + if(spderrors) + Print("FAILED"); + else + Print("OK"); + Print("* HPD: "); + //--- check + if(hpderrors) + Print("FAILED"); + else + Print("OK"); + Print("* ITERATIVE IMPROVEMENT: "); + //--- check + if(rfserrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Checks whether solver results are correct solution. | +//| Returns True on success. | +//+------------------------------------------------------------------+ +static bool CTestDenseSolverUnit::RMatrixCheckSolutionM(CMatrixDouble &xe, + const int n,const int m, + const double threshold, + const int info, + CDenseSolverReport &rep, + CMatrixDouble &xs) + { +//--- create variables + bool result; + int i=0; + int j=0; +//--- initialization + result=true; +//--- check + if(info<=0) + result=false; + else + { + //--- calculation + result=result && !(rep.m_r1<100*CMath::m_machineepsilon || rep.m_r1>1+1000*CMath::m_machineepsilon); + result=result && !(rep.m_rinf<100*CMath::m_machineepsilon || rep.m_rinf>1+1000*CMath::m_machineepsilon); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + result=result && MathAbs(xe[i][j]-xs[i][j])<=threshold; + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Checks whether solver results are correct solution. | +//| Returns True on success. | +//+------------------------------------------------------------------+ +static bool CTestDenseSolverUnit::RMatrixCheckSolution(CMatrixDouble &xe, + const int n, + const double threshold, + const int info, + CDenseSolverReport &rep, + double &xs[]) + { +//--- create a variable + int i_=0; +//--- create matrix + CMatrixDouble xsm; +//--- allocation + xsm.Resize(n,1); +//--- change values + for(i_=0;i_<=n-1;i_++) + xsm[i_].Set(0,xs[i_]); +//--- return result + return(RMatrixCheckSolutionM(xe,n,1,threshold,info,rep,xsm)); + } +//+------------------------------------------------------------------+ +//| Checks whether solver results indicate singular matrix. | +//| Returns True on success. | +//+------------------------------------------------------------------+ +static bool CTestDenseSolverUnit::RMatrixCheckSingularM(const int n, + const int m, + const int info, + CDenseSolverReport &rep, + CMatrixDouble &xs) + { +//--- create variables + bool result; + int i=0; + int j=0; +//--- initialization + result=true; +//--- check + if(info!=-3 && info!=1) + result=false; + else + { + //--- calculation + result=result && !(rep.m_r1<0.0 || rep.m_r1>1000*CMath::m_machineepsilon); + result=result && !(rep.m_rinf<0.0 || rep.m_rinf>1000*CMath::m_machineepsilon); + //--- check + if(info==-3) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + result=result && xs[i][j]==0.0; + } + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Checks whether solver results indicate singular matrix. | +//| Returns True on success. | +//+------------------------------------------------------------------+ +static bool CTestDenseSolverUnit::RMatrixCheckSingular(const int n, + const int info, + CDenseSolverReport &rep, + double &xs[]) + { +//--- create a variable + int i_=0; +//--- create matrix + CMatrixDouble xsm; +//--- allocation + xsm.Resize(n,1); +//--- change values + for(i_=0;i_<=n-1;i_++) + xsm[i_].Set(0,xs[i_]); +//--- return result + return(RMatrixCheckSingularM(n,1,info,rep,xsm)); + } +//+------------------------------------------------------------------+ +//| Checks whether solver results are correct solution. | +//| Returns True on success. | +//+------------------------------------------------------------------+ +static bool CTestDenseSolverUnit::CMatrixCheckSolutionM(CMatrixComplex &xe, + const int n,const int m, + const double threshold, + const int info, + CDenseSolverReport &rep, + CMatrixComplex &xs) + { +//--- create variables + bool result; + int i=0; + int j=0; +//--- initialization + result=true; +//--- check + if(info<=0) + result=false; + else + { + //--- calculation + result=result && !(rep.m_r1<100*CMath::m_machineepsilon || rep.m_r1>1+1000*CMath::m_machineepsilon); + result=result && !(rep.m_rinf<100*CMath::m_machineepsilon || rep.m_rinf>1+1000*CMath::m_machineepsilon); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + result=result && CMath::AbsComplex(xe[i][j]-xs[i][j])<=threshold; + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Checks whether solver results are correct solution. | +//| Returns True on success. | +//+------------------------------------------------------------------+ +static bool CTestDenseSolverUnit::CMatrixCheckSolution(CMatrixComplex &xe, + const int n, + const double threshold, + const int info, + CDenseSolverReport &rep, + complex &xs[]) + { +//--- create a variable + int i_=0; +//--- create matrix + CMatrixComplex xsm; +//--- allocation + xsm.Resize(n,1); +//--- change values + for(i_=0;i_<=n-1;i_++) + xsm[i_].Set(0,xs[i_]); +//--- return result + return(CMatrixCheckSolutionM(xe,n,1,threshold,info,rep,xsm)); + } +//+------------------------------------------------------------------+ +//| Checks whether solver results indicate singular matrix. | +//| Returns True on success. | +//+------------------------------------------------------------------+ +static bool CTestDenseSolverUnit::CMatrixCheckSingularM(const int n, + const int m, + const int info, + CDenseSolverReport &rep, + CMatrixComplex &xs) + { +//--- create variables + bool result; + int i=0; + int j=0; +//--- initialization + result=true; +//--- check + if(info!=-3 && info!=1) + result=false; + else + { + //--- calculation + result=result && !(rep.m_r1<0.0 || rep.m_r1>1000*CMath::m_machineepsilon); + result=result && !(rep.m_rinf<0.0 || rep.m_rinf>1000*CMath::m_machineepsilon); + //--- check + if(info==-3) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + result=result && xs[i][j]==0; + } + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Checks whether solver results indicate singular matrix. | +//| Returns True on success. | +//+------------------------------------------------------------------+ +static bool CTestDenseSolverUnit::CMatrixCheckSingular(const int n, + const int info, + CDenseSolverReport &rep, + complex &xs[]) + { +//--- create variables + int i_=0; +//--- create matrix + CMatrixComplex xsm; +//--- allocation + xsm.Resize(n,1); +//--- change values + for(i_=0;i_<=n-1;i_++) + xsm[i_].Set(0,xs[i_]); +//--- return result + return(CMatrixCheckSingularM(n,1,info,rep,xsm)); + } +//+------------------------------------------------------------------+ +//| Copy | +//+------------------------------------------------------------------+ +static void CTestDenseSolverUnit::RMatrixMakeACopy(CMatrixDouble &a, + const int m, + const int n, + CMatrixDouble &b) + { +//--- create variables + int i=0; + int j=0; +//--- allocation + b.Resize(m,n); +//--- copy + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + b[i].Set(j,a[i][j]); + } + } +//+------------------------------------------------------------------+ +//| Copy | +//+------------------------------------------------------------------+ +static void CTestDenseSolverUnit::CMatrixMakeACopy(CMatrixComplex &a, + const int m, + const int n, + CMatrixComplex &b) + { +//--- create variables + int i=0; + int j=0; +//--- allocation + b.Resize(m,n); +//--- copy + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + b[i].Set(j,a[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 CTestDenseSolverUnit::RMatrixDropHalf(CMatrixDouble &a, + const int n, + const bool droplower) + { +//--- create variables + int i=0; + int j=0; +//--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if((droplower && i>j) || (!droplower && ij) || (!droplower && i0.5,info,rep,x); + //--- search errors + rerrors=rerrors || !RMatrixCheckSolutionM(xe,n,m,threshold,info,rep,x); + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + Unset1D(xv); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- function call + CDenseSolver::RMatrixSolve(a,n,bv,info,rep,xv); + //--- search errors + rerrors=rerrors || !RMatrixCheckSolution(xe,n,threshold,info,rep,xv); + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + Unset2D(x); + CDenseSolver::RMatrixLUSolveM(lua,p,n,b,m,info,rep,x); + //--- search errors + rerrors=rerrors || !RMatrixCheckSolutionM(xe,n,m,threshold,info,rep,x); + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + Unset1D(xv); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- function call + CDenseSolver::RMatrixLUSolve(lua,p,n,bv,info,rep,xv); + //--- search errors + rerrors=rerrors || !RMatrixCheckSolution(xe,n,threshold,info,rep,xv); + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + Unset2D(x); + CDenseSolver::RMatrixMixedSolveM(a,lua,p,n,b,m,info,rep,x); + //--- search errors + rerrors=rerrors || !RMatrixCheckSolutionM(xe,n,m,threshold,info,rep,x); + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + Unset1D(xv); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- function call + CDenseSolver::RMatrixMixedSolve(a,lua,p,n,bv,info,rep,xv); + //--- search errors + rerrors=rerrors || !RMatrixCheckSolution(xe,n,threshold,info,rep,xv); + //--- 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; + UnsetLSRep(repls); + Unset1D(xv); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- function call + CDenseSolver::RMatrixSolveLS(a,n,n,bv,0.0,info,repls,xv); + //--- check + if(info<=0) + rerrors=true; + else + { + //--- search errors + rerrors=(rerrors || repls.m_r2<100*CMath::m_machineepsilon) || repls.m_r2>1+1000*CMath::m_machineepsilon; + rerrors=(rerrors || repls.m_n!=n) || repls.m_k!=0; + for(i=0;i<=n-1;i++) + rerrors=rerrors || MathAbs(xe[i][0]-xv[i])>threshold; + } + //--- change value + info=0; + //--- function calls + UnsetLSRep(repls); + Unset1D(xv); + //--- allocation + ArrayResize(bv,2*n); + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- change value + i1_=-n; + for(i_=n;i_<=2*n-1;i_++) + bv[i_]=b[i_+i1_][0]; + //--- allocation + atmp.Resize(2*n,n); + //--- function calls + CBlas::CopyMatrix(a,0,n-1,0,n-1,atmp,0,n-1,0,n-1); + CBlas::CopyMatrix(a,0,n-1,0,n-1,atmp,n,2*n-1,0,n-1); + CDenseSolver::RMatrixSolveLS(atmp,2*n,n,bv,0.0,info,repls,xv); + //--- check + if(info<=0) + rerrors=true; + else + { + //--- search errors + rerrors=(rerrors || repls.m_r2<100*CMath::m_machineepsilon) || repls.m_r2>1+1000*CMath::m_machineepsilon; + rerrors=(rerrors || repls.m_n!=n) || repls.m_k!=0; + for(i=0;i<=n-1;i++) + rerrors=rerrors || MathAbs(xe[i][0]-xv[i])>threshold; + } + //--- change value + info=0; + //--- function calls + UnsetLSRep(repls); + Unset1D(xv); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- allocation + atmp.Resize(n,2*n); + CBlas::CopyMatrix(a,0,n-1,0,n-1,atmp,0,n-1,0,n-1); + for(i=0;i<=n-1;i++) + { + for(j=n;j<=2*n-1;j++) + atmp[i].Set(j,0); + } + //--- function call + CDenseSolver::RMatrixSolveLS(atmp,n,2*n,bv,0.0,info,repls,xv); + //--- check + if(info<=0) + rerrors=true; + else + { + //--- search errors + rerrors=rerrors || repls.m_r2!=0.0; + rerrors=(rerrors || repls.m_n!=2*n) || repls.m_k!=n; + for(i=0;i<=n-1;i++) + rerrors=rerrors || MathAbs(xe[i][0]-xv[i])>threshold; + for(i=n;i<=2*n-1;i++) + rerrors=rerrors || MathAbs(xv[i])>threshold; + } + //--- ******************************************************** + //--- 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++) + { + Unset2D(a); + //--- check + if(taskkind==0) + { + //--- all zeros + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,0); + } + } + //--- check + if(taskkind==1) + { + //--- there is zero column + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,2*CMath::RandomReal()-1); + } + //--- change values + k=CMath::RandomInteger(n); + for(i_=0;i_<=n-1;i_++) + a[i_].Set(k,0*a[i_][k]); + } + //--- check + if(taskkind==2) + { + //--- there is zero row + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,2*CMath::RandomReal()-1); + } + //--- change values + k=CMath::RandomInteger(n); + for(i_=0;i_<=n-1;i_++) + a[k].Set(i_,0*a[k][i_]); + } + //--- check + if(taskkind==3) + { + //--- equal columns + if(n<2) + continue; + //--- change values + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,2*CMath::RandomReal()-1); + } + //--- change values + k=1+CMath::RandomInteger(n-1); + for(i_=0;i_<=n-1;i_++) + a[i_].Set(0,a[i_][k]); + } + //--- check + if(taskkind==4) + { + //--- equal rows + if(n<2) + continue; + //--- change values + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,2*CMath::RandomReal()-1); + } + //--- change values + k=1+CMath::RandomInteger(n-1); + for(i_=0;i_<=n-1;i_++) + a[0].Set(i_,a[k][i_]); + } + //--- allocation + xe.Resize(n,m); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + xe[i].Set(j,2*CMath::RandomReal()-1); + } + //--- allocation + b.Resize(n,m); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a[i][i_]*xe[i_][j]; + b[i].Set(j,v); + } + } + //--- function calls + RMatrixMakeACopy(a,n,n,lua); + CTrFac::RMatrixLU(lua,n,n,p); + //--- Test RMatrixSolveM() + info=0; + //--- function calls + UnsetRep(rep); + Unset2D(x); + CDenseSolver::RMatrixSolveM(a,n,b,m,CMath::RandomReal()>0.5,info,rep,x); + //--- search errors + rerrors=rerrors || !RMatrixCheckSingularM(n,m,info,rep,x); + //--- Test RMatrixSolve() + info=0; + //--- function calls + UnsetRep(rep); + Unset2D(x); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- function call + CDenseSolver::RMatrixSolve(a,n,bv,info,rep,xv); + //--- search errors + rerrors=rerrors || !RMatrixCheckSingular(n,info,rep,xv); + //--- Test RMatrixLUSolveM() + info=0; + //--- function calls + UnsetRep(rep); + Unset2D(x); + CDenseSolver::RMatrixLUSolveM(lua,p,n,b,m,info,rep,x); + //--- search errors + rerrors=rerrors || !RMatrixCheckSingularM(n,m,info,rep,x); + //--- Test RMatrixLUSolve() + info=0; + //--- function calls + UnsetRep(rep); + Unset2D(x); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- function call + CDenseSolver::RMatrixLUSolve(lua,p,n,bv,info,rep,xv); + //--- search errors + rerrors=rerrors || !RMatrixCheckSingular(n,info,rep,xv); + //--- Test RMatrixMixedSolveM() + info=0; + //--- function calls + UnsetRep(rep); + Unset2D(x); + CDenseSolver::RMatrixMixedSolveM(a,lua,p,n,b,m,info,rep,x); + //--- search errors + rerrors=rerrors || !RMatrixCheckSingularM(n,m,info,rep,x); + //--- Test RMatrixMixedSolve() + info=0; + //--- function calls + UnsetRep(rep); + Unset2D(x); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- function call + CDenseSolver::RMatrixMixedSolve(a,lua,p,n,bv,info,rep,xv); + //--- search errors + rerrors=rerrors || !RMatrixCheckSingular(n,info,rep,xv); + } + } + } + } +//--- 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; + a.Resize(n,n); + b.Resize(n,1); + ArrayResize(bv,n); + ArrayResize(tx,n); + ArrayResize(xv,n); + ArrayResize(y,n); + //--- change values + for(i=0;i<=n-1;i++) + xv[i]=2*CMath::RandomReal()-1; + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,2*CMath::RandomReal()-1); + for(i_=0;i_<=n-1;i_++) + y[i_]=a[i][i_]; + //--- function call + CXblas::XDot(y,xv,n,tx,v,verr); + bv[i]=v; + } + //--- change values + for(i_=0;i_<=n-1;i_++) + b[i_].Set(0,bv[i_]); + //--- Test RMatrixSolveM() + Unset2D(x); + CDenseSolver::RMatrixSolveM(a,n,b,1,true,info,rep,x); + //--- check + if(info<=0) + rfserrors=true; + else + { + //--- allocation + ArrayResize(xv,n); + for(i_=0;i_<=n-1;i_++) + xv[i_]=x[i_][0]; + for(i=0;i<=n-1;i++) + { + for(i_=0;i_<=n-1;i_++) + y[i_]=a[i][i_]; + //--- function call + CXblas::XDot(y,xv,n,tx,v,verr); + //--- search errors + rfserrors=rfserrors || MathAbs(v-b[i][0])>8*CMath::m_machineepsilon*MathMax(1,MathAbs(b[i][0])); + } + } + //--- Test RMatrixSolve() + Unset1D(xv); + CDenseSolver::RMatrixSolve(a,n,bv,info,rep,xv); + //--- check + if(info<=0) + rfserrors=true; + else + { + for(i=0;i<=n-1;i++) + { + for(i_=0;i_<=n-1;i_++) + y[i_]=a[i][i_]; + //--- function call + CXblas::XDot(y,xv,n,tx,v,verr); + //--- search errors + rfserrors=rfserrors || MathAbs(v-bv[i])>8*CMath::m_machineepsilon*MathMax(1,MathAbs(bv[i])); + } + } + //--- Test LS-solver on the same matrix + CDenseSolver::RMatrixSolveLS(a,n,n,bv,0.0,info,repls,xv); + //--- check + if(info<=0) + rfserrors=true; + else + { + for(i=0;i<=n-1;i++) + { + for(i_=0;i_<=n-1;i_++) + y[i_]=a[i][i_]; + //--- function call + CXblas::XDot(y,xv,n,tx,v,verr); + //--- search errors + rfserrors=rfserrors || MathAbs(v-bv[i])>8*CMath::m_machineepsilon*MathMax(1,MathAbs(bv[i])); + } + } + } + } +//+------------------------------------------------------------------+ +//| SPD test | +//+------------------------------------------------------------------+ +static void CTestDenseSolverUnit::TestSPDSolver(const int maxn,const int maxm, + const int passcount, + const double threshold, + bool &spderrors,bool &rfserrors) + { +//--- create variables + int i=0; + int j=0; + int k=0; + int n=0; + int m=0; + int pass=0; + int taskkind=0; + double v=0; + bool isupper; + int info=0; + int i_=0; +//--- create arrays + int p[]; + double bv[]; + double xv[]; + double y[]; + double tx[]; +//--- create matrix + CMatrixDouble a; + CMatrixDouble cha; + CMatrixDouble atmp; + CMatrixDouble xe; + CMatrixDouble b; + CMatrixDouble x; +//--- objects of class + CDenseSolverReport rep; + CDenseSolverLSReport repls; +//--- 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=CMath::RandomReal()>0.5; + CMatGen::SPDMatrixRndCond(n,1000,a); + RMatrixMakeACopy(a,n,n,cha); + //--- check + if(!CTrFac::SPDMatrixCholesky(cha,n,isupper)) + { + spderrors=true; + return; + } + //--- allocation + xe.Resize(n,m); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + xe[i].Set(j,2*CMath::RandomReal()-1); + } + //--- allocation + b.Resize(n,m); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a[i][i_]*xe[i_][j]; + b[i].Set(j,v); + } + } + //--- function calls + RMatrixDropHalf(a,n,isupper); + RMatrixDropHalf(cha,n,isupper); + //--- Test solvers + info=0; + //--- function calls + UnsetRep(rep); + Unset2D(x); + CDenseSolver::SPDMatrixSolveM(a,n,isupper,b,m,info,rep,x); + //--- search errors + spderrors=spderrors || !RMatrixCheckSolutionM(xe,n,m,threshold,info,rep,x); + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + Unset1D(xv); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- function call + CDenseSolver::SPDMatrixSolve(a,n,isupper,bv,info,rep,xv); + //--- search errors + spderrors=spderrors || !RMatrixCheckSolution(xe,n,threshold,info,rep,xv); + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + Unset2D(x); + CDenseSolver::SPDMatrixCholeskySolveM(cha,n,isupper,b,m,info,rep,x); + //--- search errors + spderrors=spderrors || !RMatrixCheckSolutionM(xe,n,m,threshold,info,rep,x); + //--- change value + info=0; + //--- function calls + UnsetRep(rep); + Unset1D(xv); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- function call + CDenseSolver::SPDMatrixCholeskySolve(cha,n,isupper,bv,info,rep,xv); + //--- search errors + spderrors=spderrors || !RMatrixCheckSolution(xe,n,threshold,info,rep,xv); + //--- ******************************************************** + //--- 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++) + { + Unset2D(a); + //--- check + if(taskkind==0) + { + //--- all zeros + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,0); + } + } + //--- check + if(taskkind==1) + { + //--- there is zero column + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=i;j<=n-1;j++) + { + a[i].Set(j,2*CMath::RandomReal()-1); + a[j].Set(i,a[i][j]); + } + } + //--- change values + k=CMath::RandomInteger(n); + for(i_=0;i_<=n-1;i_++) + a[i_].Set(k,0*a[i_][k]); + for(i_=0;i_<=n-1;i_++) + a[k].Set(i_,0*a[k][i_]); + } + //--- check + if(taskkind==2) + { + //--- there is zero row + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=i;j<=n-1;j++) + { + a[i].Set(j,2*CMath::RandomReal()-1); + a[j].Set(i,a[i][j]); + } + } + //--- change values + k=CMath::RandomInteger(n); + for(i_=0;i_<=n-1;i_++) + a[k].Set(i_,0*a[k][i_]); + for(i_=0;i_<=n-1;i_++) + a[i_].Set(k,0*a[i_][k]); + } + //--- check + if(taskkind==3) + { + //--- equal columns/rows + if(n<2) + continue; + //--- allocation + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=i;j<=n-1;j++) + { + a[i].Set(j,2*CMath::RandomReal()-1); + a[j].Set(i,a[i][j]); + } + } + //--- change values + k=1+CMath::RandomInteger(n-1); + for(i_=0;i_<=n-1;i_++) + a[i_].Set(0,a[i_][k]); + for(i_=0;i_<=n-1;i_++) + a[0].Set(i_,a[k][i_]); + } + //--- allocation + xe.Resize(n,m); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + xe[i].Set(j,2*CMath::RandomReal()-1); + } + //--- allocation + b.Resize(n,m); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a[i][i_]*xe[i_][j]; + b[i].Set(j,v); + } + } + //--- function calls + RMatrixMakeACopy(a,n,n,cha); + RMatrixDropHalf(a,n,isupper); + RMatrixDropHalf(cha,n,isupper); + //--- Test SPDMatrixSolveM() + info=0; + //--- function calls + UnsetRep(rep); + Unset2D(x); + CDenseSolver::SPDMatrixSolveM(a,n,isupper,b,m,info,rep,x); + //--- search errors + spderrors=spderrors || !RMatrixCheckSingularM(n,m,info,rep,x); + //--- Test SPDMatrixSolve() + info=0; + UnsetRep(rep); + Unset2D(x); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- function call + CDenseSolver::SPDMatrixSolve(a,n,isupper,bv,info,rep,xv); + //--- search errors + spderrors=spderrors || !RMatrixCheckSingular(n,info,rep,xv); + //--- '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() + info=0; + //--- function calls + UnsetRep(rep); + Unset2D(x); + CDenseSolver::SPDMatrixCholeskySolveM(cha,n,isupper,b,m,info,rep,x); + //--- search errors + spderrors=spderrors || !RMatrixCheckSingularM(n,m,info,rep,x); + //--- Test SPDMatrixLUSolve() + info=0; + UnsetRep(rep); + Unset2D(x); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- function call + CDenseSolver::SPDMatrixCholeskySolve(cha,n,isupper,bv,info,rep,xv); + //--- search errors + spderrors=spderrors || !RMatrixCheckSingular(n,info,rep,xv); + } + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Real test | +//+------------------------------------------------------------------+ +static void CTestDenseSolverUnit::TestCSolver(const int maxn,const int maxm, + const int passcount, + const double threshold, + bool &cerrors,bool &rfserrors) + { +//--- create variables + int i=0; + int j=0; + int k=0; + int n=0; + int m=0; + int pass=0; + int taskkind=0; + double verr=0; + complex v=0; + int info=0; + int i_=0; +//--- create arrays + int p[]; + complex bv[]; + complex xv[]; + complex y[]; + double tx[]; +//--- create matrix + CMatrixComplex a; + CMatrixComplex lua; + CMatrixComplex atmp; + CMatrixComplex xe; + CMatrixComplex b; + CMatrixComplex x; +//--- objects of classes + CDenseSolverReport rep; + CDenseSolverLSReport repls; +//--- 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 + CMatGen::CMatrixRndCond(n,1000,a); + CMatrixMakeACopy(a,n,n,lua); + CTrFac::CMatrixLU(lua,n,n,p); + //--- allocation + xe.Resize(n,m); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + { + xe[i].SetRe(j,2*CMath::RandomReal()-1); + xe[i].SetIm(j,2*CMath::RandomReal()-1); + } + } + //--- allocation + b.Resize(n,m); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a[i][i_]*xe[i_][j]; + b[i].Set(j,v); + } + } + //--- Test solvers + info=0; + //--- function calls + UnsetRep(rep); + CUnset2D(x); + CDenseSolver::CMatrixSolveM(a,n,b,m,CMath::RandomReal()>0.5,info,rep,x); + //--- search errors + cerrors=cerrors || !CMatrixCheckSolutionM(xe,n,m,threshold,info,rep,x); + //--- change values + info=0; + //--- function calls + UnsetRep(rep); + CUnset1D(xv); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- function call + CDenseSolver::CMatrixSolve(a,n,bv,info,rep,xv); + //--- search errors + cerrors=cerrors || !CMatrixCheckSolution(xe,n,threshold,info,rep,xv); + //--- change values + info=0; + //--- function calls + UnsetRep(rep); + CUnset2D(x); + CDenseSolver::CMatrixLUSolveM(lua,p,n,b,m,info,rep,x); + //--- search errors + cerrors=cerrors || !CMatrixCheckSolutionM(xe,n,m,threshold,info,rep,x); + //--- change values + info=0; + //--- function calls + UnsetRep(rep); + CUnset1D(xv); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- function call + CDenseSolver::CMatrixLUSolve(lua,p,n,bv,info,rep,xv); + //--- search errors + cerrors=cerrors || !CMatrixCheckSolution(xe,n,threshold,info,rep,xv); + //--- change values + info=0; + //--- function calls + UnsetRep(rep); + CUnset2D(x); + CDenseSolver::CMatrixMixedSolveM(a,lua,p,n,b,m,info,rep,x); + //--- search errors + cerrors=cerrors || !CMatrixCheckSolutionM(xe,n,m,threshold,info,rep,x); + //--- change values + info=0; + //--- function calls + UnsetRep(rep); + CUnset1D(xv); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- function call + CDenseSolver::CMatrixMixedSolve(a,lua,p,n,bv,info,rep,xv); + //--- search errors + cerrors=cerrors || !CMatrixCheckSolution(xe,n,threshold,info,rep,xv); + //--- ******************************************************** + //--- 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++) + { + CUnset2D(a); + //--- check + if(taskkind==0) + { + //--- all zeros + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,0); + } + } + //--- check + if(taskkind==1) + { + //--- there is zero column + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + a[i].SetRe(j,2*CMath::RandomReal()-1); + a[i].SetIm(j,2*CMath::RandomReal()-1); + } + } + //--- change values + k=CMath::RandomInteger(n); + for(i_=0;i_<=n-1;i_++) + a[i_].Set(k,a[i_][k]*0); + } + //--- check + if(taskkind==2) + { + //--- there is zero row + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + a[i].SetRe(j,2*CMath::RandomReal()-1); + a[i].SetIm(j,2*CMath::RandomReal()-1); + } + } + //--- change values + k=CMath::RandomInteger(n); + for(i_=0;i_<=n-1;i_++) + a[k].Set(i_,a[k][i_]*0); + } + //--- check + if(taskkind==3) + { + //--- equal columns + if(n<2) + continue; + //--- allocation + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + a[i].SetRe(j,2*CMath::RandomReal()-1); + a[i].SetIm(j,2*CMath::RandomReal()-1); + } + } + //--- change values + k=1+CMath::RandomInteger(n-1); + for(i_=0;i_<=n-1;i_++) + a[i_].Set(0,a[i_][k]); + } + //--- check + if(taskkind==4) + { + //--- equal rows + if(n<2) + continue; + //--- allocation + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + a[i].SetRe(j,2*CMath::RandomReal()-1); + a[i].SetIm(j,2*CMath::RandomReal()-1); + } + } + //--- change values + k=1+CMath::RandomInteger(n-1); + for(i_=0;i_<=n-1;i_++) + a[0].Set(i_,a[k][i_]); + } + //--- allocation + xe.Resize(n,m); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + xe[i].Set(j,2*CMath::RandomReal()-1); + } + //--- allocation + b.Resize(n,m); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a[i][i_]*xe[i_][j]; + b[i].Set(j,v); + } + } + //--- function calls + CMatrixMakeACopy(a,n,n,lua); + CTrFac::CMatrixLU(lua,n,n,p); + //--- Test CMatrixSolveM() + info=0; + //--- function calls + UnsetRep(rep); + CUnset2D(x); + CDenseSolver::CMatrixSolveM(a,n,b,m,CMath::RandomReal()>0.5,info,rep,x); + //--- search errors + cerrors=cerrors || !CMatrixCheckSingularM(n,m,info,rep,x); + //--- Test CMatrixSolve() + info=0; + //--- function calls + UnsetRep(rep); + CUnset2D(x); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- function call + CDenseSolver::CMatrixSolve(a,n,bv,info,rep,xv); + //--- search errors + cerrors=cerrors || !CMatrixCheckSingular(n,info,rep,xv); + //--- Test CMatrixLUSolveM() + info=0; + //--- function calls + UnsetRep(rep); + CUnset2D(x); + CDenseSolver::CMatrixLUSolveM(lua,p,n,b,m,info,rep,x); + //--- search errors + cerrors=cerrors || !CMatrixCheckSingularM(n,m,info,rep,x); + //--- Test CMatrixLUSolve() + info=0; + //--- function calls + UnsetRep(rep); + CUnset2D(x); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- function call + CDenseSolver::CMatrixLUSolve(lua,p,n,bv,info,rep,xv); + //--- search errors + cerrors=cerrors || !CMatrixCheckSingular(n,info,rep,xv); + //--- Test CMatrixMixedSolveM() + info=0; + //--- function calls + UnsetRep(rep); + CUnset2D(x); + CDenseSolver::CMatrixMixedSolveM(a,lua,p,n,b,m,info,rep,x); + //--- search errors + cerrors=cerrors || !CMatrixCheckSingularM(n,m,info,rep,x); + //--- Test CMatrixMixedSolve() + info=0; + //--- function calls + UnsetRep(rep); + CUnset2D(x); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- function call + CDenseSolver::CMatrixMixedSolve(a,lua,p,n,bv,info,rep,xv); + //--- search errors + cerrors=cerrors || !CMatrixCheckSingular(n,info,rep,xv); + } + } + } + } +//--- 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; + a.Resize(n,n); + b.Resize(n,1); + ArrayResize(bv,n); + ArrayResize(tx,2*n); + ArrayResize(xv,n); + ArrayResize(y,n); + //--- change values + for(i=0;i<=n-1;i++) + { + xv[i].re=2*CMath::RandomReal()-1; + xv[i].im=2*CMath::RandomReal()-1; + } + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + a[i].SetRe(j,2*CMath::RandomReal()-1); + a[i].SetIm(j,2*CMath::RandomReal()-1); + } + for(i_=0;i_<=n-1;i_++) + y[i_]=a[i][i_]; + //--- function call + CXblas::XCDot(y,xv,n,tx,v,verr); + bv[i]=v; + } + for(i_=0;i_<=n-1;i_++) + b[i_].Set(0,bv[i_]); + //--- Test CMatrixSolveM() + CUnset2D(x); + CDenseSolver::CMatrixSolveM(a,n,b,1,true,info,rep,x); + //--- check + if(info<=0) + rfserrors=true; + else + { + //--- allocation + ArrayResize(xv,n); + for(i_=0;i_<=n-1;i_++) + xv[i_]=x[i_][0]; + for(i=0;i<=n-1;i++) + { + for(i_=0;i_<=n-1;i_++) + y[i_]=a[i][i_]; + //--- function call + CXblas::XCDot(y,xv,n,tx,v,verr); + //--- search errors + rfserrors=rfserrors || CMath::AbsComplex(v-b[i][0])>8*CMath::m_machineepsilon*MathMax(1,CMath::AbsComplex(b[i][0])); + } + } + //--- Test CMatrixSolve() + CUnset1D(xv); + CDenseSolver::CMatrixSolve(a,n,bv,info,rep,xv); + //--- check + if(info<=0) + rfserrors=true; + else + { + for(i=0;i<=n-1;i++) + { + for(i_=0;i_<=n-1;i_++) + y[i_]=a[i][i_]; + //--- function call + CXblas::XCDot(y,xv,n,tx,v,verr); + //--- search errors + rfserrors=rfserrors || CMath::AbsComplex(v-bv[i])>8*CMath::m_machineepsilon*MathMax(1,CMath::AbsComplex(bv[i])); + } + } + //--- TODO: Test LS-solver on the same matrix + } + } +//+------------------------------------------------------------------+ +//| HPD test | +//+------------------------------------------------------------------+ +static void CTestDenseSolverUnit::TestHPDSolver(const int maxn,const int maxm, + const int passcount, + const double threshold, + bool &hpderrors,bool &rfserrors) + { +//--- create variables + int i=0; + int j=0; + int k=0; + int n=0; + int m=0; + int pass=0; + int taskkind=0; + complex v=0; + bool isupper; + int info=0; + int i_=0; +//--- create arrays + int p[]; + complex bv[]; + complex xv[]; + complex y[]; + complex tx[]; +//--- create matrix + CMatrixComplex a; + CMatrixComplex cha; + CMatrixComplex atmp; + CMatrixComplex xe; + CMatrixComplex b; + CMatrixComplex x; +//--- objects of classes + CDenseSolverReport rep; + CDenseSolverLSReport repls; +//--- 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=CMath::RandomReal()>0.5; + CMatGen::HPDMatrixRndCond(n,1000,a); + CMatrixMakeACopy(a,n,n,cha); + //--- check + if(!CTrFac::HPDMatrixCholesky(cha,n,isupper)) + { + hpderrors=true; + return; + } + //--- allocation + xe.Resize(n,m); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + { + xe[i].SetRe(j,2*CMath::RandomReal()-1); + xe[i].SetIm(j,2*CMath::RandomReal()-1); + } + } + //--- allocation + b.Resize(n,m); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a[i][i_]*xe[i_][j]; + b[i].Set(j,v); + } + } + //--- function calls + CMatrixDropHalf(a,n,isupper); + CMatrixDropHalf(cha,n,isupper); + //--- Test solvers + info=0; + //--- function calls + UnsetRep(rep); + CUnset2D(x); + CDenseSolver::HPDMatrixSolveM(a,n,isupper,b,m,info,rep,x); + //--- search errors + hpderrors=hpderrors || !CMatrixCheckSolutionM(xe,n,m,threshold,info,rep,x); + //--- change values + info=0; + //--- function calls + UnsetRep(rep); + CUnset1D(xv); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- function call + CDenseSolver::HPDMatrixSolve(a,n,isupper,bv,info,rep,xv); + //--- search errors + hpderrors=hpderrors || !CMatrixCheckSolution(xe,n,threshold,info,rep,xv); + //--- change values + info=0; + //--- function calls + UnsetRep(rep); + CUnset2D(x); + CDenseSolver::HPDMatrixCholeskySolveM(cha,n,isupper,b,m,info,rep,x); + //--- search errors + hpderrors=hpderrors || !CMatrixCheckSolutionM(xe,n,m,threshold,info,rep,x); + //--- change values + info=0; + //--- function calls + UnsetRep(rep); + CUnset1D(xv); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- function call + CDenseSolver::HPDMatrixCholeskySolve(cha,n,isupper,bv,info,rep,xv); + //--- search errors + hpderrors=hpderrors || !CMatrixCheckSolution(xe,n,threshold,info,rep,xv); + //--- ******************************************************** + //--- 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++) + { + CUnset2D(a); + //--- check + if(taskkind==0) + { + //--- all zeros + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,0); + } + } + //--- check + if(taskkind==1) + { + //--- there is zero column + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=i;j<=n-1;j++) + { + a[i].SetRe(j,2*CMath::RandomReal()-1); + a[i].SetIm(j,2*CMath::RandomReal()-1); + //--- check + if(i==j) + a[i].SetIm(j,0); + a[j].Set(i,a[i][j]); + } + } + //--- change values + k=CMath::RandomInteger(n); + for(i_=0;i_<=n-1;i_++) + a[i_].Set(k,a[i_][k]*0); + for(i_=0;i_<=n-1;i_++) + a[k].Set(i_,a[k][i_]*0); + } + //--- check + if(taskkind==2) + { + //--- there is zero row + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=i;j<=n-1;j++) + { + a[i].SetRe(j,2*CMath::RandomReal()-1); + a[i].SetIm(j,2*CMath::RandomReal()-1); + //--- check + if(i==j) + a[i].SetIm(j,0); + a[j].Set(i,a[i][j]); + } + } + //--- change values + k=CMath::RandomInteger(n); + for(i_=0;i_<=n-1;i_++) + a[k].Set(i_,a[k][i_]*0); + for(i_=0;i_<=n-1;i_++) + a[i_].Set(k,a[i_][k]*0); + } + //--- check + if(taskkind==3) + { + //--- equal columns/rows + if(n<2) + continue; + //--- allocation + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=i;j<=n-1;j++) + { + a[i].SetRe(j,2*CMath::RandomReal()-1); + a[i].SetIm(j,2*CMath::RandomReal()-1); + //--- check + if(i==j) + a[i].SetIm(j,0); + a[j].Set(i,a[i][j]); + } + } + //--- change values + k=1+CMath::RandomInteger(n-1); + for(i_=0;i_<=n-1;i_++) + a[i_].Set(0,a[i_][k]); + for(i_=0;i_<=n-1;i_++) + a[0].Set(i_,a[k][i_]); + } + //--- allocation + xe.Resize(n,m); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + xe[i].Set(j,2*CMath::RandomReal()-1); + } + //--- allocation + b.Resize(n,m); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a[i][i_]*xe[i_][j]; + b[i].Set(j,v); + } + } + //--- function calls + CMatrixMakeACopy(a,n,n,cha); + CMatrixDropHalf(a,n,isupper); + CMatrixDropHalf(cha,n,isupper); + //--- Test SPDMatrixSolveM() + info=0; + //--- function calls + UnsetRep(rep); + CUnset2D(x); + CDenseSolver::HPDMatrixSolveM(a,n,isupper,b,m,info,rep,x); + //--- search errors + hpderrors=hpderrors || !CMatrixCheckSingularM(n,m,info,rep,x); + //--- Test SPDMatrixSolve() + info=0; + //--- function calls + UnsetRep(rep); + CUnset2D(x); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- function call + CDenseSolver::HPDMatrixSolve(a,n,isupper,bv,info,rep,xv); + //--- search errors + hpderrors=hpderrors || !CMatrixCheckSingular(n,info,rep,xv); + //--- '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() + info=0; + //--- function calls + UnsetRep(rep); + CUnset2D(x); + CDenseSolver::HPDMatrixCholeskySolveM(cha,n,isupper,b,m,info,rep,x); + //--- search errors + hpderrors=hpderrors || !CMatrixCheckSingularM(n,m,info,rep,x); + //--- Test SPDMatrixLUSolve() + info=0; + //--- function calls + UnsetRep(rep); + CUnset2D(x); + //--- allocation + ArrayResize(bv,n); + //--- change values + for(i_=0;i_<=n-1;i_++) + bv[i_]=b[i_][0]; + //--- function call + CDenseSolver::HPDMatrixCholeskySolve(cha,n,isupper,bv,info,rep,xv); + //--- search errors + hpderrors=hpderrors || !CMatrixCheckSingular(n,info,rep,xv); + } + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Unsets real matrix | +//+------------------------------------------------------------------+ +static void CTestDenseSolverUnit::Unset2D(CMatrixDouble &x) + { +//--- allocation + x.Resize(1,1); +//--- change value + x[0].Set(0,2*CMath::RandomReal()-1); + } +//+------------------------------------------------------------------+ +//| Unsets real vector | +//+------------------------------------------------------------------+ +static void CTestDenseSolverUnit::Unset1D(double &x[]) + { +//--- allocation + ArrayResize(x,1); +//--- change value + x[0]=2*CMath::RandomReal()-1; + } +//+------------------------------------------------------------------+ +//| Unsets real matrix | +//+------------------------------------------------------------------+ +static void CTestDenseSolverUnit::CUnset2D(CMatrixComplex &x) + { +//--- allocation + x.Resize(1,1); +//--- change value + x[0].Set(0,2*CMath::RandomReal()-1); + } +//+------------------------------------------------------------------+ +//| Unsets real vector | +//+------------------------------------------------------------------+ +static void CTestDenseSolverUnit::CUnset1D(complex &x[]) + { +//--- allocation + ArrayResize(x,1); +//--- change value + x[0]=2*CMath::RandomReal()-1; + } +//+------------------------------------------------------------------+ +//| Unsets report | +//+------------------------------------------------------------------+ +static void CTestDenseSolverUnit::UnsetRep(CDenseSolverReport &r) + { +//--- change values + r.m_r1=-1; + r.m_rinf=-1; + } +//+------------------------------------------------------------------+ +//| Unsets report | +//+------------------------------------------------------------------+ +static void CTestDenseSolverUnit::UnsetLSRep(CDenseSolverLSReport &r) + { +//--- change values + r.m_r2=-1; + r.m_n=-1; + r.m_k=-1; +//--- function call + Unset2D(r.m_cx); + } +//+------------------------------------------------------------------+ +//| Testing class CLinMin | +//+------------------------------------------------------------------+ +class CTestLinMinUnit + { +public: + static bool TestLinMin(const bool silent) + { + //--- create variables + bool waserrors; + //--- initialization + waserrors=false; + //--- check + if(!silent) + { + Print("TESTING LINMIN"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } + //--- return result + return(!waserrors); + } + }; +//+------------------------------------------------------------------+ +//| Testing class CMinCG | +//+------------------------------------------------------------------+ +class CTestMinCGUnit + { +private: + //--- private methods + static void TestFunc1(CMinCGState &state); + static void TestFunc2(CMinCGState &state); + static void TestFunc3(CMinCGState &state); + static void CalcIIP2(CMinCGState &state,const int n); + static void CalcLowRank(CMinCGState &state,const int n,const int vcnt,double &d[],CMatrixDouble &v,double &vd[],double &x0[]); + static void TestPreconditioning(bool &err); +public: + //--- constructor, destructor + CTestMinCGUnit(void); + ~CTestMinCGUnit(void); + //--- public methods + static bool TestMinCG(const bool silent); + static void TestOther(bool &err); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestMinCGUnit::CTestMinCGUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestMinCGUnit::~CTestMinCGUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CMinCG | +//+------------------------------------------------------------------+ +static bool CTestMinCGUnit::TestMinCG(const bool silent) + { +//--- create variables + bool waserrors; + bool referror; + bool eqerror; + bool linerror1; + bool linerror2; + bool restartserror; + bool precerror; + bool converror; + bool othererrors; + int n=0; + int i=0; + int j=0; + double v=0; + int cgtype=0; + int difftype=0; + double diffstep=0; + int i_=0; +//--- create arrays + double x[]; + double xe[]; + double b[]; + double xlast[]; + double diagh[]; +//--- create matrix + CMatrixDouble a; +//--- objects of classes + CMinCGState state; + CMinCGReport rep; +//--- initialization + waserrors=false; + referror=false; + linerror1=false; + linerror2=false; + eqerror=false; + converror=false; + restartserror=false; + othererrors=false; + precerror=false; +//--- function calls + TestPreconditioning(precerror); + TestOther(othererrors); +//--- calculation + for(difftype=0;difftype<=1;difftype++) + { + for(cgtype=-1;cgtype<=1;cgtype++) + { + //--- Reference problem + ArrayResize(x,3); + //--- change values + n=3; + diffstep=1.0E-6; + x[0]=100*CMath::RandomReal()-50; + x[1]=100*CMath::RandomReal()-50; + x[2]=100*CMath::RandomReal()-50; + //--- check + if(difftype==0) + CMinCG::MinCGCreate(n,x,state); + //--- check + if(difftype==1) + CMinCG::MinCGCreateF(n,x,diffstep,state); + //--- function call + CMinCG::MinCGSetCGType(state,cgtype); + //--- cycle + while(CMinCG::MinCGIteration(state)) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=CMath::Sqr(state.m_x[0]-2)+CMath::Sqr(state.m_x[1])+CMath::Sqr(state.m_x[2]-state.m_x[0]); + //--- check + if(state.m_needfg) + { + state.m_g[0]=2*(state.m_x[0]-2)+2*(state.m_x[0]-state.m_x[2]); + state.m_g[1]=2*state.m_x[1]; + state.m_g[2]=2*(state.m_x[2]-state.m_x[0]); + } + } + //--- function call + CMinCG::MinCGResults(state,x,rep); + //--- search errors + referror=(((referror || rep.m_terminationtype<=0) || MathAbs(x[0]-2)>0.001) || MathAbs(x[1])>0.001) || MathAbs(x[2]-2)>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 + ArrayResize(x,3); + //--- change values + n=3; + diffstep=1.0E-6; + x[0]=10+10*CMath::RandomReal(); + x[1]=10+10*CMath::RandomReal(); + x[2]=10+10*CMath::RandomReal(); + //--- check + if(difftype==0) + CMinCG::MinCGCreate(n,x,state); + //--- check + if(difftype==1) + CMinCG::MinCGCreateF(n,x,diffstep,state); + //--- function calls + CMinCG::MinCGSetCGType(state,cgtype); + CMinCG::MinCGSetStpMax(state,0.1); + CMinCG::MinCGSetCond(state,0.0000001,0.0,0.0,0); + //--- calculation + for(i=0;i<=10;i++) + { + //--- check + if(!CMinCG::MinCGIteration(state)) + break; + //--- function call + TestFunc2(state); + } + //--- change values + x[0]=10+10*CMath::RandomReal(); + x[1]=10+10*CMath::RandomReal(); + x[2]=10+10*CMath::RandomReal(); + //--- function call + CMinCG::MinCGRestartFrom(state,x); + //--- cycle + while(CMinCG::MinCGIteration(state)) + TestFunc2(state); + //--- function call + CMinCG::MinCGResults(state,x,rep); + //--- search errors + restartserror=(((restartserror || rep.m_terminationtype<=0) || MathAbs(x[0]-MathLog(2))>0.01) || MathAbs(x[1])>0.01) || MathAbs(x[2]-MathLog(2))>0.01; + //--- change values + x[0]=10+10*CMath::RandomReal(); + x[1]=10+10*CMath::RandomReal(); + x[2]=10+10*CMath::RandomReal(); + //--- function call + CMinCG::MinCGRestartFrom(state,x); + //--- cycle + while(CMinCG::MinCGIteration(state)) + TestFunc2(state); + //--- function call + CMinCG::MinCGResults(state,x,rep); + //--- search errors + restartserror=(((restartserror || rep.m_terminationtype<=0) || MathAbs(x[0]-MathLog(2))>0.01) || MathAbs(x[1])>0.01) || MathAbs(x[2]-MathLog(2))>0.01; + //--- 1D problem #1 + ArrayResize(x,1); + //--- change values + n=1; + diffstep=1.0E-6; + x[0]=100*CMath::RandomReal()-50; + //--- check + if(difftype==0) + CMinCG::MinCGCreate(n,x,state); + //--- check + if(difftype==1) + CMinCG::MinCGCreateF(n,x,diffstep,state); + //--- function call + CMinCG::MinCGSetCGType(state,cgtype); + //--- cycle + while(CMinCG::MinCGIteration(state)) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=-MathCos(state.m_x[0]); + //--- check + if(state.m_needfg) + state.m_g[0]=MathSin(state.m_x[0]); + } + //--- function call + CMinCG::MinCGResults(state,x,rep); + //--- search errors + linerror1=(linerror1 || rep.m_terminationtype<=0) || MathAbs(x[0]/M_PI-(int)MathRound(x[0]/M_PI))>0.001; + //--- 1D problem #2 + ArrayResize(x,1); + //--- change values + n=1; + diffstep=1.0E-6; + x[0]=100*CMath::RandomReal()-50; + //--- check + if(difftype==0) + CMinCG::MinCGCreate(n,x,state); + //--- check + if(difftype==1) + CMinCG::MinCGCreateF(n,x,diffstep,state); + //--- function call + CMinCG::MinCGSetCGType(state,cgtype); + //--- cycle + while(CMinCG::MinCGIteration(state)) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=CMath::Sqr(state.m_x[0])/(1+CMath::Sqr(state.m_x[0])); + //--- check + if(state.m_needfg) + state.m_g[0]=(2*state.m_x[0]*(1+CMath::Sqr(state.m_x[0]))-CMath::Sqr(state.m_x[0])*2*state.m_x[0])/CMath::Sqr(1+CMath::Sqr(state.m_x[0])); + } + //--- function call + CMinCG::MinCGResults(state,x,rep); + //--- search errors + linerror2=(linerror2 || rep.m_terminationtype<=0) || MathAbs(x[0])>0.001; + //--- Linear equations + diffstep=1.0E-6; + for(n=1;n<=10;n++) + { + //--- Prepare task + a.Resize(n,n); + ArrayResize(x,n); + ArrayResize(xe,n); + ArrayResize(b,n); + for(i=0;i<=n-1;i++) + xe[i]=2*CMath::RandomReal()-1; + //--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,2*CMath::RandomReal()-1); + a[i].Set(i,a[i][i]+3*MathSign(a[i][i])); + } + for(i=0;i<=n-1;i++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a[i][i_]*xe[i_]; + b[i]=v; + } + //--- Solve task + for(i=0;i<=n-1;i++) + x[i]=2*CMath::RandomReal()-1; + //--- check + if(difftype==0) + CMinCG::MinCGCreate(n,x,state); + //--- check + if(difftype==1) + CMinCG::MinCGCreateF(n,x,diffstep,state); + //--- function call + CMinCG::MinCGSetCGType(state,cgtype); + //--- cycle + while(CMinCG::MinCGIteration(state)) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=0; + //--- check + if(state.m_needfg) + { + for(i=0;i<=n-1;i++) + state.m_g[i]=0; + } + for(i=0;i<=n-1;i++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a[i][i_]*state.m_x[i_]; + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=state.m_f+CMath::Sqr(v-b[i]); + //--- check + if(state.m_needfg) + { + for(j=0;j<=n-1;j++) + state.m_g[j]=state.m_g[j]+2*(v-b[i])*a[i][j]; + } + } + } + //--- function call + CMinCG::MinCGResults(state,x,rep); + //--- search errors + eqerror=eqerror || rep.m_terminationtype<=0; + for(i=0;i<=n-1;i++) + eqerror=eqerror || MathAbs(x[i]-xe[i])>0.001; + } + //--- Testing convergence properties + diffstep=1.0E-6; + n=3; + //--- allocation + ArrayResize(x,n); + for(i=0;i<=n-1;i++) + x[i]=6*CMath::RandomReal()-3; + //--- check + if(difftype==0) + CMinCG::MinCGCreate(n,x,state); + //--- check + if(difftype==1) + CMinCG::MinCGCreateF(n,x,diffstep,state); + //--- function calls + CMinCG::MinCGSetCond(state,0.001,0.0,0.0,0); + CMinCG::MinCGSetCGType(state,cgtype); + //--- cycle + while(CMinCG::MinCGIteration(state)) + TestFunc3(state); + //--- function call + CMinCG::MinCGResults(state,x,rep); + //--- search errors + converror=converror || rep.m_terminationtype!=4; + for(i=0;i<=n-1;i++) + x[i]=6*CMath::RandomReal()-3; + //--- check + if(difftype==0) + CMinCG::MinCGCreate(n,x,state); + //--- check + if(difftype==1) + CMinCG::MinCGCreateF(n,x,diffstep,state); + //--- function calls + CMinCG::MinCGSetCond(state,0.0,0.001,0.0,0); + CMinCG::MinCGSetCGType(state,cgtype); + //--- cycle + while(CMinCG::MinCGIteration(state)) + TestFunc3(state); + //--- function call + CMinCG::MinCGResults(state,x,rep); + //--- search errors + converror=converror || rep.m_terminationtype!=1; + //--- change values + for(i=0;i<=n-1;i++) + x[i]=6*CMath::RandomReal()-3; + //--- check + if(difftype==0) + CMinCG::MinCGCreate(n,x,state); + //--- check + if(difftype==1) + CMinCG::MinCGCreateF(n,x,diffstep,state); + //--- function calls + CMinCG::MinCGSetCond(state,0.0,0.0,0.001,0); + CMinCG::MinCGSetCGType(state,cgtype); + //--- cycle + while(CMinCG::MinCGIteration(state)) + TestFunc3(state); + //--- function call + CMinCG::MinCGResults(state,x,rep); + //--- search errors + converror=converror || rep.m_terminationtype!=2; + //--- change values + for(i=0;i<=n-1;i++) + x[i]=2*CMath::RandomReal()-1; + //--- check + if(difftype==0) + CMinCG::MinCGCreate(n,x,state); + //--- check + if(difftype==1) + CMinCG::MinCGCreateF(n,x,diffstep,state); + //--- function calls + CMinCG::MinCGSetCond(state,0.0,0.0,0.0,10); + CMinCG::MinCGSetCGType(state,cgtype); + //--- cycle + while(CMinCG::MinCGIteration(state)) + TestFunc3(state); + //--- function call + CMinCG::MinCGResults(state,x,rep); + //--- search errors + converror=converror || !((rep.m_terminationtype==5 && rep.m_iterationscount==10) || rep.m_terminationtype==7); + } + } +//--- end + waserrors=((((((referror || eqerror) || linerror1) || linerror2) || converror) || othererrors) || restartserror) || precerror; +//--- check + if(!silent) + { + Print("TESTING CG OPTIMIZATION"); + Print("REFERENCE PROBLEM: "); + //--- check + if(referror) + Print("FAILED"); + else + Print("OK"); + Print("LIN-1 PROBLEM: "); + //--- check + if(linerror1) + Print("FAILED"); + else + Print("OK"); + Print("LIN-2 PROBLEM: "); + //--- check + if(linerror2) + Print("FAILED"); + else + Print("OK"); + Print("LINEAR EQUATIONS: "); + //--- check + if(eqerror) + Print("FAILED"); + else + Print("OK"); + Print("RESTARTS: "); + //--- check + if(restartserror) + Print("FAILED"); + else + Print("OK"); + Print("PRECONDITIONING: "); + //--- check + if(precerror) + Print("FAILED"); + else + Print("OK"); + Print("CONVERGENCE PROPERTIES: "); + //--- check + if(converror) + Print("FAILED"); + else + Print("OK"); + Print("OTHER PROPERTIES: "); + //--- check + if(othererrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Other properties | +//+------------------------------------------------------------------+ +static void CTestMinCGUnit::TestOther(bool &err) + { +//--- create variables + int n=0; + double fprev=0; + double xprev=0; + double stpmax=0; + int i=0; + int cgtype=0; + double tmpeps=0; + double epsg=0; + double v=0; + double r=0; + bool hasxlast; + double lastscaledstep=0; + int pkind=0; + int ckind=0; + int mkind=0; + int dkind=0; + double diffstep=0; + double vc=0; + double vm=0; + bool wasf; + bool wasfg; + int i_=0; +//--- create arrays + double x[]; + double s[]; + double a[]; + double h[]; + double xlast[]; +//--- objects of classes + CMinCGState state; + CMinCGReport rep; +//--- calculation + for(cgtype=-1;cgtype<=1;cgtype++) + { + //--- Test reports (F should form monotone sequence) + n=50; + ArrayResize(x,n); + ArrayResize(xlast,n); + //--- change values + for(i=0;i<=n-1;i++) + x[i]=1; + //--- function calls + CMinCG::MinCGCreate(n,x,state); + CMinCG::MinCGSetCond(state,0,0,0,100); + CMinCG::MinCGSetXRep(state,true); + fprev=CMath::m_maxrealnumber; + //--- cycle + while(CMinCG::MinCGIteration(state)) + { + //--- check + if(state.m_needfg) + { + state.m_f=0; + for(i=0;i<=n-1;i++) + { + state.m_f=state.m_f+CMath::Sqr((1+i)*state.m_x[i]); + state.m_g[i]=2*(1+i)*state.m_x[i]; + } + } + //--- check + if(state.m_xupdated) + { + err=err || state.m_f>fprev; + //--- check + if(fprev==CMath::m_maxrealnumber) + { + for(i=0;i<=n-1;i++) + err=err || state.m_x[i]!=x[i]; + } + //--- change values + fprev=state.m_f; + for(i_=0;i_<=n-1;i_++) + xlast[i_]=state.m_x[i_]; + } + } + //--- function call + CMinCG::MinCGResults(state,x,rep); + //--- search errors + for(i=0;i<=n-1;i++) + err=err || x[i]!=xlast[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++) + { + //--- allocation + ArrayResize(x,n); + ArrayResize(xlast,n); + for(i=0;i<=n-1;i++) + x[i]=1; + //--- check + if(dkind==0) + CMinCG::MinCGCreate(n,x,state); + //--- check + if(dkind==1) + CMinCG::MinCGCreateF(n,x,diffstep,state); + //--- function call + CMinCG::MinCGSetCond(state,0,0,0,n/2); + //--- change values + wasf=false; + wasfg=false; + //--- cycle + while(CMinCG::MinCGIteration(state)) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=0; + for(i=0;i<=n-1;i++) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=state.m_f+CMath::Sqr((1+i)*state.m_x[i]); + //--- check + if(state.m_needfg) + state.m_g[i]=2*(1+i)*state.m_x[i]; + } + //--- search errors + wasf=wasf || state.m_needf; + wasfg=wasfg || state.m_needfg; + } + //--- function call + CMinCG::MinCGResults(state,x,rep); + //--- check + if(dkind==0) + err=(err || wasf) || !wasfg; + //--- check + 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. + ArrayResize(x,1); + ArrayResize(s,1); + diffstep=CMath::RandomReal()*1.0E-6; + s[0]=MathExp(CMath::RandomReal()*4-2); + x[0]=0; + //--- function calls + CMinCG::MinCGCreateF(1,x,diffstep,state); + CMinCG::MinCGSetCond(state,1.0E-6,0,0,0); + CMinCG::MinCGSetScale(state,s); + v=0; + //--- cycle + while(CMinCG::MinCGIteration(state)) + { + state.m_f=CMath::Sqr(state.m_x[0]); + v=MathMax(v,MathAbs(state.m_x[0])); + } + //--- function call + CMinCG::MinCGResults(state,x,rep); + r=v/(s[0]*diffstep); + //--- search errors + err=err || MathAbs(MathLog(r))>MathLog(1+1000*CMath::m_machineepsilon); + //--- Test maximum step + n=1; + ArrayResize(x,n); + x[0]=100; + stpmax=0.05+0.05*CMath::RandomReal(); + //--- function calls + CMinCG::MinCGCreate(n,x,state); + CMinCG::MinCGSetCond(state,1.0E-9,0,0,0); + CMinCG::MinCGSetStpMax(state,stpmax); + CMinCG::MinCGSetXRep(state,true); + xprev=x[0]; + //--- cycle + while(CMinCG::MinCGIteration(state)) + { + //--- check + if(state.m_needfg) + { + state.m_f=MathExp(state.m_x[0])+MathExp(-state.m_x[0]); + state.m_g[0]=MathExp(state.m_x[0])-MathExp(-state.m_x[0]); + //--- search errors + err=err || MathAbs(state.m_x[0]-xprev)>(1+MathSqrt(CMath::m_machineepsilon))*stpmax; + } + //--- check + if(state.m_xupdated) + { + //--- search errors + err=err || MathAbs(state.m_x[0]-xprev)>(1+MathSqrt(CMath::m_machineepsilon))*stpmax; + xprev=state.m_x[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++) + { + //--- allocation + ArrayResize(x,n); + ArrayResize(xlast,n); + ArrayResize(a,n); + ArrayResize(s,n); + ArrayResize(h,n); + //--- change values + for(i=0;i<=n-1;i++) + { + x[i]=CMath::RandomReal()+1; + a[i]=MathExp(MathLog(100)*(2*CMath::RandomReal()-1)); + s[i]=MathExp(MathLog(100)*(2*CMath::RandomReal()-1)); + h[i]=MathExp(MathLog(100)*(2*CMath::RandomReal()-1)); + } + //--- function calls + CMinCG::MinCGCreate(n,x,state); + CMinCG::MinCGSetScale(state,s); + CMinCG::MinCGSetXRep(state,true); + //--- check + if(pkind==1) + CMinCG::MinCGSetPrecDiag(state,h); + //--- check + if(pkind==2) + CMinCG::MinCGSetPrecScale(state); + //--- Test gradient-based stopping condition + for(i=0;i<=n-1;i++) + x[i]=CMath::RandomReal()+1; + //--- function calls + CMinCG::MinCGSetCond(state,tmpeps,0,0,0); + CMinCG::MinCGRestartFrom(state,x); + //--- cycle + while(CMinCG::MinCGIteration(state)) + { + //--- check + if(state.m_needfg) + { + state.m_f=0; + for(i=0;i<=n-1;i++) + { + state.m_f=state.m_f+a[i]*MathPow(state.m_x[i],4); + state.m_g[i]=4*a[i]*MathPow(state.m_x[i],3); + } + } + } + //--- function call + CMinCG::MinCGResults(state,x,rep); + //--- check + if(rep.m_terminationtype<=0) + { + err=true; + return; + } + //--- change value + v=0; + for(i=0;i<=n-1;i++) + v=v+CMath::Sqr(s[i]*4*a[i]*MathPow(x[i],3)); + v=MathSqrt(v); + //--- search errors + err=err || v>tmpeps; + //--- Test step-based stopping condition + for(i=0;i<=n-1;i++) + x[i]=CMath::RandomReal()+1; + hasxlast=false; + //--- function calls + CMinCG::MinCGSetCond(state,0,0,tmpeps,0); + CMinCG::MinCGRestartFrom(state,x); + //--- cycle + while(CMinCG::MinCGIteration(state)) + { + //--- check + if(state.m_needfg) + { + state.m_f=0; + for(i=0;i<=n-1;i++) + { + state.m_f=state.m_f+a[i]*MathPow(state.m_x[i],4); + state.m_g[i]=4*a[i]*MathPow(state.m_x[i],3); + } + } + //--- check + if(state.m_xupdated) + { + //--- check + if(hasxlast) + { + lastscaledstep=0; + for(i=0;i<=n-1;i++) + lastscaledstep=lastscaledstep+CMath::Sqr(state.m_x[i]-xlast[i])/CMath::Sqr(s[i]); + lastscaledstep=MathSqrt(lastscaledstep); + } + else + lastscaledstep=0; + for(i_=0;i_<=n-1;i_++) + xlast[i_]=state.m_x[i_]; + hasxlast=true; + } + } + //--- function call + CMinCG::MinCGResults(state,x,rep); + //--- check + if(rep.m_terminationtype<=0) + { + err=true; + return; + } + //--- search errors + err=err || 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 + if(ckind==0) + vc=1.0; + //--- check + if(ckind==1) + vc=1.0E+6; + //--- check + if(mkind==0) + vm=1.0E+8; + //--- check + if(mkind==1) + vm=1.0E+20; + //--- check + if(mkind==2) + vm=CInfOrNaN::PositiveInfinity(); + //--- Create optimizer,solve optimization problem + epsg=1.0E-6*vc; + ArrayResize(x,1); + x[0]=0.0; + //--- function calls + CMinCG::MinCGCreate(1,x,state); + CMinCG::MinCGSetCond(state,epsg,0,0,0); + CMinCG::MinCGSetCGType(state,cgtype); + //--- cycle + while(CMinCG::MinCGIteration(state)) + { + //--- check + if(state.m_needfg) + { + //--- check + if(-0.999999epsg; + } + } + } + } +//+------------------------------------------------------------------+ +//| Calculate test function #1 | +//+------------------------------------------------------------------+ +static void CTestMinCGUnit::TestFunc1(CMinCGState &state) + { +//--- check + if(state.m_x[0]<100.0) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=CMath::Sqr(MathExp(state.m_x[0])-2)+CMath::Sqr(state.m_x[1])+CMath::Sqr(state.m_x[2]-state.m_x[0]); + //--- check + if(state.m_needfg) + { + state.m_g[0]=2*(MathExp(state.m_x[0])-2)*MathExp(state.m_x[0])+2*(state.m_x[0]-state.m_x[2]); + state.m_g[1]=2*state.m_x[1]; + state.m_g[2]=2*(state.m_x[2]-state.m_x[0]); + } + } + else + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=MathSqrt(CMath::m_maxrealnumber); + //--- check + if(state.m_needfg) + { + state.m_g[0]=MathSqrt(CMath::m_maxrealnumber); + state.m_g[1]=0; + state.m_g[2]=0; + } + } + } +//+------------------------------------------------------------------+ +//| Calculate test function #2 | +//| Simple variation of #1,much more nonlinear,which makes unlikely | +//| premature convergence of algorithm . | +//+------------------------------------------------------------------+ +static void CTestMinCGUnit::TestFunc2(CMinCGState &state) + { +//--- check + if(state.m_x[0]<100.0) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=CMath::Sqr(MathExp(state.m_x[0])-2)+CMath::Sqr(CMath::Sqr(state.m_x[1]))+CMath::Sqr(state.m_x[2]-state.m_x[0]); + //--- check + if(state.m_needfg) + { + state.m_g[0]=2*(MathExp(state.m_x[0])-2)*MathExp(state.m_x[0])+2*(state.m_x[0]-state.m_x[2]); + state.m_g[1]=4*state.m_x[1]*CMath::Sqr(state.m_x[1]); + state.m_g[2]=2*(state.m_x[2]-state.m_x[0]); + } + } + else + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=MathSqrt(CMath::m_maxrealnumber); + //--- check + if(state.m_needfg) + { + state.m_g[0]=MathSqrt(CMath::m_maxrealnumber); + state.m_g[1]=0; + state.m_g[2]=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 CTestMinCGUnit::TestFunc3(CMinCGState &state) + { +//--- create a variable + double s=0; +//--- initialization + s=0.001; +//--- check + if(state.m_x[0]<100.0) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=CMath::Sqr(MathExp(state.m_x[0])-2)+CMath::Sqr(CMath::Sqr(state.m_x[1])+s)+CMath::Sqr(state.m_x[2]-state.m_x[0]); + //--- check + if(state.m_needfg) + { + state.m_g[0]=2*(MathExp(state.m_x[0])-2)*MathExp(state.m_x[0])+2*(state.m_x[0]-state.m_x[2]); + state.m_g[1]=2*(CMath::Sqr(state.m_x[1])+s)*2*state.m_x[1]; + state.m_g[2]=2*(state.m_x[2]-state.m_x[0]); + } + } + else + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=MathSqrt(CMath::m_maxrealnumber); + //--- check + if(state.m_needfg) + { + state.m_g[0]=MathSqrt(CMath::m_maxrealnumber); + state.m_g[1]=0; + state.m_g[2]=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 CTestMinCGUnit::CalcIIP2(CMinCGState &state,const int n) + { +//--- create a variable + int i=0; +//--- check + if(state.m_needf || state.m_needfg) + state.m_f=0; +//--- calculation + for(i=0;i<=n-1;i++) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=state.m_f+CMath::Sqr(i*i+1)*CMath::Sqr(state.m_x[i]); + //--- check + if(state.m_needfg) + state.m_g[i]=CMath::Sqr(i*i+1)*2*state.m_x[i]; + } + } +//+------------------------------------------------------------------+ +//| Calculate test function f(x)=0.5*(x-x0)'*A*(x-x0),A=D+V'*Vd*V | +//+------------------------------------------------------------------+ +static void CTestMinCGUnit::CalcLowRank(CMinCGState &state,const int n, + const int vcnt,double &d[], + CMatrixDouble &v,double &vd[], + double &x0[]) + { +//--- create variables + int i=0; + int j=0; + double dx=0; + double t=0; + double t2=0; + int i_=0; +//--- change values + state.m_f=0; + for(i=0;i<=n-1;i++) + state.m_g[i]=0; +//--- calculation + for(i=0;i<=n-1;i++) + { + dx=state.m_x[i]-x0[i]; + state.m_f=state.m_f+0.5*dx*d[i]*dx; + state.m_g[i]=state.m_g[i]+d[i]*dx; + } +//--- calculation + for(i=0;i<=vcnt-1;i++) + { + t=0; + for(j=0;j<=n-1;j++) + t=t+v[i][j]*(state.m_x[j]-x0[j]); + //--- change values + state.m_f=state.m_f+0.5*t*vd[i]*t; + t2=t*vd[i]; + for(i_=0;i_<=n-1;i_++) + state.m_g[i_]=state.m_g[i_]+t2*v[i][i_]; + } + } +//+------------------------------------------------------------------+ +//| This function tests preconditioning | +//| On failure sets Err to True (leaves it unchanged otherwise) | +//+------------------------------------------------------------------+ +static void CTestMinCGUnit::TestPreconditioning(bool &err) + { +//--- create variables + int pass=0; + int n=0; + int i=0; + int j=0; + int k=0; + int vs=0; + int cntb1=0; + int cntg1=0; + int cntb2=0; + int cntg2=0; + double epsg=0; + int cgtype=0; +//--- create arrays + double x[]; + double x0[]; + double vd[]; + double d[]; + double s[]; + double diagh[]; +//--- create matrix + CMatrixDouble v; +//--- objects of classes + CMinCGState state; + CMinCGReport rep; +//--- initialization + k=50; + epsg=1.0E-10; +//--- calculation + 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++) + { + //--- allocation + ArrayResize(x,n); + for(i=0;i<=n-1;i++) + x[i]=0; + //--- function calls + CMinCG::MinCGCreate(n,x,state); + CMinCG::MinCGSetCGType(state,cgtype); + //--- Test it with default preconditioner + CMinCG::MinCGSetPrecDefault(state); + //--- change values + cntb1=0; + for(pass=0;pass<=k-1;pass++) + { + for(i=0;i<=n-1;i++) + x[i]=2*CMath::RandomReal()-1; + //--- function call + CMinCG::MinCGRestartFrom(state,x); + //--- cycle + while(CMinCG::MinCGIteration(state)) + CalcIIP2(state,n); + //--- function call + CMinCG::MinCGResults(state,x,rep); + cntb1=cntb1+rep.m_iterationscount; + //--- search errors + err=err || rep.m_terminationtype<=0; + } + //--- Test it with perturbed diagonal preconditioner + ArrayResize(diagh,n); + for(i=0;i<=n-1;i++) + diagh[i]=2*CMath::Sqr(i*i+1)*(0.8+0.4*CMath::RandomReal()); + //--- function call + CMinCG::MinCGSetPrecDiag(state,diagh); + //--- change values + cntg1=0; + for(pass=0;pass<=k-1;pass++) + { + for(i=0;i<=n-1;i++) + x[i]=2*CMath::RandomReal()-1; + //--- function call + CMinCG::MinCGRestartFrom(state,x); + //--- cycle + while(CMinCG::MinCGIteration(state)) + CalcIIP2(state,n); + //--- function call + CMinCG::MinCGResults(state,x,rep); + cntg1=cntg1+rep.m_iterationscount; + //--- search errors + err=err || rep.m_terminationtype<=0; + } + //--- Compare + err=err || cntb10) + { + //--- allocation + v.Resize(vs,n); + ArrayResize(vd,vs); + //--- change values + for(i=0;i<=vs-1;i++) + { + for(j=0;j<=n-1;j++) + v[i].Set(j,2*CMath::RandomReal()-1); + vd[i]=MathExp(2*CMath::RandomReal()); + } + } + //--- function calls + CMinCG::MinCGCreate(n,x,state); + CMinCG::MinCGSetCGType(state,cgtype); + //--- Test it with default preconditioner + CMinCG::MinCGSetPrecDefault(state); + //--- change values + cntb1=0; + for(pass=0;pass<=k-1;pass++) + { + for(i=0;i<=n-1;i++) + x[i]=2*CMath::RandomReal()-1; + //--- function call + CMinCG::MinCGRestartFrom(state,x); + //--- cycle + while(CMinCG::MinCGIteration(state)) + CalcLowRank(state,n,vs,d,v,vd,x0); + //--- function call + CMinCG::MinCGResults(state,x,rep); + cntb1=cntb1+rep.m_iterationscount; + //--- search errors + err=err || rep.m_terminationtype<=0; + } + //--- Test it with low rank preconditioner + CMinCG::MinCGSetPrecLowRankFast(state,d,vd,v,vs); + //--- change values + cntg1=0; + for(pass=0;pass<=k-1;pass++) + { + for(i=0;i<=n-1;i++) + x[i]=2*CMath::RandomReal()-1; + //--- function call + CMinCG::MinCGRestartFrom(state,x); + //--- cycle + while(CMinCG::MinCGIteration(state)) + CalcLowRank(state,n,vs,d,v,vd,x0); + //--- function call + CMinCG::MinCGResults(state,x,rep); + cntg1=cntg1+rep.m_iterationscount; + //--- search errors + err=err || rep.m_terminationtype<=0; + } + //--- Compare + err=err || cntb1bndu[i]) + err=true; + } + } +//+------------------------------------------------------------------+ +//| 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 CTestMinBLEICUnit::CalcIIP2(CMinBLEICState &state,const int n, + const int fk) + { +//--- create a variable + int i=0; +//--- check + if(state.m_needfg) + state.m_f=0; +//--- calculation + for(i=0;i<=n-1;i++) + { + //--- check + if(state.m_needfg) + { + state.m_f=state.m_f+MathPow(i*i+1,2*fk)*CMath::Sqr(state.m_x[i]); + state.m_g[i]=MathPow(i*i+1,2*fk)*2*state.m_x[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 CTestMinBLEICUnit::TestFeasibility(bool &feaserr,bool &converr, + bool &interr) + { +//--- create variables + int pkind=0; + int preckind=0; + int passcount=0; + int pass=0; + int n=0; + int nmax=0; + int i=0; + int j=0; + int k=0; + int p=0; + double v=0; + double v2=0; + double v3=0; + double vv=0; + double epsc=0; + double epsg=0; + int dkind=0; + double diffstep=0; + int i_=0; +//--- create arrays + double bl[]; + double bu[]; + double x[]; + double g[]; + double x0[]; + double xs[]; + int ct[]; +//--- create matrix + CMatrixDouble c; +//--- objects of classes + CMinBLEICState state; + CMinBLEICReport rep; +//--- initialization + nmax=5; + epsc=1.0E-4; + epsg=1.0E-8; + passcount=10; +//--- calculation + 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; + ArrayResize(x,n); + ArrayResize(g,n); + c.Resize(1,n+1); + ArrayResize(ct,1); + c[0].Set(n,0); + //--- calculation + for(i=0;i<=n-1;i++) + { + x[i]=2*CMath::RandomReal()-1; + c[0].Set(i,2*CMath::RandomReal()-1); + v=2*CMath::RandomReal()-1; + c[0].Set(n,c[0][n]+c[0][i]*v); + } + ct[0]=0; + //--- Create and optimize + if(dkind==0) + CMinBLEIC::MinBLEICCreate(n,x,state); + //--- check + if(dkind==1) + CMinBLEIC::MinBLEICCreateF(n,x,diffstep,state); + //--- function calls + CMinBLEIC::MinBLEICSetLC(state,c,ct,1); + CMinBLEIC::MinBLEICSetInnerCond(state,epsg,0.0,0.0); + CMinBLEIC::MinBLEICSetOuterCond(state,epsc,epsc); + SetRandomPreconditioner(state,n,preckind); + //--- cycle + while(CMinBLEIC::MinBLEICIteration(state)) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=0; + for(i=0;i<=n-1;i++) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=state.m_f+MathPow(state.m_x[i],p); + //--- check + if(state.m_needfg) + state.m_g[i]=p*MathPow(state.m_x[i],p-1); + } + } + //--- function call + CMinBLEIC::MinBLEICResults(state,x,rep); + //--- check + if(rep.m_terminationtype<=0) + { + converr=true; + return; + } + //--- Test feasibility of solution + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=c[0][i_]*x[i_]; + //--- search errors + feaserr=feaserr || MathAbs(v-c[0][n])>epsc; + //--- 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=0.0; + for(i_=0;i_<=n-1;i_++) + vv+=c[0][i_]*c[0][i_]; + //--- check + if(vv!=0.0) + { + //--- Calculate gradient at the result + //--- Project gradient into C + //--- Check projected norm + for(i=0;i<=n-1;i++) + g[i]=p*MathPow(x[i],p-1); + v2=0.0; + for(i_=0;i_<=n-1;i_++) + v2+=c[0][i_]*c[0][i_]; + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=c[0][i_]*g[i_]; + vv=v/v2; + for(i_=0;i_<=n-1;i_++) + { + g[i_]=g[i_]-vv*c[0][i_]; + } + v3=0.0; + for(i_=0;i_<=n-1;i_++) + v3+=g[i_]*g[i_]; + //--- search errors + converr=converr || MathSqrt(v3)>0.001; + } + } + } + } + } + //--- 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] + //--- * 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. + p=2*pkind; + ArrayResize(x,n); + ArrayResize(x0,n); + ArrayResize(xs,n); + ArrayResize(g,n); + c.Resize(k,n+1); + ArrayResize(ct,k); + c[0].Set(n,0); + //--- change values + for(i=0;i<=n-1;i++) + { + x[i]=2*CMath::RandomReal()-1; + xs[i]=2*CMath::RandomReal()-1; + } + for(i=0;i<=k-1;i++) + { + for(j=0;j<=n-1;j++) + c[i].Set(j,2*CMath::RandomReal()-1); + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=c[i][i_]*xs[i_]; + c[i].Set(n,v); + ct[i]=0; + } + //--- copy + for(i_=0;i_<=n-1;i_++) + x0[i_]=xs[i_]; + for(i_=0;i_<=n-1;i_++) + x0[i_]=x0[i_]+c[0][i_]; + //--- Create and optimize + // + if(dkind==0) + CMinBLEIC::MinBLEICCreate(n,x,state); + //--- check + if(dkind==1) + CMinBLEIC::MinBLEICCreateF(n,x,diffstep,state); + //--- function calls + CMinBLEIC::MinBLEICSetLC(state,c,ct,k); + CMinBLEIC::MinBLEICSetInnerCond(state,epsg,0.0,0.0); + CMinBLEIC::MinBLEICSetOuterCond(state,epsc,epsc); + SetRandomPreconditioner(state,n,preckind); + //--- cycle + while(CMinBLEIC::MinBLEICIteration(state)) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=0; + for(i=0;i<=n-1;i++) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=state.m_f+CMath::Sqr(state.m_x[i]-x0[i]); + //--- check + if(state.m_needfg) + state.m_g[i]=2*(state.m_x[i]-x0[i]); + } + } + //--- function call + CMinBLEIC::MinBLEICResults(state,x,rep); + //--- check + if(rep.m_terminationtype<=0) + { + converr=true; + return; + } + //--- check feasiblity properties + for(i=0;i<=k-1;i++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=c[i][i_]*x[i_]; + //--- search errors + feaserr=feaserr || MathAbs(v-c[i][n])>epsc; + } + //--- Compare with XS + v=0; + for(i=0;i<=n-1;i++) + v=v+CMath::Sqr(x[i]-xs[i]); + v=MathSqrt(v); + //--- search errors + converr=converr || MathAbs(v)>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; + ArrayResize(bl,n); + ArrayResize(bu,n); + ArrayResize(x,n); + ArrayResize(x0,n); + //--- change values + for(i=0;i<=n-1;i++) + { + bl[i]=0; + bu[i]=1; + x[i]=CMath::RandomReal(); + x0[i]=3*CMath::RandomReal()-1; + } + //--- Create and optimize + if(dkind==0) + CMinBLEIC::MinBLEICCreate(n,x,state); + //--- check + if(dkind==1) + CMinBLEIC::MinBLEICCreateF(n,x,diffstep,state); + //--- function calls + CMinBLEIC::MinBLEICSetBC(state,bl,bu); + CMinBLEIC::MinBLEICSetInnerCond(state,epsg,0.0,0.0); + CMinBLEIC::MinBLEICSetOuterCond(state,epsc,epsc); + SetRandomPreconditioner(state,n,preckind); + //--- cycle + while(CMinBLEIC::MinBLEICIteration(state)) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=0; + for(i=0;i<=n-1;i++) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=state.m_f+MathPow(state.m_x[i]-x0[i],p); + //--- check + if(state.m_needfg) + state.m_g[i]=p*MathPow(state.m_x[i]-x0[i],p-1); + //--- search errors + feaserr=feaserr || state.m_x[i]<0.0; + feaserr=feaserr || state.m_x[i]>1.0; + } + } + //--- function call + CMinBLEIC::MinBLEICResults(state,x,rep); + //--- check + if(rep.m_terminationtype<=0) + { + converr=true; + return; + } + //--- * compare solution with analytic one + //--- * check feasibility + for(i=0;i<=n-1;i++) + { + //--- search errors + converr=converr || MathAbs(x[i]-CApServ::BoundVal(x0[i],0.0,1.0))>0.01; + feaserr=feaserr || x[i]<0.0; + feaserr=feaserr || x[i]>1.0; + } + } + } + } + } + //--- 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; + ArrayResize(x,n); + ArrayResize(x0,n); + c.Resize(2*n,n+1); + ArrayResize(ct,2*n); + //--- change values + for(i=0;i<=n-1;i++) + { + x[i]=CMath::RandomReal(); + x0[i]=3*CMath::RandomReal()-1; + for(j=0;j<=n;j++) + { + c[2*i].Set(j,0); + c[2*i+1].Set(j,0); + } + c[2*i+0].Set(i,1); + c[2*i+0].Set(n,0); + ct[2*i+0]=1; + c[2*i+1].Set(i,1); + c[2*i+1].Set(n,1); + ct[2*i+1]=-1; + } + //--- Create and optimize + CMinBLEIC::MinBLEICCreate(n,x,state); + CMinBLEIC::MinBLEICSetLC(state,c,ct,2*n); + CMinBLEIC::MinBLEICSetInnerCond(state,epsg,0.0,0.0); + CMinBLEIC::MinBLEICSetOuterCond(state,epsc,epsc); + SetRandomPreconditioner(state,n,preckind); + //--- cycle + while(CMinBLEIC::MinBLEICIteration(state)) + { + //--- check + if(state.m_needfg) + { + state.m_f=0; + for(i=0;i<=n-1;i++) + { + state.m_f=state.m_f+MathPow(state.m_x[i]-x0[i],p); + state.m_g[i]=p*MathPow(state.m_x[i]-x0[i],p-1); + } + continue; + } + //--- Unknown protocol specified + interr=true; + return; + } + //--- function call + CMinBLEIC::MinBLEICResults(state,x,rep); + //--- check + if(rep.m_terminationtype<=0) + { + converr=true; + return; + } + //--- * compare solution with analytic one + //--- * check feasibility + for(i=0;i<=n-1;i++) + { + //--- search errors + converr=converr || MathAbs(x[i]-CApServ::BoundVal(x0[i],0.0,1.0))>0.05; + feaserr=feaserr || x[i]<0.0-epsc; + feaserr=feaserr || x[i]>1.0+epsc; + } + } + } + } + //--- 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; + ArrayResize(bl,n); + ArrayResize(bu,n); + ArrayResize(x,n); + ArrayResize(x0,n); + //--- change values + for(i=0;i<=n-1;i++) + { + bl[i]=0; + bu[i]=1; + x[i]=CMath::RandomReal(); + x0[i]=3*CMath::RandomReal()-1; + } + i=CMath::RandomInteger(n); + bl[i]=1; + bu[i]=0; + //--- Create and optimize + CMinBLEIC::MinBLEICCreate(n,x,state); + CMinBLEIC::MinBLEICSetBC(state,bl,bu); + CMinBLEIC::MinBLEICSetInnerCond(state,epsg,0.0,0.0); + CMinBLEIC::MinBLEICSetOuterCond(state,epsc,epsc); + SetRandomPreconditioner(state,n,preckind); + //--- cycle + while(CMinBLEIC::MinBLEICIteration(state)) + { + //--- check + if(state.m_needfg) + { + state.m_f=0; + for(i=0;i<=n-1;i++) + { + state.m_f=state.m_f+MathPow(state.m_x[i]-x0[i],p); + state.m_g[i]=p*MathPow(state.m_x[i]-x0[i],p-1); + } + continue; + } + //--- Unknown protocol specified + interr=true; + return; + } + //--- function call + CMinBLEIC::MinBLEICResults(state,x,rep); + //--- search errors + feaserr=feaserr || rep.m_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; + ArrayResize(x,n); + c.Resize(k+1,n+1); + ArrayResize(ct,k+1); + for(i=0;i<=n-1;i++) + x[i]=CMath::RandomReal(); + //--- change values + for(i=0;i<=k-1;i++) + { + for(j=0;j<=n;j++) + c[i].Set(j,2*CMath::RandomReal()-1); + ct[i]=0; + } + ct[k]=0; + for(i_=0;i_<=n-1;i_++) + c[k].Set(i_,c[0][i_]); + c[k].Set(n,c[0][n]+1); + //--- Create and optimize + CMinBLEIC::MinBLEICCreate(n,x,state); + CMinBLEIC::MinBLEICSetLC(state,c,ct,k+1); + CMinBLEIC::MinBLEICSetInnerCond(state,epsg,0.0,0.0); + CMinBLEIC::MinBLEICSetOuterCond(state,epsc,epsc); + SetRandomPreconditioner(state,n,preckind); + //--- cycle + while(CMinBLEIC::MinBLEICIteration(state)) + { + //--- check + if(state.m_needfg) + { + state.m_f=0; + for(i=0;i<=n-1;i++) + { + state.m_f=state.m_f+MathPow(state.m_x[i],p); + state.m_g[i]=p*MathPow(state.m_x[i],p-1); + } + continue; + } + //--- Unknown protocol specified + interr=true; + return; + } + //--- function call + CMinBLEIC::MinBLEICResults(state,x,rep); + //--- search errors + feaserr=feaserr || rep.m_terminationtype!=-3; + } + } + } + } + } + } +//+------------------------------------------------------------------+ +//| This function additional properties. | +//| On failure sets Err to True (leaves it unchanged otherwise) | +//+------------------------------------------------------------------+ +static void CTestMinBLEICUnit::TestOther(bool &err) + { +//--- create variables + int passcount=0; + int pass=0; + int n=0; + int nmax=0; + int i=0; + double fprev=0; + double xprev=0; + double stpmax=0; + double v=0; + int pkind=0; + int ckind=0; + int mkind=0; + double vc=0; + double vm=0; + double epsc=0; + double epsg=0; + double tmpeps=0; + double diffstep=0; + int dkind=0; + bool wasf; + bool wasfg; + double r=0; + int i_=0; +//--- create arrays + double bl[]; + double bu[]; + double x[]; + double xf[]; + double xlast[]; + double a[]; + double s[]; + double h[]; + int ct[]; +//--- create matrix + CMatrixDouble c; +//--- objects of classes + CMinBLEICState state; + CMinBLEICReport rep; +//--- initialization + nmax=5; + epsc=1.0E-4; + epsg=1.0E-8; + passcount=10; +//--- calculation + for(pass=1;pass<=passcount;pass++) + { + //--- Test reports: + //--- * first value must be starting point + //--- * last value must be last point + n=50; + ArrayResize(x,n); + ArrayResize(xlast,n); + ArrayResize(bl,n); + ArrayResize(bu,n); + //--- change values + for(i=0;i<=n-1;i++) + { + x[i]=10; + bl[i]=2*CMath::RandomReal()-1; + bu[i]=CInfOrNaN::PositiveInfinity(); + } + //--- function calls + CMinBLEIC::MinBLEICCreate(n,x,state); + CMinBLEIC::MinBLEICSetBC(state,bl,bu); + CMinBLEIC::MinBLEICSetInnerCond(state,0,0,0); + CMinBLEIC::MinBLEICSetMaxIts(state,10); + CMinBLEIC::MinBLEICSetOuterCond(state,1.0E-64,1.0E-64); + CMinBLEIC::MinBLEICSetXRep(state,true); + fprev=CMath::m_maxrealnumber; + //--- cycle + while(CMinBLEIC::MinBLEICIteration(state)) + { + //--- check + if(state.m_needfg) + { + state.m_f=0; + for(i=0;i<=n-1;i++) + { + state.m_f=state.m_f+CMath::Sqr((1+i)*state.m_x[i]); + state.m_g[i]=2*(1+i)*state.m_x[i]; + } + } + //--- check + if(state.m_xupdated) + { + //--- check + if(fprev==CMath::m_maxrealnumber) + { + for(i=0;i<=n-1;i++) + err=err || state.m_x[i]!=x[i]; + } + //--- change values + fprev=state.m_f; + for(i_=0;i_<=n-1;i_++) + xlast[i_]=state.m_x[i_]; + } + } + //--- function call + CMinBLEIC::MinBLEICResults(state,x,rep); + //--- search errors + for(i=0;i<=n-1;i++) + err=err || x[i]!=xlast[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++) + { + //--- allocation + ArrayResize(x,n); + ArrayResize(xlast,n); + for(i=0;i<=n-1;i++) + x[i]=1; + //--- check + if(dkind==0) + CMinBLEIC::MinBLEICCreate(n,x,state); + //--- check + if(dkind==1) + CMinBLEIC::MinBLEICCreateF(n,x,diffstep,state); + //--- function calls + CMinBLEIC::MinBLEICSetInnerCond(state,1.0E-10,0,0); + CMinBLEIC::MinBLEICSetOuterCond(state,1.0E-6,1.0E-6); + wasf=false; + wasfg=false; + //--- cycle + while(CMinBLEIC::MinBLEICIteration(state)) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=0; + //--- calculation + for(i=0;i<=n-1;i++) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=state.m_f+CMath::Sqr((1+i)*state.m_x[i]); + //--- check + if(state.m_needfg) + state.m_g[i]=2*(1+i)*state.m_x[i]; + } + //--- search errors + wasf=wasf || state.m_needf; + wasfg=wasfg || state.m_needfg; + } + //--- function call + CMinBLEIC::MinBLEICResults(state,x,rep); + //--- check + if(dkind==0) + err=(err || wasf) || !wasfg; + //--- check + 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. + ArrayResize(x,1); + ArrayResize(s,1); + diffstep=CMath::RandomReal()*1.0E-6; + s[0]=MathExp(CMath::RandomReal()*4-2); + x[0]=0; + //--- function calls + CMinBLEIC::MinBLEICCreateF(1,x,diffstep,state); + CMinBLEIC::MinBLEICSetInnerCond(state,1.0E-6,0,0); + CMinBLEIC::MinBLEICSetScale(state,s); + v=0; + //--- cycle + while(CMinBLEIC::MinBLEICIteration(state)) + { + state.m_f=CMath::Sqr(state.m_x[0]); + v=MathMax(v,MathAbs(state.m_x[0])); + } + //--- function call + CMinBLEIC::MinBLEICResults(state,x,rep); + r=v/(s[0]*diffstep); + //--- search errors + err=err || MathAbs(MathLog(r))>MathLog(1+1000*CMath::m_machineepsilon); + //--- Test stpmax + n=1; + ArrayResize(x,n); + ArrayResize(bl,n); + ArrayResize(bu,n); + //--- change values + x[0]=100; + bl[0]=2*CMath::RandomReal()-1; + bu[0]=CInfOrNaN::PositiveInfinity(); + stpmax=0.05+0.05*CMath::RandomReal(); + //--- function calls + CMinBLEIC::MinBLEICCreate(n,x,state); + CMinBLEIC::MinBLEICSetBC(state,bl,bu); + CMinBLEIC::MinBLEICSetInnerCond(state,epsg,0,0); + CMinBLEIC::MinBLEICSetOuterCond(state,epsc,epsc); + CMinBLEIC::MinBLEICSetXRep(state,true); + CMinBLEIC::MinBLEICSetStpMax(state,stpmax); + xprev=x[0]; + //--- cycle + while(CMinBLEIC::MinBLEICIteration(state)) + { + //--- check + if(state.m_needfg) + { + state.m_f=MathExp(state.m_x[0])+MathExp(-state.m_x[0]); + state.m_g[0]=MathExp(state.m_x[0])-MathExp(-state.m_x[0]); + err=err || MathAbs(state.m_x[0]-xprev)>(double)((1+MathSqrt(CMath::m_machineepsilon))*stpmax); + } + //--- check + if(state.m_xupdated) + { + err=err || MathAbs(state.m_x[0]-xprev)>(double)((1+MathSqrt(CMath::m_machineepsilon))*stpmax); + xprev=state.m_x[0]; + } + } + //--- Ability to solve problems with function which is unbounded from below + n=1; + ArrayResize(x,n); + ArrayResize(bl,n); + ArrayResize(bu,n); + bl[0]=4*CMath::RandomReal()+1; + bu[0]=bl[0]+1; + x[0]=0.5*(bl[0]+bu[0]); + //--- function calls + CMinBLEIC::MinBLEICCreate(n,x,state); + CMinBLEIC::MinBLEICSetBC(state,bl,bu); + CMinBLEIC::MinBLEICSetInnerCond(state,epsg,0,0); + CMinBLEIC::MinBLEICSetOuterCond(state,epsc,epsc); + //--- cycle + while(CMinBLEIC::MinBLEICIteration(state)) + { + //--- check + if(state.m_needfg) + { + state.m_f=-(1.0E8*CMath::Sqr(state.m_x[0])); + state.m_g[0]=-(2.0E8*state.m_x[0]); + } + } + //--- function call + CMinBLEIC::MinBLEICResults(state,x,rep); + //--- search errors + err=err || MathAbs(x[0]-bu[0])>epsc; + //--- 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 mild outer stopping conditions - OuterEpsX=1.0,but + //--- inner conditions are very stringent + //--- * and we test that in the extremum inner stopping conditions are + //--- satisfied subject to the current scaling coefficients. + tmpeps=1.0E-10; + for(n=1;n<=10;n++) + { + for(ckind=0;ckind<=3;ckind++) + { + for(pkind=0;pkind<=2;pkind++) + { + //--- allocation + ArrayResize(x,n); + ArrayResize(a,n); + ArrayResize(s,n); + ArrayResize(h,n); + ArrayResize(bl,n); + ArrayResize(bu,n); + c.Resize(1,n+1); + ArrayResize(ct,1); + ct[0]=0; + c[0].Set(n,0); + //--- change values + for(i=0;i<=n-1;i++) + { + x[i]=CMath::RandomReal()+1; + bl[i]=-100000; + bu[i]=100000; + c[0].Set(i,0); + a[i]=MathExp(MathLog(100)*(2*CMath::RandomReal()-1)); + s[i]=MathExp(MathLog(100)*(2*CMath::RandomReal()-1)); + h[i]=MathExp(MathLog(100)*(2*CMath::RandomReal()-1)); + } + CMinBLEIC::MinBLEICCreate(n,x,state); + //--- check + if(ckind==1 || ckind==3) + CMinBLEIC::MinBLEICSetBC(state,bl,bu); + //--- check + if(ckind==2 || ckind==3) + CMinBLEIC::MinBLEICSetLC(state,c,ct,1); + //--- check + if(pkind==1) + CMinBLEIC::MinBLEICSetPrecDiag(state,h); + //--- check + if(pkind==2) + CMinBLEIC::MinBLEICSetPrecScale(state); + //--- function calls + CMinBLEIC::MinBLEICSetInnerCond(state,tmpeps,0,0); + CMinBLEIC::MinBLEICSetOuterCond(state,1.0,1.0E-8); + CMinBLEIC::MinBLEICSetScale(state,s); + //--- cycle + while(CMinBLEIC::MinBLEICIteration(state)) + { + //--- check + if(state.m_needfg) + { + state.m_f=0; + for(i=0;i<=n-1;i++) + { + state.m_f=state.m_f+a[i]*MathPow(state.m_x[i],4); + state.m_g[i]=4*a[i]*MathPow(state.m_x[i],3); + } + } + } + //--- function call + CMinBLEIC::MinBLEICResults(state,x,rep); + //--- check + if(rep.m_terminationtype<=0) + { + err=true; + return; + } + //--- change value + v=0; + for(i=0;i<=n-1;i++) + v=v+CMath::Sqr(s[i]*4*a[i]*MathPow(x[i],3)); + v=MathSqrt(v); + //--- search errors + err=err || v>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 + if(ckind==0) + vc=1.0; + //--- check + if(ckind==1) + vc=1.0E+6; + //--- check + if(mkind==0) + vm=1.0E+8; + //--- check + if(mkind==1) + vm=1.0E+20; + //--- check + if(mkind==2) + vm=CInfOrNaN::PositiveInfinity(); + //--- Create optimizer,solve optimization problem + epsg=1.0E-6*vc; + ArrayResize(x,1); + x[0]=0.0; + //--- function calls + CMinBLEIC::MinBLEICCreate(1,x,state); + CMinBLEIC::MinBLEICSetInnerCond(state,epsg,0,0); + CMinBLEIC::MinBLEICSetOuterCond(state,1.0E-6,1.0E-6); + //--- cycle + while(CMinBLEIC::MinBLEICIteration(state)) + { + //--- check + if(state.m_needfg) + { + //--- check + if(-0.999999epsg; + } + } + } + } +//+------------------------------------------------------------------+ +//| 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 CTestMinBLEICUnit::TestConv(bool &err) + { +//--- create variables + int passcount=0; + int pass=0; + double epsc=0; + double epsg=0; + double tol=0; +//--- create arrays + double bl[]; + double bu[]; + double x[]; + int ct[]; +//--- create matrix + CMatrixDouble c; +//--- objects of classes + CMinBLEICState state; + CMinBLEICReport rep; +//--- initialization + epsc=1.0E-4; + epsg=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 + ArrayResize(x,2); + ArrayResize(bl,2); + ArrayResize(bu,2); + c.Resize(4,3); + ArrayResize(ct,4); +//--- change values + bl[0]=-1; + bl[1]=-1; + bu[0]=1; + bu[1]=1; + c[0].Set(0,1); + c[0].Set(1,1); + c[0].Set(2,1.5); + ct[0]=-1; + c[1].Set(0,1); + c[1].Set(1,-1); + c[1].Set(2,1.5); + ct[1]=-1; + c[2].Set(0,-1); + c[2].Set(1,1); + c[2].Set(2,1.5); + ct[2]=-1; + c[3].Set(0,-1); + c[3].Set(1,-1); + c[3].Set(2,1.5); + ct[3]=-1; +//--- calculation + for(pass=1;pass<=passcount;pass++) + { + //--- f0 + x[0]=0.2*CMath::RandomReal()-0.1; + x[1]=0.2*CMath::RandomReal()-0.1; + //--- function call + CMinBLEIC::MinBLEICCreate(2,x,state); + CMinBLEIC::MinBLEICSetBC(state,bl,bu); + CMinBLEIC::MinBLEICSetLC(state,c,ct,4); + CMinBLEIC::MinBLEICSetInnerCond(state,epsg,0,0); + CMinBLEIC::MinBLEICSetOuterCond(state,epsc,epsc); + //--- cycle + while(CMinBLEIC::MinBLEICIteration(state)) + { + //--- check + if(state.m_needfg) + { + state.m_f=state.m_x[0]+0.001*state.m_x[1]; + state.m_g[0]=1; + state.m_g[1]=0.001; + } + } + //--- function call + CMinBLEIC::MinBLEICResults(state,x,rep); + //--- check + if(rep.m_terminationtype>0) + { + //--- search errors + err=err || MathAbs(x[0]+1)>tol; + err=err || MathAbs(x[1]+0.5)>tol; + } + else + err=true; + //--- f1 + x[0]=0.2*CMath::RandomReal()-0.1; + x[1]=0.2*CMath::RandomReal()-0.1; + //--- function calls + CMinBLEIC::MinBLEICCreate(2,x,state); + CMinBLEIC::MinBLEICSetBC(state,bl,bu); + CMinBLEIC::MinBLEICSetLC(state,c,ct,4); + CMinBLEIC::MinBLEICSetInnerCond(state,epsg,0,0); + CMinBLEIC::MinBLEICSetOuterCond(state,epsc,epsc); + //--- cycle + while(CMinBLEIC::MinBLEICIteration(state)) + { + //--- check + if(state.m_needfg) + { + state.m_f=CMath::Sqr(state.m_x[0]+10)+CMath::Sqr(state.m_x[1]); + state.m_g[0]=2*(state.m_x[0]+10); + state.m_g[1]=2*state.m_x[1]; + } + } + //--- function call + CMinBLEIC::MinBLEICResults(state,x,rep); + //--- check + if(rep.m_terminationtype>0) + { + //--- search errors + err=err || MathAbs(x[0]+1)>tol; + err=err || MathAbs(x[1])>tol; + } + else + err=true; + //--- f2 + x[0]=0.2*CMath::RandomReal()-0.1; + x[1]=0.2*CMath::RandomReal()-0.1; + //--- function calls + CMinBLEIC::MinBLEICCreate(2,x,state); + CMinBLEIC::MinBLEICSetBC(state,bl,bu); + CMinBLEIC::MinBLEICSetLC(state,c,ct,4); + CMinBLEIC::MinBLEICSetInnerCond(state,epsg,0,0); + CMinBLEIC::MinBLEICSetOuterCond(state,epsc,epsc); + //--- cycle + while(CMinBLEIC::MinBLEICIteration(state)) + { + //--- check + if(state.m_needfg) + { + state.m_f=CMath::Sqr(state.m_x[0]+10)+CMath::Sqr(state.m_x[1]-0.6); + state.m_g[0]=2*(state.m_x[0]+10); + state.m_g[1]=2*(state.m_x[1]-0.6); + } + } + //--- function call + CMinBLEIC::MinBLEICResults(state,x,rep); + //--- check + if(rep.m_terminationtype>0) + { + //--- search errors + err=err || MathAbs(x[0]+1)>tol; + err=err || MathAbs(x[1]-0.5)>tol; + } + else + err=true; + } + } +//+------------------------------------------------------------------+ +//| This function tests preconditioning | +//| On failure sets Err to True (leaves it unchanged otherwise) | +//+------------------------------------------------------------------+ +static void CTestMinBLEICUnit::TestPreconditioning(bool &err) + { +//--- create variables + int pass=0; + int n=0; + int i=0; + int k=0; + int cntb1=0; + int cntb2=0; + int cntg1=0; + int cntg2=0; + double epsg=0; + int fkind=0; + int ckind=0; + int fk=0; +//--- create arrays + double x[]; + double x0[]; + int ct[]; + double bl[]; + double bu[]; + double vd[]; + double d[]; + double units[]; + double s[]; + double diagh[]; +//--- create matrix + CMatrixDouble v; + CMatrixDouble c; +//--- objects of classes + CMinBLEICState state; + CMinBLEICReport rep; +//--- 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)^FK*x[i])^2,i=0..N-1) +//--- * FK is either +1 or -1 (we try both to test different aspects of preconditioning) +//--- * 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=30; + epsg=1.0E-10; + for(n=5;n<=8;n++) + { + for(fkind=0;fkind<=1;fkind++) + { + for(ckind=0;ckind<=3;ckind++) + { + fk=1-2*fkind; + //--- allocation + ArrayResize(x,n); + ArrayResize(units,n); + for(i=0;i<=n-1;i++) + { + x[i]=0; + units[i]=1; + } + //--- function call + CMinBLEIC::MinBLEICCreate(n,x,state); + //--- check + if(ckind==1 || ckind==3) + { + //--- allocation + ArrayResize(bl,n); + ArrayResize(bu,n); + for(i=0;i<=n-1;i++) + { + bl[i]=-1; + bu[i]=1; + } + //--- function call + CMinBLEIC::MinBLEICSetBC(state,bl,bu); + } + //--- check + if(ckind==2 || ckind==3) + { + //--- allocation + c.Resize(1,n+1); + ArrayResize(ct,1); + //--- change value + ct[0]=CMath::RandomInteger(3)-1; + for(i=0;i<=n-1;i++) + c[0].Set(i,2*CMath::RandomReal()-1); + c[0].Set(n,0); + //--- function call + CMinBLEIC::MinBLEICSetLC(state,c,ct,1); + } + //--- Test it with default preconditioner VS. perturbed diagonal preconditioner + CMinBLEIC::MinBLEICSetPrecDefault(state); + CMinBLEIC::MinBLEICSetScale(state,units); + //--- calculation + cntb1=0; + for(pass=0;pass<=k-1;pass++) + { + for(i=0;i<=n-1;i++) + x[i]=2*CMath::RandomReal()-1; + //--- function call + CMinBLEIC::MinBLEICRestartFrom(state,x); + //--- cycle + while(CMinBLEIC::MinBLEICIteration(state)) + CalcIIP2(state,n,fk); + //--- function call + CMinBLEIC::MinBLEICResults(state,x,rep); + cntb1=cntb1+rep.m_inneriterationscount; + //--- search errors + err=err || rep.m_terminationtype<=0; + } + //--- allocation + ArrayResize(diagh,n); + for(i=0;i<=n-1;i++) + diagh[i]=2*MathPow(i*i+1,2*fk)*(0.8+0.4*CMath::RandomReal()); + //--- function calls + CMinBLEIC::MinBLEICSetPrecDiag(state,diagh); + CMinBLEIC::MinBLEICSetScale(state,units); + //--- calculation + cntg1=0; + for(pass=0;pass<=k-1;pass++) + { + for(i=0;i<=n-1;i++) + x[i]=2*CMath::RandomReal()-1; + //--- function call + CMinBLEIC::MinBLEICRestartFrom(state,x); + //--- cycle + while(CMinBLEIC::MinBLEICIteration(state)) + CalcIIP2(state,n,fk); + //--- function call + CMinBLEIC::MinBLEICResults(state,x,rep); + cntg1=cntg1+rep.m_inneriterationscount; + //--- search errors + err=err || rep.m_terminationtype<=0; + } + //--- search errors + err=err || cntb10) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + err=err || MathAbs(p[i][j]-pexact[i][j])>threshold; + } + } + else + err=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 + pexact.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + pexact[i].Set(j,CMath::RandomReal()); + } + //--- calculation + for(j=0;j<=n-1;j++) + { + i=CMath::RandomInteger(n); + pexact[i].Set(j,pexact[i][j]+0.1); + } + for(j=0;j<=n-1;j++) + { + v=0; + for(i=0;i<=n-1;i++) + v=v+pexact[i][j]; + for(i=0;i<=n-1;i++) + pexact[i].Set(j,pexact[i][j]/v); + } + //--- Initialize solver: + //--- * create object + //--- * add tracks + CMarkovCPD::MCPDCreate(n,s); + for(i=0;i<=n-1;i++) + { + //--- allocation + xy.Resize(2,n); + for(j=0;j<=n-1;j++) + xy[0].Set(j,0); + //--- "main" element + xy[0].Set(i,1.0-2*offdiagonal); + for(j=0;j<=n-1;j++) + xy[1].Set(j,(1.0-2*offdiagonal)*pexact[j][i]); + //--- off-diagonal ones + if(i>0) + { + xy[0].Set(i-1,offdiagonal); + for(j=0;j<=n-1;j++) + xy[1].Set(j,xy[1][j]+offdiagonal*pexact[j][i-1]); + } + //--- check + if(i0) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + err=err || MathAbs(p[i][j]-pexact[i][j])>threshold; + } + } + else + err=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 + pexact.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + pexact[i].Set(j,CMath::RandomReal()); + } + //--- change values + for(j=0;j<=n-1;j++) + { + i=CMath::RandomInteger(n); + pexact[i].Set(j,pexact[i][j]+0.1); + } + for(j=0;j<=n-1;j++) + { + v=0; + for(i=0;i<=n-1;i++) + v=v+pexact[i][j]; + for(i=0;i<=n-1;i++) + pexact[i].Set(j,pexact[i][j]/v); + } + //--- Initialize solver: + //--- * create object + //--- * add tracks + CMarkovCPD::MCPDCreate(n,s); + for(i=0;i<=n-1;i++) + { + //--- allocation + xy.Resize(2,n); + for(j=0;j<=n-1;j++) + xy[0].Set(j,0); + //--- "main" element + v0=9*CMath::RandomReal()+1; + xy[0].Set(i,v0*(1.0-2*offdiagonal)); + for(j=0;j<=n-1;j++) + xy[1].Set(j,v0*(1.0-2*offdiagonal)*pexact[j][i]); + //--- off-diagonal ones + if(i>0) + { + xy[0].Set(i-1,v0*offdiagonal); + for(j=0;j<=n-1;j++) + xy[1].Set(j,xy[1][j]+v0*offdiagonal*pexact[j][i-1]); + } + //--- check + if(i0) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + err=err || MathAbs(p[i][j]-pexact[i][j])>threshold; + } + } + else + err=true; + } + } +//+------------------------------------------------------------------+ +//| Test for different combinations of "entry"/"exit" models | +//| On failure sets Err to True (leaves it unchanged otherwise) | +//+------------------------------------------------------------------+ +static void CTestMCPDUnit::TestEntryExit(bool &err) + { +//--- create variables + int n=0; + double threshold=0; + int entrystate=0; + int exitstate=0; + int entrykind=0; + int exitkind=0; + int popkind=0; + int i=0; + int j=0; + int k=0; + double v=0; + int i_=0; +//--- create matrix + CMatrixDouble p; + CMatrixDouble pexact; + CMatrixDouble xy; +//--- objects of classes + CMCPDState s; + CMCPDReport rep; +//--- initialization + threshold=1.0E-3; +//--- calculation + 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 + { + //--- check + if(entrykind==0) + entrystate=-1; + else + entrystate=CMath::RandomInteger(n); + //--- check + if(exitkind==0) + exitstate=-1; + else + exitstate=CMath::RandomInteger(n); + } + 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 + pexact.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + pexact[i].Set(j,1+CMath::RandomInteger(5)); + //--- check + if(i==entrystate) + pexact[i].Set(j,0.0); + //--- check + if(j==exitstate) + pexact[i].Set(j,0.0); + } + } + //--- calculation + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i=0;i<=n-1;i++) + v=v+pexact[i][j]; + //--- check + if(v!=0.0) + { + for(i=0;i<=n-1;i++) + pexact[i].Set(j,pexact[i][j]/v); + } + } + //--- Create MCPD solver + if(entrystate<0 && exitstate<0) + CMarkovCPD::MCPDCreate(n,s); + //--- check + if(entrystate>=0 && exitstate<0) + CMarkovCPD::MCPDCreateEntry(n,entrystate,s); + //--- check + if(entrystate<0 && exitstate>=0) + CMarkovCPD::MCPDCreateExit(n,exitstate,s); + //--- check + if(entrystate>=0 && exitstate>=0) + CMarkovCPD::MCPDCreateEntryExit(n,entrystate,exitstate,s); + //--- 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 + xy.Resize(2+CMath::RandomInteger(3),n); + for(j=0;j<=n-1;j++) + xy[0].Set(j,0.05*CMath::RandomReal()); + xy[0].Set(k,1+CMath::RandomReal()); + //--- calculation + for(i=1;i<=CAp::Rows(xy)-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(j!=entrystate) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=pexact[j][i_]*xy[i-1][i_]; + xy[i].Set(j,v); + } + else + xy[i].Set(j,CMath::RandomReal()); + } + } + //--- Normalize,if needed + if(popkind==1) + { + for(i=0;i<=CAp::Rows(xy)-1;i++) + { + //--- change value + v=0.0; + for(j=0;j<=n-1;j++) + v=v+xy[i][j]; + //--- check + if(v>0.0) + { + for(j=0;j<=n-1;j++) + xy[i].Set(j,xy[i][j]/v); + } + } + } + //--- Add track + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + } + //--- Solve and test + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- check + if(rep.m_terminationtype>0) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + err=err || MathAbs(p[i][j]-pexact[i][j])>threshold; + } + } + else + err=true; + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Test equality constraints. | +//| On failure sets Err to True (leaves it unchanged otherwise) | +//+------------------------------------------------------------------+ +static void CTestMCPDUnit::TestEC(bool &err) + { +//--- create variables + int n=0; + int entrystate=0; + int exitstate=0; + int entrykind=0; + int exitkind=0; + int i=0; + int j=0; + int ic=0; + int jc=0; + double vc=0; +//--- create matrix + CMatrixDouble p; + CMatrixDouble ec; + CMatrixDouble xy; +//--- objects of classes + CMCPDState s; + CMCPDReport rep; +//--- 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; + //--- check + if(exitkind==0) + exitstate=-1; + else + exitstate=n-1; + //--- allocation + xy.Resize(2*n,n); + for(i=0;i<=CAp::Rows(xy)-1;i++) + { + for(j=0;j<=CAp::Cols(xy)-1;j++) + xy[i].Set(j,CMath::RandomReal()); + } + //--- 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 + if(!CAp::Assert(n>=4,"TestEC: expectation failed")) + return; + ic=1+CMath::RandomInteger(n-2); + jc=1+CMath::RandomInteger(n-2); + vc=CMath::RandomReal(); + //--- function calls + CreateEE(n,entrystate,exitstate,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + CMarkovCPD::MCPDAddEC(s,ic,jc,vc); + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- check + if(rep.m_terminationtype>0) + err=err || p[ic][jc]!=vc; + else + err=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 + if(!CAp::Assert(n>=3,"TestEC: expectation failed")) + return; + jc=CMath::RandomInteger(n-1); + vc=0.95; + //--- function calls + CreateEE(n,entrystate,exitstate,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + for(i=1;i<=n-1;i++) + CMarkovCPD::MCPDAddEC(s,i,jc,vc); + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- search errors + err=err || rep.m_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=CMath::RandomInteger(n); + //--- function calls + CreateEE(n,entrystate,exitstate,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + CMarkovCPD::MCPDAddEC(s,entrystate,jc,0.0); + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- search errors + err=err || rep.m_terminationtype<=0; + //--- function calls + CreateEE(n,entrystate,exitstate,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + CMarkovCPD::MCPDAddEC(s,entrystate,jc,0.5); + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- search errors + err=err || rep.m_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=CMath::RandomInteger(n); + //--- function calls + CreateEE(n,entrystate,exitstate,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + CMarkovCPD::MCPDAddEC(s,ic,exitstate,0.0); + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- search errors + err=err || rep.m_terminationtype<=0; + //--- function calls + CreateEE(n,entrystate,exitstate,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + CMarkovCPD::MCPDAddEC(s,ic,exitstate,0.5); + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- search errors + err=err || rep.m_terminationtype!=-3; + } + //--- Test SetEC() call - we constrain subset of non-entry + //--- non-exit elements and test it. + if(!CAp::Assert(n>=4,"TestEC: expectation failed")) + return; + //--- allocation + ec.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + ec[i].Set(j,CInfOrNaN::NaN()); + } + for(j=1;j<=n-2;j++) + ec[1+CMath::RandomInteger(n-2)].Set(j,0.1+0.1*CMath::RandomReal()); + //--- function calls + CreateEE(n,entrystate,exitstate,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + CMarkovCPD::MCPDSetEC(s,ec); + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- check + if(rep.m_terminationtype>0) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(CMath::IsFinite(ec[i][j])) + err=err || p[i][j]!=ec[i][j]; + } + } + } + else + err=true; + } + } + } + } +//+------------------------------------------------------------------+ +//| Test bound constraints. | +//| On failure sets Err to True (leaves it unchanged otherwise) | +//+------------------------------------------------------------------+ +static void CTestMCPDUnit::TestBC(bool &err) + { +//--- create variables + int n=0; + int entrystate=0; + int exitstate=0; + int entrykind=0; + int exitkind=0; + int i=0; + int j=0; + int ic=0; + int jc=0; + double vl=0; + double vu=0; +//--- create matrix + CMatrixDouble p; + CMatrixDouble bndl; + CMatrixDouble bndu; + CMatrixDouble xy; +//--- îáúåòû êëàññîâ + CMCPDState s; + CMCPDReport rep; +//--- 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; + //--- check + if(exitkind==0) + exitstate=-1; + else + exitstate=n-1; + //--- allocation + xy.Resize(2*n,n); + for(i=0;i<=CAp::Rows(xy)-1;i++) + { + for(j=0;j<=CAp::Cols(xy)-1;j++) + xy[i].Set(j,CMath::RandomReal()); + } + //--- 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 + if(!CAp::Assert(n>=4,"TestBC: expectation failed")) + return; + //--- change values + ic=1+CMath::RandomInteger(n-2); + jc=1+CMath::RandomInteger(n-2); + //--- check + if(CMath::RandomReal()>0.5) + vl=0.3*CMath::RandomReal(); + else + vl=CInfOrNaN::NegativeInfinity(); + //--- check + if(CMath::RandomReal()>0.5) + vu=0.5+0.3*CMath::RandomReal(); + else + vu=CInfOrNaN::PositiveInfinity(); + //--- function calls + CreateEE(n,entrystate,exitstate,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + CMarkovCPD::MCPDAddBC(s,ic,jc,vl,vu); + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- check + if(rep.m_terminationtype>0) + { + err=err || p[ic][jc]vu; + } + else + err=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 + if(!CAp::Assert(n>=3,"TestEC: expectation failed")) + return; + jc=CMath::RandomInteger(n-1); + vl=0.85; + vu=0.95; + //--- function calls + CreateEE(n,entrystate,exitstate,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + for(i=1;i<=n-1;i++) + CMarkovCPD::MCPDAddBC(s,i,jc,vl,vu); + //--- function calls + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- search errors + err=err || rep.m_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=CMath::RandomInteger(n); + //--- function calls + CreateEE(n,entrystate,exitstate,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + CMarkovCPD::MCPDAddBC(s,entrystate,jc,0.0,1.0); + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- search errors + err=err || rep.m_terminationtype<=0; + //--- function calls + CreateEE(n,entrystate,exitstate,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + CMarkovCPD::MCPDAddBC(s,entrystate,jc,0.5,1.0); + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- search errors + err=err || rep.m_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=CMath::RandomInteger(n); + //--- function calls + CreateEE(n,entrystate,exitstate,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + CMarkovCPD::MCPDAddBC(s,ic,exitstate,0.0,1.0); + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- search errors + err=err || rep.m_terminationtype<=0; + //--- function calls + CreateEE(n,entrystate,exitstate,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + CMarkovCPD::MCPDAddBC(s,ic,exitstate,0.5,1.0); + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- search errors + err=err || rep.m_terminationtype!=-3; + } + //--- Test SetBC() call - we constrain subset of non-entry + //--- non-exit elements and test it. + if(!CAp::Assert(n>=4,"TestBC: expectation failed")) + return; + //--- allocation + bndl.Resize(n,n); + bndu.Resize(n,n); + //--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + bndl[i].Set(j,CInfOrNaN::NegativeInfinity()); + bndu[i].Set(j,CInfOrNaN::PositiveInfinity()); + } + } + //--- change values + for(j=1;j<=n-2;j++) + { + i=1+CMath::RandomInteger(n-2); + bndl[i].Set(j,0.5-0.1*CMath::RandomReal()); + bndu[i].Set(j,0.5+0.1*CMath::RandomReal()); + } + //--- function calls + CreateEE(n,entrystate,exitstate,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + CMarkovCPD::MCPDSetBC(s,bndl,bndu); + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- check + if(rep.m_terminationtype>0) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + err=err || p[i][j]bndu[i][j]; + } + } + } + else + err=true; + } + } + } + } +//+------------------------------------------------------------------+ +//| Test bound constraints. | +//| On failure sets Err to True (leaves it unchanged otherwise) | +//+------------------------------------------------------------------+ +static void CTestMCPDUnit::TestLC(bool &err) + { +//--- create variables + int n=0; + int entrystate=0; + int exitstate=0; + int entrykind=0; + int exitkind=0; + int i=0; + int j=0; + int k=0; + int t=0; + int jc=0; + double v=0; + double threshold=0; +//--- create array + int ct[]; +//--- create matrix + CMatrixDouble p; + CMatrixDouble c; + CMatrixDouble xy; +//--- objects of classes + CMCPDState s; + CMCPDReport rep; +//--- initialization + threshold=1.0E5*CMath::m_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; + //--- check + if(exitkind==0) + exitstate=-1; + else + exitstate=n-1; + //--- allocation + xy.Resize(2*n,n); + for(i=0;i<=CAp::Rows(xy)-1;i++) + { + for(j=0;j<=CAp::Cols(xy)-1;j++) + xy[i].Set(j,CMath::RandomReal()); + } + //--- 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). + if(!CAp::Assert(n>=4,"TestLC: expectation failed")) + return; + //--- allocation + c.Resize(1,n*n+1); + ArrayResize(ct,1); + //--- calculation + v=0; + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(((i==0 || i==n-1) || j==0) || j==n-1) + c[0].Set(i*n+j,0); + else + { + c[0].Set(i*n+j,CMath::RandomReal()); + v=v+c[0][i*n+j]*(1.0/(double)n); + } + } + } + //--- change value + c[0].Set(n*n,v); + ct[0]=CMath::RandomInteger(3)-1; + //--- check + if(ct[0]<0) + c[0].Set(n*n,c[0][n*n]+0.1); + //--- check + if(ct[0]>0) + c[0].Set(n*n,c[0][n*n]-0.1); + //--- function calls + CreateEE(n,entrystate,exitstate,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + CMarkovCPD::MCPDSetLC(s,c,ct,1); + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- check + if(rep.m_terminationtype>0) + { + v=0; + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + v=v+p[i][j]*c[0][i*n+j]; + } + //--- check + if(ct[0]<0) + err=err || v>=c[0][n*n]+threshold; + //--- check + if(ct[0]==0) + err=err || MathAbs(v-c[0][n*n])>=threshold; + //--- check + if(ct[0]>0) + err=err || v<=c[0][n*n]-threshold; + } + else + err=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 + if(!CAp::Assert(n>=2,"TestLC: expectation failed")) + return; + jc=CMath::RandomInteger(n-1); + //--- allocation + c.Resize(1,n*n+1); + ArrayResize(ct,1); + //--- change values + for(i=0;i<=n*n-1;i++) + c[0].Set(i,0.0); + for(i=0;i<=n-1;i++) + c[0].Set(n*i+jc,1.0); + c[0].Set(n*n,1.0); + ct[0]=0; + //--- function calls + CreateEE(n,entrystate,exitstate,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + CMarkovCPD::MCPDSetLC(s,c,ct,1); + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- search errors + err=err || rep.m_terminationtype<=0; + c[0].Set(n*n,2.0); + //--- function calls + CreateEE(n,entrystate,exitstate,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + CMarkovCPD::MCPDSetLC(s,c,ct,1); + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- search errors + err=err || rep.m_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) + { + c.Resize(1,n*n+1); + ArrayResize(ct,1); + for(i=0;i<=n*n-1;i++) + c[0].Set(i,0.0); + for(j=0;j<=n-1;j++) + c[0].Set(n*entrystate+j,1.0); + ct[0]=0; + c[0].Set(n*n,0.0); + //--- function calls + CreateEE(n,entrystate,exitstate,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + CMarkovCPD::MCPDSetLC(s,c,ct,1); + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- search errors + err=err || rep.m_terminationtype<=0; + c[0].Set(n*n,1.0); + //--- function calls + CreateEE(n,entrystate,exitstate,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + CMarkovCPD::MCPDSetLC(s,c,ct,1); + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- search errors + err=err || rep.m_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) + { + c.Resize(1,n*n+1); + ArrayResize(ct,1); + //--- change values + for(i=0;i<=n*n-1;i++) + c[0].Set(i,0.0); + for(i=0;i<=n-1;i++) + c[0].Set(n*i+exitstate,1.0); + ct[0]=0; + c[0].Set(n*n,0.0); + //--- function calls + CreateEE(n,entrystate,exitstate,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + CMarkovCPD::MCPDSetLC(s,c,ct,1); + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- search errors + err=err || rep.m_terminationtype<=0; + c[0].Set(n*n,1.0); + //--- function calls + CreateEE(n,entrystate,exitstate,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + CMarkovCPD::MCPDSetLC(s,c,ct,1); + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- search errors + err=err || rep.m_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 + xy.Resize(2*n,n); + for(i=0;i<=CAp::Rows(xy)-1;i++) + { + for(j=0;j<=CAp::Cols(xy)-1;j++) + xy[i].Set(j,CMath::RandomReal()); + } + //--- Generate random constraints + c.Resize(k,n*n+1); + ArrayResize(ct,k); + //--- calculation + for(i=0;i<=k-1;i++) + { + //--- Generate constraint and its right part + c[i].Set(n*n,0); + for(j=0;j<=n*n-1;j++) + { + c[i].Set(j,2*CMath::RandomReal()-1); + c[i].Set(n*n,c[i][n*n]+c[i][j]*(1.0/(double)n)); + } + ct[i]=CMath::RandomInteger(3)-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[i]<0) + c[i].Set(n*n,c[i][n*n]+0.1); + //--- check + if(ct[i]>0) + c[i].Set(n*n,c[i][n*n]-0.1); + } + //--- Test + CreateEE(n,-1,-1,s); + CMarkovCPD::MCPDAddTrack(s,xy,CAp::Rows(xy)); + CMarkovCPD::MCPDSetLC(s,c,ct,k); + CMarkovCPD::MCPDSolve(s); + CMarkovCPD::MCPDResults(s,p,rep); + //--- check + if(rep.m_terminationtype>0) + { + for(t=0;t<=k-1;t++) + { + //--- change values + v=0; + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + v=v+p[i][j]*c[t][i*n+j]; + } + //--- check + if(ct[t]<0) + err=err || v>=c[t][n*n]+threshold; + //--- check + if(ct[t]==0) + err=err || MathAbs(v-c[t][n*n])>=threshold; + //--- check + if(ct[t]>0) + err=err || v<=c[t][n*n]-threshold; + } + } + else + err=true; + } + } + } +//+------------------------------------------------------------------+ +//| This function is used to create MCPD object with arbitrary | +//| combination of entry and exit states | +//+------------------------------------------------------------------+ +static void CTestMCPDUnit::CreateEE(const int n,const int entrystate, + const int exitstate,CMCPDState &s) + { +//--- check + if(entrystate<0 && exitstate<0) + CMarkovCPD::MCPDCreate(n,s); +//--- check + if(entrystate>=0 && exitstate<0) + CMarkovCPD::MCPDCreateEntry(n,entrystate,s); +//--- check + if(entrystate<0 && exitstate>=0) + CMarkovCPD::MCPDCreateExit(n,exitstate,s); +//--- check + if(entrystate>=0 && exitstate>=0) + CMarkovCPD::MCPDCreateEntryExit(n,entrystate,exitstate,s); + } +//+------------------------------------------------------------------+ +//| Testing class CFbls | +//+------------------------------------------------------------------+ +class CTestFblsUnit + { +public: + //--- constructor, destructor + CTestFblsUnit(void); + ~CTestFblsUnit(void); + //--- public method + static bool TestFbls(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestFblsUnit::CTestFblsUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestFblsUnit::~CTestFblsUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing | +//+------------------------------------------------------------------+ +static bool CTestFblsUnit::TestFbls(const bool silent) + { +//--- create variables + int n=0; + int m=0; + int mx=0; + int i=0; + int j=0; + bool waserrors; + bool cgerrors; + double v=0; + double v1=0; + double v2=0; + double alpha=0; + double e1=0; + double e2=0; + int i_=0; +//--- create arrays + double tmp1[]; + double tmp2[]; + double b[]; + double x[]; + double xe[]; + double buf[]; +//--- create matrix + CMatrixDouble a; +//--- object of class + CFblsLinCgState cgstate; +//--- initialization + mx=10; + waserrors=false; + cgerrors=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++) + { + //--- allocation + a.Resize(m,n); + ArrayResize(b,n); + ArrayResize(x,n); + ArrayResize(xe,n); + ArrayResize(tmp1,m); + ArrayResize(tmp2,n); + //--- 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[i].Set(j,2*CMath::RandomReal()-1); + } + //--- change values + alpha=CMath::RandomReal()+0.1; + for(i=0;i<=n-1;i++) + { + b[i]=2*CMath::RandomReal()-1; + xe[i]=2*CMath::RandomReal()-1; + x[i]=(2*CMath::RandomInteger(2)-1)*(2+CMath::RandomReal()); + } + //--- Test dense CG (which solves A'A*x=b and accepts dense A) + for(i=0;i<=n-1;i++) + x[i]=(2*CMath::RandomInteger(2)-1)*(2+CMath::RandomReal()); + //--- function calls + CAblas::RMatrixMVect(m,n,a,0,0,0,x,0,tmp1,0); + CAblas::RMatrixMVect(n,m,a,0,0,1,tmp1,0,tmp2,0); + //--- calculation + for(i_=0;i_<=n-1;i_++) + tmp2[i_]=tmp2[i_]+alpha*x[i_]; + for(i_=0;i_<=n-1;i_++) + tmp2[i_]=tmp2[i_]-b[i_]; + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=tmp2[i_]*tmp2[i_]; + e1=MathSqrt(v); + //--- function calls + CFbls::FblsSolveCGx(a,m,n,alpha,b,x,buf); + CAblas::RMatrixMVect(m,n,a,0,0,0,x,0,tmp1,0); + CAblas::RMatrixMVect(n,m,a,0,0,1,tmp1,0,tmp2,0); + //--- calculation + for(i_=0;i_<=n-1;i_++) + tmp2[i_]=tmp2[i_]+alpha*x[i_]; + for(i_=0;i_<=n-1;i_++) + tmp2[i_]=tmp2[i_]-b[i_]; + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=tmp2[i_]*tmp2[i_]; + e2=MathSqrt(v); + //--- search errors + cgerrors=cgerrors || e2>0.001*e1; + //--- Test sparse CG (which relies on reverse communication) + for(i=0;i<=n-1;i++) + x[i]=(2*CMath::RandomInteger(2)-1)*(2+CMath::RandomReal()); + //--- function calls + CAblas::RMatrixMVect(m,n,a,0,0,0,x,0,tmp1,0); + CAblas::RMatrixMVect(n,m,a,0,0,1,tmp1,0,tmp2,0); + //--- calculation + for(i_=0;i_<=n-1;i_++) + tmp2[i_]=tmp2[i_]+alpha*x[i_]; + for(i_=0;i_<=n-1;i_++) + tmp2[i_]=tmp2[i_]-b[i_]; + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=tmp2[i_]*tmp2[i_]; + e1=MathSqrt(v); + //--- function call + CFbls::FblsCGCreate(x,b,n,cgstate); + //--- cycle + while(CFbls::FblsCGIteration(cgstate)) + { + //--- function calls + CAblas::RMatrixMVect(m,n,a,0,0,0,cgstate.m_x,0,tmp1,0); + CAblas::RMatrixMVect(n,m,a,0,0,1,tmp1,0,cgstate.m_ax,0); + for(i_=0;i_<=n-1;i_++) + cgstate.m_ax[i_]=cgstate.m_ax[i_]+alpha*cgstate.m_x[i_]; + //--- change values + v1=0.0; + for(i_=0;i_<=m-1;i_++) + v1+=tmp1[i_]*tmp1[i_]; + v2=0.0; + for(i_=0;i_<=n-1;i_++) + v2+=cgstate.m_x[i_]*cgstate.m_x[i_]; + cgstate.m_xax=v1+alpha*v2; + } + //--- function calls + CAblas::RMatrixMVect(m,n,a,0,0,0,cgstate.m_xk,0,tmp1,0); + CAblas::RMatrixMVect(n,m,a,0,0,1,tmp1,0,tmp2,0); + //--- calculation + for(i_=0;i_<=n-1;i_++) + tmp2[i_]=tmp2[i_]+alpha*cgstate.m_xk[i_]; + for(i_=0;i_<=n-1;i_++) + tmp2[i_]=tmp2[i_]-b[i_]; + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=tmp2[i_]*tmp2[i_]; + e2=MathSqrt(v); + //--- search errors + cgerrors=cgerrors || MathAbs(e1-cgstate.m_e1)>100*CMath::m_machineepsilon*e1; + cgerrors=cgerrors || MathAbs(e2-cgstate.m_e2)>100*CMath::m_machineepsilon*e1; + cgerrors=cgerrors || e2>0.001*e1; + } + } +//--- report + waserrors=cgerrors; +//--- check + if(!silent) + { + Print("TESTING FBLS"); + Print("CG ERRORS: "); + //--- check + if(cgerrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Testing class CMinLBFGS | +//+------------------------------------------------------------------+ +class CTestMinLBFGSUnit + { +private: + //--- private methods + static void TestFunc1(CMinLBFGSState &state); + static void TestFunc2(CMinLBFGSState &state); + static void TestFunc3(CMinLBFGSState &state); + static void CalcIIP2(CMinLBFGSState &state,const int n); + static void TestPreconditioning(bool &err); + static void TestOther(bool &err); +public: + //--- constructor, destructor + CTestMinLBFGSUnit(void); + ~CTestMinLBFGSUnit(void); + //--- public method + static bool TestMinLBFGS(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestMinLBFGSUnit::CTestMinLBFGSUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestMinLBFGSUnit::~CTestMinLBFGSUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CMinLBFGS | +//+------------------------------------------------------------------+ +static bool CTestMinLBFGSUnit::TestMinLBFGS(const bool silent) + { +//--- create variables + bool waserrors; + bool referror; + bool nonconverror; + bool eqerror; + bool converror; + bool crashtest; + bool othererrors; + bool restartserror; + bool precerror; + int n=0; + int m=0; + int i=0; + int j=0; + double v=0; + int maxits=0; + double diffstep=0; + int dkind=0; + int i_=0; +//--- create arrays + double x[]; + double xe[]; + double b[]; + double xlast[]; + double diagh[]; +//--- create matrix + CMatrixDouble a; +//--- objects of classes + CMinLBFGSState state; + CMinLBFGSReport rep; +//--- initialization + waserrors=false; + precerror=false; + nonconverror=false; + restartserror=false; + eqerror=false; + converror=false; + crashtest=false; + othererrors=false; + referror=false; +//--- function calls + TestPreconditioning(precerror); + TestOther(othererrors); +//--- Reference problem + diffstep=1.0E-6; + for(dkind=0;dkind<=1;dkind++) + { + //--- allocation + ArrayResize(x,3); + n=3; + m=2; + x[0]=100*CMath::RandomReal()-50; + x[1]=100*CMath::RandomReal()-50; + x[2]=100*CMath::RandomReal()-50; + //--- check + if(dkind==0) + CMinLBFGS::MinLBFGSCreate(n,m,x,state); + //--- check + if(dkind==1) + CMinLBFGS::MinLBFGSCreateF(n,m,x,diffstep,state); + //--- function call + CMinLBFGS::MinLBFGSSetCond(state,0,0,0,0); + //--- cycle + while(CMinLBFGS::MinLBFGSIteration(state)) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=CMath::Sqr(state.m_x[0]-2)+CMath::Sqr(state.m_x[1])+CMath::Sqr(state.m_x[2]-state.m_x[0]); + //--- check + if(state.m_needfg) + { + state.m_g[0]=2*(state.m_x[0]-2)+2*(state.m_x[0]-state.m_x[2]); + state.m_g[1]=2*state.m_x[1]; + state.m_g[2]=2*(state.m_x[2]-state.m_x[0]); + } + } + //--- function call + CMinLBFGS::MinLBFGSResults(state,x,rep); + //--- search errors + referror=((rep.m_terminationtype<=0 || MathAbs(x[0]-2)>0.001) || MathAbs(x[1])>0.001) || MathAbs(x[2]-2)>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++) + { + //--- allocation + ArrayResize(x,1); + n=1; + m=1; + v=-100; + //--- calculation + while(v<0.1) + { + x[0]=v; + //--- check + if(dkind==0) + CMinLBFGS::MinLBFGSCreate(n,m,x,state); + //--- check + if(dkind==1) + CMinLBFGS::MinLBFGSCreateF(n,m,x,diffstep,state); + //--- function call + CMinLBFGS::MinLBFGSSetCond(state,1.0E-9,0,0,0); + //--- cycle + while(CMinLBFGS::MinLBFGSIteration(state)) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=CMath::Sqr(state.m_x[0])/(1+CMath::Sqr(state.m_x[0])); + //--- check + if(state.m_needfg) + state.m_g[0]=(2*state.m_x[0]*(1+CMath::Sqr(state.m_x[0]))-CMath::Sqr(state.m_x[0])*2*state.m_x[0])/CMath::Sqr(1+CMath::Sqr(state.m_x[0])); + } + //--- function call + CMinLBFGS::MinLBFGSResults(state,x,rep); + //--- search errors + nonconverror=(nonconverror || rep.m_terminationtype<=0) || MathAbs(x[0])>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++) + { + //--- allocation + ArrayResize(x,3); + //--- change values + n=3; + m=2; + x[0]=10+10*CMath::RandomReal(); + x[1]=10+10*CMath::RandomReal(); + x[2]=10+10*CMath::RandomReal(); + //--- check + if(dkind==0) + CMinLBFGS::MinLBFGSCreate(n,m,x,state); + //--- check + if(dkind==1) + CMinLBFGS::MinLBFGSCreateF(n,m,x,diffstep,state); + //--- function calls + CMinLBFGS::MinLBFGSSetStpMax(state,0.1); + CMinLBFGS::MinLBFGSSetCond(state,0.0000001,0.0,0.0,0); + //--- calculation + for(i=0;i<=10;i++) + { + //--- check + if(!CMinLBFGS::MinLBFGSIteration(state)) + break; + TestFunc2(state); + } + //--- change values + x[0]=10+10*CMath::RandomReal(); + x[1]=10+10*CMath::RandomReal(); + x[2]=10+10*CMath::RandomReal(); + //--- function call + CMinLBFGS::MinLBFGSRestartFrom(state,x); + //--- cycle + while(CMinLBFGS::MinLBFGSIteration(state)) + TestFunc2(state); + //--- function call + CMinLBFGS::MinLBFGSResults(state,x,rep); + //--- search errors + restartserror=(((restartserror || rep.m_terminationtype<=0) || MathAbs(x[0]-MathLog(2))>0.01) || MathAbs(x[1])>0.01) || MathAbs(x[2]-MathLog(2))>0.01; + //--- change values + x[0]=10+10*CMath::RandomReal(); + x[1]=10+10*CMath::RandomReal(); + x[2]=10+10*CMath::RandomReal(); + //--- function call + CMinLBFGS::MinLBFGSRestartFrom(state,x); + //--- cycle + while(CMinLBFGS::MinLBFGSIteration(state)) + TestFunc2(state); + //--- function call + CMinLBFGS::MinLBFGSResults(state,x,rep); + //--- search errors + restartserror=(((restartserror || rep.m_terminationtype<=0) || MathAbs(x[0]-MathLog(2))>0.01) || MathAbs(x[1])>0.01) || MathAbs(x[2]-MathLog(2))>0.01; + } +//--- Linear equations + diffstep=1.0E-6; + for(n=1;n<=10;n++) + { + //--- Prepare task + a.Resize(n,n); + ArrayResize(x,n); + ArrayResize(xe,n); + ArrayResize(b,n); + //--- change values + for(i=0;i<=n-1;i++) + xe[i]=2*CMath::RandomReal()-1; + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,2*CMath::RandomReal()-1); + a[i].Set(i,a[i][i]+3*MathSign(a[i][i])); + } + //--- calculation + for(i=0;i<=n-1;i++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a[i][i_]*xe[i_]; + b[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[i]=2*CMath::RandomReal()-1; + //--- check + if(dkind==0) + CMinLBFGS::MinLBFGSCreate(n,m,x,state); + //--- check + if(dkind==1) + CMinLBFGS::MinLBFGSCreateF(n,m,x,diffstep,state); + //--- function call + CMinLBFGS::MinLBFGSSetCond(state,0,0,0,0); + //--- cycle + while(CMinLBFGS::MinLBFGSIteration(state)) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=0; + //--- check + if(state.m_needfg) + { + for(i=0;i<=n-1;i++) + state.m_g[i]=0; + } + for(i=0;i<=n-1;i++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a[i][i_]*state.m_x[i_]; + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=state.m_f+CMath::Sqr(v-b[i]); + //--- check + if(state.m_needfg) + { + for(j=0;j<=n-1;j++) + state.m_g[j]=state.m_g[j]+2*(v-b[i])*a[i][j]; + } + } + } + //--- function call + CMinLBFGS::MinLBFGSResults(state,x,rep); + //--- search errors + eqerror=eqerror || rep.m_terminationtype<=0; + for(i=0;i<=n-1;i++) + eqerror=eqerror || MathAbs(x[i]-xe[i])>0.001; + } + } + } +//--- Testing convergence properties + diffstep=1.0E-6; + for(dkind=0;dkind<=1;dkind++) + { + //--- allocation + ArrayResize(x,3); + //--- change values + n=3; + m=2; + for(i=0;i<=2;i++) + x[i]=6*CMath::RandomReal()-3; + //--- check + if(dkind==0) + CMinLBFGS::MinLBFGSCreate(n,m,x,state); + //--- check + if(dkind==1) + CMinLBFGS::MinLBFGSCreateF(n,m,x,diffstep,state); + //--- function call + CMinLBFGS::MinLBFGSSetCond(state,0.001,0,0,0); + //--- cycle + while(CMinLBFGS::MinLBFGSIteration(state)) + TestFunc3(state); + //--- function call + CMinLBFGS::MinLBFGSResults(state,x,rep); + //--- search errors + converror=converror || rep.m_terminationtype!=4; + //--- change values + for(i=0;i<=2;i++) + x[i]=6*CMath::RandomReal()-3; + //--- check + if(dkind==0) + CMinLBFGS::MinLBFGSCreate(n,m,x,state); + //--- check + if(dkind==1) + CMinLBFGS::MinLBFGSCreateF(n,m,x,diffstep,state); + //--- function call + CMinLBFGS::MinLBFGSSetCond(state,0,0.001,0,0); + //--- cycle + while(CMinLBFGS::MinLBFGSIteration(state)) + TestFunc3(state); + //--- function call + CMinLBFGS::MinLBFGSResults(state,x,rep); + //--- search errors + converror=converror || rep.m_terminationtype!=1; + //--- change values + for(i=0;i<=2;i++) + x[i]=6*CMath::RandomReal()-3; + //--- check + if(dkind==0) + CMinLBFGS::MinLBFGSCreate(n,m,x,state); + //--- check + if(dkind==1) + CMinLBFGS::MinLBFGSCreateF(n,m,x,diffstep,state); + //--- function call + CMinLBFGS::MinLBFGSSetCond(state,0,0,0.001,0); + //--- cycle + while(CMinLBFGS::MinLBFGSIteration(state)) + TestFunc3(state); + //--- function call + CMinLBFGS::MinLBFGSResults(state,x,rep); + //--- search errors + converror=converror || rep.m_terminationtype!=2; + //--- change values + for(i=0;i<=2;i++) + x[i]=2*CMath::RandomReal()-1; + //--- check + if(dkind==0) + CMinLBFGS::MinLBFGSCreate(n,m,x,state); + //--- check + if(dkind==1) + CMinLBFGS::MinLBFGSCreateF(n,m,x,diffstep,state); + //--- function call + CMinLBFGS::MinLBFGSSetCond(state,0,0,0,10); + //--- cycle + while(CMinLBFGS::MinLBFGSIteration(state)) + TestFunc3(state); + //--- function call + CMinLBFGS::MinLBFGSResults(state,x,rep); + //--- search errors + converror=(converror || rep.m_terminationtype!=5) || rep.m_iterationscount!=10; + } +//--- Crash test: too many iterations on a simple tasks +//--- May fail when encounter zero step,underflow or something like that + ArrayResize(x,3); + n=3; + m=2; + maxits=10000; + for(i=0;i<=2;i++) + x[i]=6*CMath::RandomReal()-3; +//--- function calls + CMinLBFGS::MinLBFGSCreate(n,m,x,state); + CMinLBFGS::MinLBFGSSetCond(state,0,0,0,maxits); +//--- cycle + while(CMinLBFGS::MinLBFGSIteration(state)) + { + state.m_f=CMath::Sqr(MathExp(state.m_x[0])-2)+CMath::Sqr(state.m_x[1])+CMath::Sqr(state.m_x[2]-state.m_x[0]); + state.m_g[0]=2*(MathExp(state.m_x[0])-2)*MathExp(state.m_x[0])+2*(state.m_x[0]-state.m_x[2]); + state.m_g[1]=2*state.m_x[1]; + state.m_g[2]=2*(state.m_x[2]-state.m_x[0]); + } +//--- function call + CMinLBFGS::MinLBFGSResults(state,x,rep); +//--- search errors + crashtest=crashtest || rep.m_terminationtype<=0; +//--- end + waserrors=((((((referror || nonconverror) || eqerror) || converror) || crashtest) || othererrors) || restartserror) || precerror; +//--- check + if(!silent) + { + Print("TESTING L-BFGS OPTIMIZATION"); + Print("REFERENCE PROBLEM: "); + //--- check + if(referror) + Print("FAILED"); + else + Print("OK"); + Print("NON-CONVEX PROBLEM: "); + //--- check + if(nonconverror) + Print("FAILED"); + else + Print("OK"); + Print("LINEAR EQUATIONS: "); + //--- check + if(eqerror) + Print("FAILED"); + else + Print("OK"); + Print("RESTARTS: "); + //--- check + if(restartserror) + Print("FAILED"); + else + Print("OK"); + Print("PRECONDITIONER: "); + //--- check + if(precerror) + Print("FAILED"); + else + Print("OK"); + Print("CONVERGENCE PROPERTIES: "); + //--- check + if(converror) + Print("FAILED"); + else + Print("OK"); + Print("CRASH TEST: "); + //--- check + if(crashtest) + Print("FAILED"); + else + Print("OK"); + Print("OTHER PROPERTIES: "); + //--- check + if(othererrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Calculate test function #1 | +//| It may show very interesting behavior when optimized with | +//| 'x[0]>=ln(2)' constraint. | +//+------------------------------------------------------------------+ +static void CTestMinLBFGSUnit::TestFunc1(CMinLBFGSState &state) + { +//--- check + if(state.m_x[0]<100.0) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=CMath::Sqr(MathExp(state.m_x[0])-2)+CMath::Sqr(state.m_x[1])+CMath::Sqr(state.m_x[2]-state.m_x[0]); + //--- check + if(state.m_needfg) + { + //--- calculation + state.m_g[0]=2*(MathExp(state.m_x[0])-2)*MathExp(state.m_x[0])+2*(state.m_x[0]-state.m_x[2]); + state.m_g[1]=2*state.m_x[1]; + state.m_g[2]=2*(state.m_x[2]-state.m_x[0]); + } + } + else + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=MathSqrt(CMath::m_maxrealnumber); + //--- check + if(state.m_needfg) + { + //--- calculation + state.m_g[0]=MathSqrt(CMath::m_maxrealnumber); + state.m_g[1]=0; + state.m_g[2]=0; + } + } + } +//+------------------------------------------------------------------+ +//| Calculate test function #2 | +//| Simple variation of #1,much more nonlinear,which makes unlikely | +//| premature convergence of algorithm. | +//+------------------------------------------------------------------+ +static void CTestMinLBFGSUnit::TestFunc2(CMinLBFGSState &state) + { +//--- check + if(state.m_x[0]<100.0) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=CMath::Sqr(MathExp(state.m_x[0])-2)+CMath::Sqr(CMath::Sqr(state.m_x[1]))+CMath::Sqr(state.m_x[2]-state.m_x[0]); + //--- check + if(state.m_needfg) + { + //--- calculation + state.m_g[0]=2*(MathExp(state.m_x[0])-2)*MathExp(state.m_x[0])+2*(state.m_x[0]-state.m_x[2]); + state.m_g[1]=4*state.m_x[1]*CMath::Sqr(state.m_x[1]); + state.m_g[2]=2*(state.m_x[2]-state.m_x[0]); + } + } + else + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=MathSqrt(CMath::m_maxrealnumber); + //--- check + if(state.m_needfg) + { + //--- calculation + state.m_g[0]=MathSqrt(CMath::m_maxrealnumber); + state.m_g[1]=0; + state.m_g[2]=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 CTestMinLBFGSUnit::TestFunc3(CMinLBFGSState &state) + { +//--- create a variable + double s=0; +//--- initialization + s=0.001; +//--- check + if(state.m_x[0]<100.0) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=CMath::Sqr(MathExp(state.m_x[0])-2)+CMath::Sqr(CMath::Sqr(state.m_x[1])+s)+CMath::Sqr(state.m_x[2]-state.m_x[0]); + //--- check + if(state.m_needfg) + { + //--- calculation + state.m_g[0]=2*(MathExp(state.m_x[0])-2)*MathExp(state.m_x[0])+2*(state.m_x[0]-state.m_x[2]); + state.m_g[1]=2*(CMath::Sqr(state.m_x[1])+s)*2*state.m_x[1]; + state.m_g[2]=2*(state.m_x[2]-state.m_x[0]); + } + } + else + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=MathSqrt(CMath::m_maxrealnumber); + //--- check + if(state.m_needfg) + { + //--- calculation + state.m_g[0]=MathSqrt(CMath::m_maxrealnumber); + state.m_g[1]=0; + state.m_g[2]=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 CTestMinLBFGSUnit::CalcIIP2(CMinLBFGSState &state,const int n) + { +//--- create variables + int i=0; +//--- check + if(state.m_needf || state.m_needfg) + state.m_f=0; +//--- calculation + for(i=0;i<=n-1;i++) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=state.m_f+CMath::Sqr(i*i+1)*CMath::Sqr(state.m_x[i]); + //--- check + if(state.m_needfg) + state.m_g[i]=CMath::Sqr(i*i+1)*2*state.m_x[i]; + } + } +//+------------------------------------------------------------------+ +//| This function tests preconditioning | +//| On failure sets Err to True (leaves it unchanged otherwise) | +//+------------------------------------------------------------------+ +static void CTestMinLBFGSUnit::TestPreconditioning(bool &err) + { +//--- create variables + int pass=0; + int n=0; + int m=0; + int i=0; + int j=0; + int k=0; + int cntb1=0; + int cntb2=0; + int cntg1=0; + int cntg2=0; + double epsg=0; + int pkind=0; +//--- create arrays + double x[]; + double s[]; + double diagh[]; +//--- create matrix + CMatrixDouble a; +//--- objects of classes + CMinLBFGSState state; + CMinLBFGSReport rep; +//--- initialization + 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=CMath::RandomInteger(2); + ArrayResize(x,n); + for(i=0;i<=n-1;i++) + x[i]=0; + //--- function call + CMinLBFGS::MinLBFGSCreate(n,m,x,state); + //--- Test it with default preconditioner + CMinLBFGS::MinLBFGSSetPrecDefault(state); + cntb1=0; + for(pass=0;pass<=k-1;pass++) + { + for(i=0;i<=n-1;i++) + x[i]=2*CMath::RandomReal()-1; + //--- function call + CMinLBFGS::MinLBFGSRestartFrom(state,x); + //--- cycle + while(CMinLBFGS::MinLBFGSIteration(state)) + CalcIIP2(state,n); + //--- function call + CMinLBFGS::MinLBFGSResults(state,x,rep); + cntb1=cntb1+rep.m_iterationscount; + //--- search errors + err=err || rep.m_terminationtype<=0; + } + //--- Test it with unit preconditioner + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(i==j) + a[i].Set(i,1); + else + a[i].Set(j,0); + } + } + //--- function call + CMinLBFGS::MinLBFGSSetPrecCholesky(state,a,pkind==0); + //--- change values + cntb2=0; + for(pass=0;pass<=k-1;pass++) + { + for(i=0;i<=n-1;i++) + x[i]=2*CMath::RandomReal()-1; + //--- function call + CMinLBFGS::MinLBFGSRestartFrom(state,x); + //--- cycle + while(CMinLBFGS::MinLBFGSIteration(state)) + CalcIIP2(state,n); + //--- function call + CMinLBFGS::MinLBFGSResults(state,x,rep); + cntb2=cntb2+rep.m_iterationscount; + //--- search errors + err=err || rep.m_terminationtype<=0; + } + //--- Test it with perturbed Hessian preconditioner + a.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(i==j) + a[i].Set(i,(i*i+1)*(0.8+0.4*CMath::RandomReal())); + else + { + //--- check + if((pkind==0 && j>i) || (pkind==1 && jfprev; + //--- check + if(fprev==CMath::m_maxrealnumber) + { + for(i=0;i<=n-1;i++) + err=err || state.m_x[i]!=x[i]; + } + //--- change values + fprev=state.m_f; + for(i_=0;i_<=n-1;i_++) + xlast[i_]=state.m_x[i_]; + } + } +//--- function call + CMinLBFGS::MinLBFGSResults(state,x,rep); +//--- search errors + for(i=0;i<=n-1;i++) + err=err || x[i]!=xlast[i]; +//--- Test differentiation vs. analytic gradient +//--- (first one issues NeedF requests,second one issues NeedFG requests) + n=50; + m=5; + diffstep=1.0E-6; +//--- calculation + for(dkind=0;dkind<=1;dkind++) + { + //--- allocation + ArrayResize(x,n); + ArrayResize(xlast,n); + for(i=0;i<=n-1;i++) + x[i]=1; + //--- check + if(dkind==0) + CMinLBFGS::MinLBFGSCreate(n,m,x,state); + //--- check + if(dkind==1) + CMinLBFGS::MinLBFGSCreateF(n,m,x,diffstep,state); + //--- function call + CMinLBFGS::MinLBFGSSetCond(state,0,0,0,n/2); + wasf=false; + wasfg=false; + //--- cycle + while(CMinLBFGS::MinLBFGSIteration(state)) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=0; + for(i=0;i<=n-1;i++) + { + //--- check + if(state.m_needf || state.m_needfg) + state.m_f=state.m_f+CMath::Sqr((1+i)*state.m_x[i]); + //--- check + if(state.m_needfg) + state.m_g[i]=2*(1+i)*state.m_x[i]; + } + //--- search errors + wasf=wasf || state.m_needf; + wasfg=wasfg || state.m_needfg; + } + //--- function call + CMinLBFGS::MinLBFGSResults(state,x,rep); + //--- check + if(dkind==0) + err=(err || wasf) || !wasfg; + //--- check + 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. + ArrayResize(x,1); + ArrayResize(s,1); +//--- change values + diffstep=CMath::RandomReal()*1.0E-6; + s[0]=MathExp(CMath::RandomReal()*4-2); + x[0]=0; +//--- function calls + CMinLBFGS::MinLBFGSCreateF(1,1,x,diffstep,state); + CMinLBFGS::MinLBFGSSetCond(state,1.0E-6,0,0,0); + CMinLBFGS::MinLBFGSSetScale(state,s); + v=0; +//--- cycle + while(CMinLBFGS::MinLBFGSIteration(state)) + { + state.m_f=CMath::Sqr(state.m_x[0]); + v=MathMax(v,MathAbs(state.m_x[0])); + } +//--- function call + CMinLBFGS::MinLBFGSResults(state,x,rep); + r=v/(s[0]*diffstep); +//--- search errors + err=err || MathAbs(MathLog(r))>MathLog(1+1000*CMath::m_machineepsilon); +//--- test maximum step + n=1; + m=1; +//--- allocation + ArrayResize(x,n); + x[0]=100; + stpmax=0.05+0.05*CMath::RandomReal(); +//--- function calls + CMinLBFGS::MinLBFGSCreate(n,m,x,state); + CMinLBFGS::MinLBFGSSetCond(state,1.0E-9,0,0,0); + CMinLBFGS::MinLBFGSSetStpMax(state,stpmax); + CMinLBFGS::MinLBFGSSetXRep(state,true); + xprev=x[0]; +//--- cycle + while(CMinLBFGS::MinLBFGSIteration(state)) + { + //--- check + if(state.m_needfg) + { + state.m_f=MathExp(state.m_x[0])+MathExp(-state.m_x[0]); + state.m_g[0]=MathExp(state.m_x[0])-MathExp(-state.m_x[0]); + //--- search errors + err=err || MathAbs(state.m_x[0]-xprev)>(double)((1+MathSqrt(CMath::m_machineepsilon))*stpmax); + } + //--- check + if(state.m_xupdated) + { + //--- search errors + err=err || MathAbs(state.m_x[0]-xprev)>(double)((1+MathSqrt(CMath::m_machineepsilon))*stpmax); + xprev=state.m_x[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; + m=1; + for(n=1;n<=10;n++) + { + for(pkind=0;pkind<=2;pkind++) + { + //--- allocation + ArrayResize(x,n); + ArrayResize(xlast,n); + ArrayResize(a,n); + ArrayResize(s,n); + ArrayResize(h,n); + //--- change values + for(i=0;i<=n-1;i++) + { + x[i]=CMath::RandomReal()+1; + a[i]=MathExp(MathLog(100)*(2*CMath::RandomReal()-1)); + s[i]=MathExp(MathLog(100)*(2*CMath::RandomReal()-1)); + h[i]=MathExp(MathLog(100)*(2*CMath::RandomReal()-1)); + } + //--- function call + CMinLBFGS::MinLBFGSCreate(n,m,x,state); + CMinLBFGS::MinLBFGSSetScale(state,s); + CMinLBFGS::MinLBFGSSetXRep(state,true); + //--- check + if(pkind==1) + CMinLBFGS::MinLBFGSSetPrecDiag(state,h); + //--- check + if(pkind==2) + CMinLBFGS::MinLBFGSSetPrecScale(state); + //--- Test gradient-based stopping condition + for(i=0;i<=n-1;i++) + x[i]=CMath::RandomReal()+1; + //--- function calls + CMinLBFGS::MinLBFGSSetCond(state,tmpeps,0,0,0); + CMinLBFGS::MinLBFGSRestartFrom(state,x); + //--- cycle + while(CMinLBFGS::MinLBFGSIteration(state)) + { + //--- check + if(state.m_needfg) + { + state.m_f=0; + for(i=0;i<=n-1;i++) + { + state.m_f=state.m_f+a[i]*MathPow(state.m_x[i],4); + state.m_g[i]=4*a[i]*MathPow(state.m_x[i],3); + } + } + } + //--- function call + CMinLBFGS::MinLBFGSResults(state,x,rep); + //--- check + if(rep.m_terminationtype<=0) + { + err=true; + return; + } + //--- change value + v=0; + for(i=0;i<=n-1;i++) + v=v+CMath::Sqr(s[i]*4*a[i]*MathPow(x[i],3)); + v=MathSqrt(v); + //--- search errors + err=err || v>tmpeps; + //--- Test step-based stopping condition + for(i=0;i<=n-1;i++) + x[i]=CMath::RandomReal()+1; + hasxlast=false; + //--- function call + CMinLBFGS::MinLBFGSSetCond(state,0,0,tmpeps,0); + CMinLBFGS::MinLBFGSRestartFrom(state,x); + //--- cycle + while(CMinLBFGS::MinLBFGSIteration(state)) + { + //--- check + if(state.m_needfg) + { + state.m_f=0; + for(i=0;i<=n-1;i++) + { + state.m_f=state.m_f+a[i]*MathPow(state.m_x[i],4); + state.m_g[i]=4*a[i]*MathPow(state.m_x[i],3); + } + } + //--- check + if(state.m_xupdated) + { + //--- check + if(hasxlast) + { + lastscaledstep=0; + for(i=0;i<=n-1;i++) + lastscaledstep=lastscaledstep+CMath::Sqr(state.m_x[i]-xlast[i])/CMath::Sqr(s[i]); + lastscaledstep=MathSqrt(lastscaledstep); + } + else + lastscaledstep=0; + //--- change values + for(i_=0;i_<=n-1;i_++) + xlast[i_]=state.m_x[i_]; + hasxlast=true; + } + } + //--- function call + CMinLBFGS::MinLBFGSResults(state,x,rep); + //--- check + if(rep.m_terminationtype<=0) + { + err=true; + return; + } + //--- search errors + err=err || 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 + if(ckind==0) + vc=1.0; + //--- check + if(ckind==1) + vc=1.0E+6; + //--- check + if(mkind==0) + vm=1.0E+8; + //--- check + if(mkind==1) + vm=1.0E+20; + //--- check + if(mkind==2) + vm=CInfOrNaN::PositiveInfinity(); + //--- Create optimizer,solve optimization problem + epsg=1.0E-6*vc; + ArrayResize(x,1); + x[0]=0.0; + //--- function calls + CMinLBFGS::MinLBFGSCreate(1,1,x,state); + CMinLBFGS::MinLBFGSSetCond(state,epsg,0,0,0); + //--- cycle + while(CMinLBFGS::MinLBFGSIteration(state)) + { + //--- check + if(state.m_needfg) + { + //--- check + if(-0.999999epsg; + } + } + } +//+------------------------------------------------------------------+ +//| Testing class CMLPBase è CMLPTrain | +//+------------------------------------------------------------------+ +class CTestMLPTrainUnit + { +private: + //--- private methods + static void CreateNetwork(CMultilayerPerceptron &network,const int nkind,const double a1,const double a2,const int nin,const int nhid1,const int nhid2,const int nout); + static void UnsetNetwork(CMultilayerPerceptron &network); + static void TestInformational(const int nkind,const int nin,const int nhid1,const int nhid2,const int nout,const int passcount,bool &err); + static void TestProcessing(const int nkind,const int nin,const int nhid1,const int nhid2,const int nout,const int passcount,bool &err); + static void TestGradient(const int nkind,const int nin,const int nhid1,const int nhid2,const int nout,const int passcount,bool &err); + static void TestHessian(const int nkind,const int nin,const int nhid1,const int nhid2,const int nout,const int passcount,bool &err); +public: + //--- constructor, destructor + CTestMLPTrainUnit(void); + ~CTestMLPTrainUnit(void); + //--- public method + static bool TestMLPTrain(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestMLPTrainUnit::CTestMLPTrainUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestMLPTrainUnit::~CTestMLPTrainUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CMLPBase è CMLPTrain | +//+------------------------------------------------------------------+ +static bool CTestMLPTrainUnit::TestMLPTrain(const bool silent) + { +//--- create variables + bool waserrors; + int passcount=0; + int maxn=0; + int maxhid=0; + int info=0; + int nf=0; + int nl=0; + int nhid1=0; + int nhid2=0; + int nkind=0; + int i=0; + int ncount=0; + bool inferrors; + bool procerrors; + bool graderrors; + bool hesserrors; + bool trnerrors; +//--- objects of classes êëàññîâ + CMultilayerPerceptron network; + CMultilayerPerceptron network2; + CMLPReport rep; + CMLPCVReport cvrep; + CMatrixDouble xy; + CMatrixDouble valxy; +//--- initialization + waserrors=false; + inferrors=false; + procerrors=false; + graderrors=false; + hesserrors=false; + trnerrors=false; + passcount=10; + maxn=4; + maxhid=4; +//--- General multilayer network tests + for(nf=1;nf<=maxn;nf++) + { + for(nl=1;nl<=maxn;nl++) + { + for(nhid1=0;nhid1<=maxhid;nhid1++) + { + for(nhid2=0;nhid2<=0;nhid2++) + { + for(nkind=0;nkind<=3;nkind++) + { + //--- Skip meaningless parameters combinations + if(nkind==1 && nl<2) + continue; + //--- check + if(nhid1==0 && nhid2!=0) + continue; + //--- Tests + TestInformational(nkind,nf,nhid1,nhid2,nl,passcount,inferrors); + TestProcessing(nkind,nf,nhid1,nhid2,nl,passcount,procerrors); + TestGradient(nkind,nf,nhid1,nhid2,nl,passcount,graderrors); + TestHessian(nkind,nf,nhid1,nhid2,nl,passcount,hesserrors); + } + } + } + } + } +//--- Test network training on simple XOR problem + xy.Resize(4,3); + xy[0].Set(0,-1); + xy[0].Set(1,-1); + xy[0].Set(2,-1); + xy[1].Set(0,1); + xy[1].Set(1,-1); + xy[1].Set(2,1); + xy[2].Set(0,-1); + xy[2].Set(1,1); + xy[2].Set(2,1); + xy[3].Set(0,1); + xy[3].Set(1,1); + xy[3].Set(2,-1); +//--- function calls + CMLPBase::MLPCreate1(2,2,1,network); + CMLPTrain::MLPTrainLM(network,xy,4,0.001,10,info,rep); +//--- search errors + trnerrors=trnerrors || CMLPBase::MLPRMSError(network,xy,4)>0.1; +//--- Test CV on random noisy problem + ncount=100; + xy.Resize(ncount,2); +//--- change values + for(i=0;i<=ncount-1;i++) + { + xy[i].Set(0,2*CMath::RandomReal()-1); + xy[i].Set(1,CMath::RandomInteger(4)); + } +//--- function calls + CMLPBase::MLPCreateC0(1,4,network); + CMLPTrain::MLPKFoldCVLM(network,xy,ncount,0.001,5,10,info,rep,cvrep); +//--- Final report + waserrors=(((inferrors || procerrors) || graderrors) || hesserrors) || trnerrors; +//--- check + if(!silent) + { + Print("MLP TEST"); + Print("INFORMATIONAL FUNCTIONS: "); + //--- check + if(!inferrors) + Print("OK"); + else + Print("FAILED"); + Print("BASIC PROCESSING: "); + //--- check + if(!procerrors) + Print("OK"); + else + Print("FAILED"); + Print("GRADIENT CALCULATION: "); + //--- check + if(!graderrors) + Print("OK"); + else + Print("FAILED"); + Print("HESSIAN CALCULATION: "); + //--- check + if(!hesserrors) + Print("OK"); + else + Print("FAILED"); + Print("TRAINING: "); + //--- check + if(!trnerrors) + Print("OK"); + else + Print("FAILED"); + //--- check + if(waserrors) + Print("TEST SUMMARY: FAILED"); + else + Print("TEST SUMMARY: PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Network creation | +//| This function creates network with desired structure. Network is | +//| created using one of the three methods: | +//| a) straighforward 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 with probability 1/3. | +//+------------------------------------------------------------------+ +static void CTestMLPTrainUnit::CreateNetwork(CMultilayerPerceptron &network, + const int nkind,const double a1, + const double a2,const int nin, + const int nhid1,const int nhid2, + const int nout) + { +//--- create a variable + int mkind=0; +//--- object of class + CMultilayerPerceptron tmp; +//--- check + if(!CAp::Assert(((nin>0 && nhid1>=0) && nhid2>=0) && nout>0,"CreateNetwork error")) + return; +//--- check + if(!CAp::Assert(nhid1!=0 || nhid2==0,"CreateNetwork error")) + return; +//--- check + if(!CAp::Assert(nkind!=1 || nout>=2,"CreateNetwork error")) + return; +//--- change value + mkind=CMath::RandomInteger(3); +//--- check + if(nhid1==0) + { + //--- No hidden layers + if(nkind==0) + { + //--- check + if(mkind==0) + CMLPBase::MLPCreate0(nin,nout,network); + //--- check + if(mkind==1) + { + //--- function call + CMLPBase::MLPCreate0(nin,nout,tmp); + { + //--- This code passes data structure through serializers + //--- (serializes it to string and loads back) + CSerializer _local_serializer; + string _local_str; + //--- serialization + _local_serializer.Reset(); + _local_serializer.Alloc_Start(); + CMLPBase::MLPAlloc(_local_serializer,tmp); + _local_serializer.SStart_Str(); + CMLPBase::MLPSerialize(_local_serializer,tmp); + _local_serializer.Stop(); + _local_str=_local_serializer.Get_String(); + //--- unserialization + _local_serializer.Reset(); + _local_serializer.UStart_Str(_local_str); + CMLPBase::MLPUnserialize(_local_serializer,network); + _local_serializer.Stop(); + } + } + //--- check + if(mkind==2) + { + CMLPBase::MLPCreate0(nin,nout,tmp); + CMLPBase::MLPCopy(tmp,network); + } + } + else + { + //--- check + if(nkind==1) + { + //--- check + if(mkind==0) + CMLPBase::MLPCreateC0(nin,nout,network); + //--- check + if(mkind==1) + { + //--- function call + CMLPBase::MLPCreateC0(nin,nout,tmp); + { + //--- This code passes data structure through serializers + //--- (serializes it to string and loads back) + CSerializer _local_serializer; + string _local_str; + //--- serialization + _local_serializer.Reset(); + _local_serializer.Alloc_Start(); + CMLPBase::MLPAlloc(_local_serializer,tmp); + _local_serializer.SStart_Str(); + CMLPBase::MLPSerialize(_local_serializer,tmp); + _local_serializer.Stop(); + _local_str=_local_serializer.Get_String(); + //--- unserialization + _local_serializer.Reset(); + _local_serializer.UStart_Str(_local_str); + CMLPBase::MLPUnserialize(_local_serializer,network); + _local_serializer.Stop(); + } + } + //--- check + if(mkind==2) + { + CMLPBase::MLPCreateC0(nin,nout,tmp); + CMLPBase::MLPCopy(tmp,network); + } + } + else + { + //--- check + if(nkind==2) + { + //--- check + if(mkind==0) + CMLPBase::MLPCreateB0(nin,nout,a1,a2,network); + //--- check + if(mkind==1) + { + //--- function call + CMLPBase::MLPCreateB0(nin,nout,a1,a2,tmp); + { + //--- This code passes data structure through serializers + //--- (serializes it to string and loads back) + CSerializer _local_serializer; + string _local_str; + //--- serialization + _local_serializer.Reset(); + _local_serializer.Alloc_Start(); + CMLPBase::MLPAlloc(_local_serializer,tmp); + _local_serializer.SStart_Str(); + CMLPBase::MLPSerialize(_local_serializer,tmp); + _local_serializer.Stop(); + _local_str=_local_serializer.Get_String(); + //--- unserialization + _local_serializer.Reset(); + _local_serializer.UStart_Str(_local_str); + CMLPBase::MLPUnserialize(_local_serializer,network); + _local_serializer.Stop(); + } + } + //--- check + if(mkind==2) + { + CMLPBase::MLPCreateB0(nin,nout,a1,a2,tmp); + CMLPBase::MLPCopy(tmp,network); + } + } + else + { + //--- check + if(nkind==3) + { + //--- check + if(mkind==0) + CMLPBase::MLPCreateR0(nin,nout,a1,a2,network); + //--- check + if(mkind==1) + { + //--- function call + CMLPBase::MLPCreateR0(nin,nout,a1,a2,tmp); + { + //--- This code passes data structure through serializers + //--- (serializes it to string and loads back) + CSerializer _local_serializer; + string _local_str; + //--- serialization + _local_serializer.Reset(); + _local_serializer.Alloc_Start(); + CMLPBase::MLPAlloc(_local_serializer,tmp); + _local_serializer.SStart_Str(); + CMLPBase::MLPSerialize(_local_serializer,tmp); + _local_serializer.Stop(); + _local_str=_local_serializer.Get_String(); + //--- unserialization + _local_serializer.Reset(); + _local_serializer.UStart_Str(_local_str); + CMLPBase::MLPUnserialize(_local_serializer,network); + _local_serializer.Stop(); + } + } + //--- check + if(mkind==2) + { + CMLPBase::MLPCreateR0(nin,nout,a1,a2,tmp); + CMLPBase::MLPCopy(tmp,network); + } + } + } + } + } + //--- function call + CMLPBase::MLPRandomizeFull(network); + return; + } +//--- check + if(nhid2==0) + { + //--- One hidden layer + if(nkind==0) + { + //--- check + if(mkind==0) + CMLPBase::MLPCreate1(nin,nhid1,nout,network); + //--- check + if(mkind==1) + { + //--- function call + CMLPBase::MLPCreate1(nin,nhid1,nout,tmp); + { + //--- This code passes data structure through serializers + //--- (serializes it to string and loads back) + CSerializer _local_serializer; + string _local_str; + //--- serialization + _local_serializer.Reset(); + _local_serializer.Alloc_Start(); + CMLPBase::MLPAlloc(_local_serializer,tmp); + _local_serializer.SStart_Str(); + CMLPBase::MLPSerialize(_local_serializer,tmp); + _local_serializer.Stop(); + _local_str=_local_serializer.Get_String(); + //--- unserialization + _local_serializer.Reset(); + _local_serializer.UStart_Str(_local_str); + CMLPBase::MLPUnserialize(_local_serializer,network); + _local_serializer.Stop(); + } + } + //--- check + if(mkind==2) + { + CMLPBase::MLPCreate1(nin,nhid1,nout,tmp); + CMLPBase::MLPCopy(tmp,network); + } + } + else + { + //--- check + if(nkind==1) + { + //--- check + if(mkind==0) + CMLPBase::MLPCreateC1(nin,nhid1,nout,network); + //--- check + if(mkind==1) + { + //--- function call + CMLPBase::MLPCreateC1(nin,nhid1,nout,tmp); + { + //--- This code passes data structure through serializers + //--- (serializes it to string and loads back) + CSerializer _local_serializer; + string _local_str; + //--- serialization + _local_serializer.Reset(); + _local_serializer.Alloc_Start(); + CMLPBase::MLPAlloc(_local_serializer,tmp); + _local_serializer.SStart_Str(); + CMLPBase::MLPSerialize(_local_serializer,tmp); + _local_serializer.Stop(); + _local_str=_local_serializer.Get_String(); + //--- unserialization + _local_serializer.Reset(); + _local_serializer.UStart_Str(_local_str); + CMLPBase::MLPUnserialize(_local_serializer,network); + _local_serializer.Stop(); + } + } + //--- check + if(mkind==2) + { + CMLPBase::MLPCreateC1(nin,nhid1,nout,tmp); + CMLPBase::MLPCopy(tmp,network); + } + } + else + { + //--- check + if(nkind==2) + { + //--- check + if(mkind==0) + CMLPBase::MLPCreateB1(nin,nhid1,nout,a1,a2,network); + //--- check + if(mkind==1) + { + //--- function call + CMLPBase::MLPCreateB1(nin,nhid1,nout,a1,a2,tmp); + { + //--- This code passes data structure through serializers + //--- (serializes it to string and loads back) + CSerializer _local_serializer; + string _local_str; + //--- serialization + _local_serializer.Reset(); + _local_serializer.Alloc_Start(); + CMLPBase::MLPAlloc(_local_serializer,tmp); + _local_serializer.SStart_Str(); + CMLPBase::MLPSerialize(_local_serializer,tmp); + _local_serializer.Stop(); + _local_str=_local_serializer.Get_String(); + //--- unserialization + _local_serializer.Reset(); + _local_serializer.UStart_Str(_local_str); + CMLPBase::MLPUnserialize(_local_serializer,network); + _local_serializer.Stop(); + } + } + //--- check + if(mkind==2) + { + CMLPBase::MLPCreateB1(nin,nhid1,nout,a1,a2,tmp); + CMLPBase::MLPCopy(tmp,network); + } + } + else + { + //--- check + if(nkind==3) + { + //--- check + if(mkind==0) + CMLPBase::MLPCreateR1(nin,nhid1,nout,a1,a2,network); + //--- check + if(mkind==1) + { + //--- function call + CMLPBase::MLPCreateR1(nin,nhid1,nout,a1,a2,tmp); + { + //--- This code passes data structure through serializers + //--- (serializes it to string and loads back) + CSerializer _local_serializer; + string _local_str; + //--- serialization + _local_serializer.Reset(); + _local_serializer.Alloc_Start(); + CMLPBase::MLPAlloc(_local_serializer,tmp); + _local_serializer.SStart_Str(); + CMLPBase::MLPSerialize(_local_serializer,tmp); + _local_serializer.Stop(); + _local_str=_local_serializer.Get_String(); + //--- unserialization + _local_serializer.Reset(); + _local_serializer.UStart_Str(_local_str); + CMLPBase::MLPUnserialize(_local_serializer,network); + _local_serializer.Stop(); + } + } + //--- check + if(mkind==2) + { + CMLPBase::MLPCreateR1(nin,nhid1,nout,a1,a2,tmp); + CMLPBase::MLPCopy(tmp,network); + } + } + } + } + } + //--- function call + CMLPBase::MLPRandomizeFull(network); + return; + } +//--- Two hidden layers + if(nkind==0) + { + //--- check + if(mkind==0) + CMLPBase::MLPCreate2(nin,nhid1,nhid2,nout,network); + //--- check + if(mkind==1) + { + //--- function call + CMLPBase::MLPCreate2(nin,nhid1,nhid2,nout,tmp); + { + //--- This code passes data structure through serializers + //--- (serializes it to string and loads back) + CSerializer _local_serializer; + string _local_str; + //--- serialization + _local_serializer.Reset(); + _local_serializer.Alloc_Start(); + CMLPBase::MLPAlloc(_local_serializer,tmp); + _local_serializer.SStart_Str(); + CMLPBase::MLPSerialize(_local_serializer,tmp); + _local_serializer.Stop(); + _local_str=_local_serializer.Get_String(); + //--- unserialization + _local_serializer.Reset(); + _local_serializer.UStart_Str(_local_str); + CMLPBase::MLPUnserialize(_local_serializer,network); + _local_serializer.Stop(); + } + } + //--- check + if(mkind==2) + { + CMLPBase::MLPCreate2(nin,nhid1,nhid2,nout,tmp); + CMLPBase::MLPCopy(tmp,network); + } + } + else + { + //--- check + if(nkind==1) + { + //--- check + if(mkind==0) + CMLPBase::MLPCreateC2(nin,nhid1,nhid2,nout,network); + //--- check + if(mkind==1) + { + //--- function call + CMLPBase::MLPCreateC2(nin,nhid1,nhid2,nout,tmp); + { + //--- This code passes data structure through serializers + //--- (serializes it to string and loads back) + CSerializer _local_serializer; + string _local_str; + //--- serialization + _local_serializer.Reset(); + _local_serializer.Alloc_Start(); + CMLPBase::MLPAlloc(_local_serializer,tmp); + _local_serializer.SStart_Str(); + CMLPBase::MLPSerialize(_local_serializer,tmp); + _local_serializer.Stop(); + _local_str=_local_serializer.Get_String(); + //--- unserialization + _local_serializer.Reset(); + _local_serializer.UStart_Str(_local_str); + CMLPBase::MLPUnserialize(_local_serializer,network); + _local_serializer.Stop(); + } + } + //--- check + if(mkind==2) + { + CMLPBase::MLPCreateC2(nin,nhid1,nhid2,nout,tmp); + CMLPBase::MLPCopy(tmp,network); + } + } + else + { + //--- check + if(nkind==2) + { + //--- check + if(mkind==0) + CMLPBase::MLPCreateB2(nin,nhid1,nhid2,nout,a1,a2,network); + //--- check + if(mkind==1) + { + //--- function call + CMLPBase::MLPCreateB2(nin,nhid1,nhid2,nout,a1,a2,tmp); + { + //--- This code passes data structure through serializers + //--- (serializes it to string and loads back) + CSerializer _local_serializer; + string _local_str; + //--- serialization + _local_serializer.Reset(); + _local_serializer.Alloc_Start(); + CMLPBase::MLPAlloc(_local_serializer,tmp); + _local_serializer.SStart_Str(); + CMLPBase::MLPSerialize(_local_serializer,tmp); + _local_serializer.Stop(); + _local_str=_local_serializer.Get_String(); + //--- unserialization + _local_serializer.Reset(); + _local_serializer.UStart_Str(_local_str); + CMLPBase::MLPUnserialize(_local_serializer,network); + _local_serializer.Stop(); + } + } + //--- check + if(mkind==2) + { + CMLPBase::MLPCreateB2(nin,nhid1,nhid2,nout,a1,a2,tmp); + CMLPBase::MLPCopy(tmp,network); + } + } + else + { + //--- check + if(nkind==3) + { + //--- check + if(mkind==0) + CMLPBase::MLPCreateR2(nin,nhid1,nhid2,nout,a1,a2,network); + //--- check + if(mkind==1) + { + //--- function call + CMLPBase::MLPCreateR2(nin,nhid1,nhid2,nout,a1,a2,tmp); + { + //--- This code passes data structure through serializers + //--- (serializes it to string and loads back) + CSerializer _local_serializer; + string _local_str; + //--- serialization + _local_serializer.Reset(); + _local_serializer.Alloc_Start(); + CMLPBase::MLPAlloc(_local_serializer,tmp); + _local_serializer.SStart_Str(); + CMLPBase::MLPSerialize(_local_serializer,tmp); + _local_serializer.Stop(); + _local_str=_local_serializer.Get_String(); + //--- unserialization + _local_serializer.Reset(); + _local_serializer.UStart_Str(_local_str); + CMLPBase::MLPUnserialize(_local_serializer,network); + _local_serializer.Stop(); + } + } + //--- check + if(mkind==2) + { + CMLPBase::MLPCreateR2(nin,nhid1,nhid2,nout,a1,a2,tmp); + CMLPBase::MLPCopy(tmp,network); + } + } + } + } + } +//--- function call + CMLPBase::MLPRandomizeFull(network); + } +//+------------------------------------------------------------------+ +//| Unsets network (initialize it to smallest network possible | +//+------------------------------------------------------------------+ +static void CTestMLPTrainUnit::UnsetNetwork(CMultilayerPerceptron &network) + { +//--- function call + CMLPBase::MLPCreate0(1,1,network); + } +//+------------------------------------------------------------------+ +//| Informational functions test | +//+------------------------------------------------------------------+ +static void CTestMLPTrainUnit::TestInformational(const int nkind,const int nin, + const int nhid1,const int nhid2, + const int nout,const int passcount, + bool &err) + { +//--- create variables + int n1=0; + int n2=0; + int wcount=0; + int i=0; + int j=0; + int k=0; + double threshold=0; + int nlayers=0; + int nmax=0; + bool issoftmax; + double mean=0; + double sigma=0; + int fkind=0; + double c=0; + double f=0; + double df=0; + double d2f=0; + double s=0; +//--- create arrays + double x[]; + double y[]; +//--- create matrix + CMatrixDouble neurons; +//--- object of class + CMultilayerPerceptron network; +//--- initialization + threshold=100000*CMath::m_machineepsilon; +//--- function call + CreateNetwork(network,nkind,0.0,0.0,nin,nhid1,nhid2,nout); +//--- test MLPProperties() + CMLPBase::MLPProperties(network,n1,n2,wcount); +//--- search errors + err=((err || n1!=nin) || n2!=nout) || wcount<=0; +//--- 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=MathMax(nin,nout); + issoftmax=nkind==1; +//--- check + if(nhid1!=0) + { + nlayers=3; + nmax=MathMax(nmax,nhid1); + } +//--- check + if(nhid2!=0) + { + nlayers=4; + nmax=MathMax(nmax,nhid2); + } +//--- allocation + neurons.Resize(nlayers,nmax); + for(i=0;i<=nlayers-1;i++) + { + for(j=0;j<=nmax-1;j++) + neurons[i].Set(j,0); + } +//--- allocation + ArrayResize(x,nin); +//--- change values + for(i=0;i<=nin-1;i++) + x[i]=2*CMath::RandomReal()-1; +//--- allocation + ArrayResize(y,nout); +//--- change values + for(i=0;i<=nout-1;i++) + y[i]=2*CMath::RandomReal()-1; + for(j=0;j<=nin-1;j++) + { + //--- function call + CMLPBase::MLPGetInputScaling(network,j,mean,sigma); + neurons[0].Set(j,(x[j]-mean)/sigma); + } +//--- calculation + for(i=1;i<=nlayers-1;i++) + { + for(j=0;j<=CMLPBase::MLPGetLayerSize(network,i)-1;j++) + { + for(k=0;k<=CMLPBase::MLPGetLayerSize(network,i-1)-1;k++) + neurons[i].Set(j,neurons[i][j]+CMLPBase::MLPGetWeight(network,i-1,k,i,j)*neurons[i-1][k]); + //--- function calls + CMLPBase::MLPGetNeuronInfo(network,i,j,fkind,c); + CMLPBase::MLPActivationFunction(neurons[i][j]-c,fkind,f,df,d2f); + neurons[i].Set(j,f); + } + } +//--- check + if(nkind==1) + { + s=0; + for(j=0;j<=nout-1;j++) + s=s+MathExp(neurons[nlayers-1][j]); + for(j=0;j<=nout-1;j++) + neurons[nlayers-1].Set(j,MathExp(neurons[nlayers-1][j])/s); + } +//--- calculation + for(j=0;j<=nout-1;j++) + { + //--- function call + CMLPBase::MLPGetOutputScaling(network,j,mean,sigma); + neurons[nlayers-1].Set(j,neurons[nlayers-1][j]*sigma+mean); + } +//--- function call + CMLPBase::MLPProcess(network,x,y); +//--- search errors + for(j=0;j<=nout-1;j++) + err=err || MathAbs(neurons[nlayers-1][j]-y[j])>threshold; + } +//+------------------------------------------------------------------+ +//| Processing functions test | +//+------------------------------------------------------------------+ +static void CTestMLPTrainUnit::TestProcessing(const int nkind,const int nin, + const int nhid1,const int nhid2, + const int nout,const int passcount, + bool &err) + { +//--- create variables + int n1=0; + int n2=0; + int wcount=0; + bool zeronet; + double a1=0; + double a2=0; + int pass=0; + int i=0; + bool allsame; + double v=0; + int i_=0; +//--- create arrays + double x1[]; + double x2[]; + double y1[]; + double y2[]; +//--- objects of classes + CMultilayerPerceptron network; + CMultilayerPerceptron network2; +//--- check + if(!CAp::Assert(passcount>=2,"PassCount<2!")) + return; +//--- Prepare network + a1=0; + a2=0; +//--- check + if(nkind==2) + { + a1=1000*CMath::RandomReal()-500; + a2=2*CMath::RandomReal()-1; + } +//--- check + if(nkind==3) + { + a1=1000*CMath::RandomReal()-500; + a2=a1+(2*CMath::RandomInteger(2)-1)*(0.1+0.9*CMath::RandomReal()); + } +//--- function calls + CreateNetwork(network,nkind,a1,a2,nin,nhid1,nhid2,nout); + CMLPBase::MLPProperties(network,n1,n2,wcount); +//--- Initialize arrays + ArrayResize(x1,nin); + ArrayResize(x2,nin); + ArrayResize(y1,nout); + ArrayResize(y2,nout); +//--- Main cycle + for(pass=1;pass<=passcount;pass++) + { + //--- Last run is made on zero network + CMLPBase::MLPRandomizeFull(network); + zeronet=false; + //--- check + if(pass==passcount) + { + for(i_=0;i_<=wcount-1;i_++) + network.m_weights[i_]=0*network.m_weights[i_]; + zeronet=true; + } + //--- Same inputs leads to same outputs + for(i=0;i<=nin-1;i++) + { + x1[i]=2*CMath::RandomReal()-1; + x2[i]=x1[i]; + } + for(i=0;i<=nout-1;i++) + { + y1[i]=2*CMath::RandomReal()-1; + y2[i]=2*CMath::RandomReal()-1; + } + //--- function calls + CMLPBase::MLPProcess(network,x1,y1); + CMLPBase::MLPProcess(network,x2,y2); + //--- search errors + allsame=true; + for(i=0;i<=nout-1;i++) + allsame=allsame && y1[i]==y2[i]; + err=err || !allsame; + //--- Same inputs on original network leads to same outputs + //--- on copy created using MLPCopy + UnsetNetwork(network2); + CMLPBase::MLPCopy(network,network2); + //--- change values + for(i=0;i<=nin-1;i++) + { + x1[i]=2*CMath::RandomReal()-1; + x2[i]=x1[i]; + } + for(i=0;i<=nout-1;i++) + { + y1[i]=2*CMath::RandomReal()-1; + y2[i]=2*CMath::RandomReal()-1; + } + //--- function calls + CMLPBase::MLPProcess(network,x1,y1); + CMLPBase::MLPProcess(network2,x2,y2); + //--- search errors + allsame=true; + for(i=0;i<=nout-1;i++) + allsame=allsame && y1[i]==y2[i]; + err=err || !allsame; + //--- Same inputs on original network leads to same outputs + //--- on copy created using MLPSerialize + UnsetNetwork(network2); + //--- This code passes data structure through serializers + //--- (serializes it to string and loads back) + CSerializer _local_serializer; + string _local_str; + //--- serialization + _local_serializer.Reset(); + _local_serializer.Alloc_Start(); + CMLPBase::MLPAlloc(_local_serializer,network); + _local_serializer.SStart_Str(); + CMLPBase::MLPSerialize(_local_serializer,network); + _local_serializer.Stop(); + _local_str=_local_serializer.Get_String(); + //--- unserialization + _local_serializer.Reset(); + _local_serializer.UStart_Str(_local_str); + CMLPBase::MLPUnserialize(_local_serializer,network2); + _local_serializer.Stop(); + //--- change values + for(i=0;i<=nin-1;i++) + { + x1[i]=2*CMath::RandomReal()-1; + x2[i]=x1[i]; + } + for(i=0;i<=nout-1;i++) + { + y1[i]=2*CMath::RandomReal()-1; + y2[i]=2*CMath::RandomReal()-1; + } + //--- function calls + CMLPBase::MLPProcess(network,x1,y1); + CMLPBase::MLPProcess(network2,x2,y2); + //--- search errors + allsame=true; + for(i=0;i<=nout-1;i++) + allsame=allsame && y1[i]==y2[i]; + err=err || !allsame; + //--- Different inputs leads to different outputs (non-zero network) + if(!zeronet) + { + for(i=0;i<=nin-1;i++) + { + x1[i]=2*CMath::RandomReal()-1; + x2[i]=2*CMath::RandomReal()-1; + } + for(i=0;i<=nout-1;i++) + { + y1[i]=2*CMath::RandomReal()-1; + y2[i]=y1[i]; + } + //--- function calls + CMLPBase::MLPProcess(network,x1,y1); + CMLPBase::MLPProcess(network,x2,y2); + //--- search errors + allsame=true; + for(i=0;i<=nout-1;i++) + allsame=allsame && y1[i]==y2[i]; + err=err || allsame; + } + //--- Randomization changes outputs (when inputs are unchanged,non-zero network) + if(!zeronet) + { + for(i=0;i<=nin-1;i++) + { + x1[i]=2*CMath::RandomReal()-1; + x2[i]=2*CMath::RandomReal()-1; + } + for(i=0;i<=nout-1;i++) + { + y1[i]=2*CMath::RandomReal()-1; + y2[i]=y1[i]; + } + //--- function calls + CMLPBase::MLPCopy(network,network2); + CMLPBase::MLPRandomize(network2); + CMLPBase::MLPProcess(network,x1,y1); + CMLPBase::MLPProcess(network2,x1,y2); + //--- search errors + allsame=true; + for(i=0;i<=nout-1;i++) + allsame=allsame && y1[i]==y2[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[i]=2*CMath::RandomReal()-1; + x2[i]=2*CMath::RandomReal()-1; + } + for(i=0;i<=nout-1;i++) + { + y1[i]=2*CMath::RandomReal()-1; + y2[i]=y1[i]; + } + //--- function calls + CMLPBase::MLPCopy(network,network2); + CMLPBase::MLPRandomizeFull(network2); + CMLPBase::MLPProcess(network,x1,y1); + CMLPBase::MLPProcess(network2,x1,y2); + //--- search errors + allsame=true; + for(i=0;i<=nout-1;i++) + allsame=allsame && y1[i]==y2[i]; + err=err || allsame; + } + //--- Normalization properties + if(nkind==1) + { + //--- Classifier network outputs are normalized + for(i=0;i<=nin-1;i++) + x1[i]=2*CMath::RandomReal()-1; + //--- function call + CMLPBase::MLPProcess(network,x1,y1); + v=0; + for(i=0;i<=nout-1;i++) + { + v=v+y1[i]; + //--- search errors + err=err || y1[i]<0.0; + } + //--- search errors + err=err || MathAbs(v-1)>1000*CMath::m_machineepsilon; + } + //--- check + if(nkind==2) + { + //--- B-type network outputs are bounded from above/below + for(i=0;i<=nin-1;i++) + x1[i]=2*CMath::RandomReal()-1; + //--- function call + CMLPBase::MLPProcess(network,x1,y1); + for(i=0;i<=nout-1;i++) + { + //--- check + if(a2>=0.0) + err=err || y1[i]a1; + } + } + //--- check + if(nkind==3) + { + //--- R-type network outputs are within [A1,A2] (or [A2,A1]) + for(i=0;i<=nin-1;i++) + x1[i]=2*CMath::RandomReal()-1; + //--- function call + CMLPBase::MLPProcess(network,x1,y1); + //--- search errors + for(i=0;i<=nout-1;i++) + err=(err || y1[i]MathMax(a1,a2); + } + } + } +//+------------------------------------------------------------------+ +//| Gradient functions test | +//+------------------------------------------------------------------+ +static void CTestMLPTrainUnit::TestGradient(const int nkind,const int nin, + const int nhid1,const int nhid2, + const int nout,const int passcount, + bool &err) + { +//--- create variables + int n1=0; + int n2=0; + int wcount=0; + double h=0; + double etol=0; + double a1=0; + double a2=0; + int pass=0; + int i=0; + int j=0; + int ssize=0; + double v=0; + double e=0; + double e1=0; + double e2=0; + double v1=0; + double v2=0; + double v3=0; + double v4=0; + double wprev=0; + int i_=0; + int i1_=0; +//--- create arrays + double grad1[]; + double grad2[]; + double x[]; + double y[]; + double x1[]; + double x2[]; + double y1[]; + double y2[]; +//--- create matrix + CMatrixDouble xy; +//--- object of class + CMultilayerPerceptron network; +//--- check + if(!CAp::Assert(passcount>=2,"PassCount<2!")) + return; +//--- change values + a1=0; + a2=0; +//--- check + if(nkind==2) + { + a1=1000*CMath::RandomReal()-500; + a2=2*CMath::RandomReal()-1; + } +//--- check + if(nkind==3) + { + a1=1000*CMath::RandomReal()-500; + a2=a1+(2*CMath::RandomInteger(2)-1)*(0.1+0.9*CMath::RandomReal()); + } +//--- function calls + CreateNetwork(network,nkind,a1,a2,nin,nhid1,nhid2,nout); + CMLPBase::MLPProperties(network,n1,n2,wcount); +//--- change values + h=0.0001; + etol=0.01; +//--- Initialize + ArrayResize(x,nin); + ArrayResize(x1,nin); + ArrayResize(x2,nin); + ArrayResize(y,nout); + ArrayResize(y1,nout); + ArrayResize(y2,nout); + ArrayResize(grad1,wcount); + ArrayResize(grad2,wcount); +//--- Process + for(pass=1;pass<=passcount;pass++) + { + //--- function call + CMLPBase::MLPRandomizeFull(network); + //--- Test error/gradient calculation (least squares) + xy.Resize(1,nin+nout); + for(i=0;i<=nin-1;i++) + x[i]=4*CMath::RandomReal()-2; + for(i_=0;i_<=nin-1;i_++) + xy[0].Set(i_,x[i_]); + //--- check + if(CMLPBase::MLPIsSoftMax(network)) + { + for(i=0;i<=nout-1;i++) + y[i]=0; + xy[0].Set(nin,CMath::RandomInteger(nout)); + y[(int)MathRound(xy[0][nin])]=1; + } + else + { + for(i=0;i<=nout-1;i++) + y[i]=4*CMath::RandomReal()-2; + i1_=-nin; + for(i_=nin;i_<=nin+nout-1;i_++) + xy[0].Set(i_,y[i_+i1_]); + } + //--- function calls + CMLPBase::MLPGrad(network,x,y,e,grad2); + CMLPBase::MLPProcess(network,x,y2); + for(i_=0;i_<=nout-1;i_++) + y2[i_]=y2[i_]-y[i_]; + //--- change value + v=0.0; + for(i_=0;i_<=nout-1;i_++) + v+=y2[i_]*y2[i_]; + v=v/2; + //--- search errors + err=err || MathAbs((v-e)/v)>etol; + err=err || MathAbs((CMLPBase::MLPError(network,xy,1)-v)/v)>etol; + for(i=0;i<=wcount-1;i++) + { + wprev=network.m_weights[i]; + network.m_weights[i]=wprev-2*h; + //--- function call + CMLPBase::MLPProcess(network,x,y1); + for(i_=0;i_<=nout-1;i_++) + y1[i_]=y1[i_]-y[i_]; + //--- change value + v1=0.0; + for(i_=0;i_<=nout-1;i_++) + v1+=y1[i_]*y1[i_]; + v1=v1/2; + network.m_weights[i]=wprev-h; + //--- function call + CMLPBase::MLPProcess(network,x,y1); + for(i_=0;i_<=nout-1;i_++) + y1[i_]=y1[i_]-y[i_]; + //--- change value + v2=0.0; + for(i_=0;i_<=nout-1;i_++) + v2+=y1[i_]*y1[i_]; + v2=v2/2; + network.m_weights[i]=wprev+h; + //--- function call + CMLPBase::MLPProcess(network,x,y1); + for(i_=0;i_<=nout-1;i_++) + y1[i_]=y1[i_]-y[i_]; + //--- change value + v3=0.0; + for(i_=0;i_<=nout-1;i_++) + v3+=y1[i_]*y1[i_]; + v3=v3/2; + network.m_weights[i]=wprev+2*h; + //--- function call + CMLPBase::MLPProcess(network,x,y1); + for(i_=0;i_<=nout-1;i_++) + y1[i_]=y1[i_]-y[i_]; + //--- change value + v4=0.0; + for(i_=0;i_<=nout-1;i_++) + v4+=y1[i_]*y1[i_]; + v4=v4/2; + network.m_weights[i]=wprev; + grad1[i]=(v1-8*v2+8*v3-v4)/(12*h); + //--- check + if(MathAbs(grad1[i])>1.0E-3) + err=err || MathAbs((grad2[i]-grad1[i])/grad1[i])>etol; + else + err=err || MathAbs(grad2[i]-grad1[i])>etol; + } + //--- Test error/gradient calculation (natural). + //--- Testing on non-random structure networks + //--- (because NKind is representative only in that case). + xy.Resize(1,nin+nout); + for(i=0;i<=nin-1;i++) + x[i]=4*CMath::RandomReal()-2; + for(i_=0;i_<=nin-1;i_++) + xy[0].Set(i_,x[i_]); + //--- check + if(CMLPBase::MLPIsSoftMax(network)) + { + for(i=0;i<=nout-1;i++) + y[i]=0; + xy[0].Set(nin,CMath::RandomInteger(nout)); + y[(int)MathRound(xy[0][nin])]=1; + } + else + { + for(i=0;i<=nout-1;i++) + y[i]=4*CMath::RandomReal()-2; + i1_=-nin; + for(i_=nin;i_<=nin+nout-1;i_++) + xy[0].Set(i_,y[i_+i1_]); + } + //--- function calls + CMLPBase::MLPGradN(network,x,y,e,grad2); + CMLPBase::MLPProcess(network,x,y2); + v=0; + //--- check + if(nkind!=1) + { + for(i=0;i<=nout-1;i++) + v=v+0.5*CMath::Sqr(y2[i]-y[i]); + } + else + { + for(i=0;i<=nout-1;i++) + { + //--- check + if(y[i]!=0.0) + { + //--- check + if(y2[i]==0.0) + v=v+y[i]*MathLog(CMath::m_maxrealnumber); + else + v=v+y[i]*MathLog(y[i]/y2[i]); + } + } + } + //--- search errors + err=err || MathAbs((v-e)/v)>etol; + err=err || MathAbs((CMLPBase::MLPErrorN(network,xy,1)-v)/v)>etol; + for(i=0;i<=wcount-1;i++) + { + wprev=network.m_weights[i]; + network.m_weights[i]=wprev+h; + //--- function call + CMLPBase::MLPProcess(network,x,y2); + network.m_weights[i]=wprev-h; + //--- function call + CMLPBase::MLPProcess(network,x,y1); + network.m_weights[i]=wprev; + v=0; + //--- check + if(nkind!=1) + { + for(j=0;j<=nout-1;j++) + v=v+0.5*(CMath::Sqr(y2[j]-y[j])-CMath::Sqr(y1[j]-y[j]))/(2*h); + } + else + { + for(j=0;j<=nout-1;j++) + { + //--- check + if(y[j]!=0.0) + { + //--- check + if(y2[j]==0.0) + v=v+y[j]*MathLog(CMath::m_maxrealnumber); + else + v=v+y[j]*MathLog(y[j]/y2[j]); + //--- check + if(y1[j]==0.0) + v=v-y[j]*MathLog(CMath::m_maxrealnumber); + else + v=v-y[j]*MathLog(y[j]/y1[j]); + } + } + v=v/(2*h); + } + grad1[i]=v; + //--- check + if(MathAbs(grad1[i])>1.0E-3) + err=err || MathAbs((grad2[i]-grad1[i])/grad1[i])>etol; + else + err=err || MathAbs(grad2[i]-grad1[i])>etol; + } + //--- Test gradient calculation: batch (least squares) + ssize=1+CMath::RandomInteger(10); + xy.Resize(ssize,nin+nout); + for(i=0;i<=wcount-1;i++) + grad1[i]=0; + //--- calculation + e1=0; + for(i=0;i<=ssize-1;i++) + { + for(j=0;j<=nin-1;j++) + x1[j]=4*CMath::RandomReal()-2; + for(i_=0;i_<=nin-1;i_++) + xy[i].Set(i_,x1[i_]); + //--- check + if(CMLPBase::MLPIsSoftMax(network)) + { + for(j=0;j<=nout-1;j++) + y1[j]=0; + //--- change values + xy[i].Set(nin,CMath::RandomInteger(nout)); + y1[(int)MathRound(xy[i][nin])]=1; + } + else + { + //--- change values + for(j=0;j<=nout-1;j++) + y1[j]=4*CMath::RandomReal()-2; + i1_=-nin; + for(i_=nin;i_<=nin+nout-1;i_++) + xy[i].Set(i_,y1[i_+i1_]); + } + //--- function call + CMLPBase::MLPGrad(network,x1,y1,v,grad2); + //--- change values + e1=e1+v; + for(i_=0;i_<=wcount-1;i_++) + grad1[i_]=grad1[i_]+grad2[i_]; + } + //--- function call + CMLPBase::MLPGradBatch(network,xy,ssize,e2,grad2); + //--- search errors + err=err || MathAbs(e1-e2)/e1>0.01; + for(i=0;i<=wcount-1;i++) + { + //--- check + if(grad1[i]!=0.0) + err=err || MathAbs((grad2[i]-grad1[i])/grad1[i])>etol; + else + err=err || grad2[i]!=grad1[i]; + } + //--- Test gradient calculation: batch (natural error func) + ssize=1+CMath::RandomInteger(10); + xy.Resize(ssize,nin+nout); + for(i=0;i<=wcount-1;i++) + grad1[i]=0; + //--- calculation + e1=0; + for(i=0;i<=ssize-1;i++) + { + for(j=0;j<=nin-1;j++) + x1[j]=4*CMath::RandomReal()-2; + for(i_=0;i_<=nin-1;i_++) + xy[i].Set(i_,x1[i_]); + //--- check + if(CMLPBase::MLPIsSoftMax(network)) + { + for(j=0;j<=nout-1;j++) + y1[j]=0; + //--- change values + xy[i].Set(nin,CMath::RandomInteger(nout)); + y1[(int)MathRound(xy[i][nin])]=1; + } + else + { + //--- change values + for(j=0;j<=nout-1;j++) + y1[j]=4*CMath::RandomReal()-2; + i1_=-nin; + for(i_=nin;i_<=nin+nout-1;i_++) + xy[i].Set(i_,y1[i_+i1_]); + } + //--- function call + CMLPBase::MLPGradN(network,x1,y1,v,grad2); + //--- change values + e1=e1+v; + for(i_=0;i_<=wcount-1;i_++) + grad1[i_]=grad1[i_]+grad2[i_]; + } + //--- function call + CMLPBase::MLPGradNBatch(network,xy,ssize,e2,grad2); + //--- search errors + err=err || MathAbs(e1-e2)/e1>etol; + for(i=0;i<=wcount-1;i++) + { + //--- check + if(grad1[i]!=0.0) + err=err || MathAbs((grad2[i]-grad1[i])/grad1[i])>etol; + else + err=err || grad2[i]!=grad1[i]; + } + } + } +//+------------------------------------------------------------------+ +//| Hessian functions test | +//+------------------------------------------------------------------+ +static void CTestMLPTrainUnit::TestHessian(const int nkind,const int nin, + const int nhid1,const int nhid2, + const int nout,const int passcount, + bool &err) + { +//--- create variables + int hkind=0; + int n1=0; + int n2=0; + int wcount=0; + double h=0; + double etol=0; + int pass=0; + int i=0; + int j=0; + int ssize=0; + double a1=0; + double a2=0; + double v=0; + double e1=0; + double e2=0; + double wprev=0; + int i_=0; + int i1_=0; +//--- create arrays + double grad1[]; + double grad2[]; + double grad3[]; + double x[]; + double y[]; + double x1[]; + double x2[]; + double y1[]; + double y2[]; +//--- create matrix + CMatrixDouble xy; + CMatrixDouble h1; + CMatrixDouble h2; +//--- îáúåêò êëàññâ + CMultilayerPerceptron network; +//--- check + if(!CAp::Assert(passcount>=2,"PassCount<2!")) + return; +//--- change values + a1=0; + a2=0; +//--- check + if(nkind==2) + { + a1=1000*CMath::RandomReal()-500; + a2=2*CMath::RandomReal()-1; + } +//--- check + if(nkind==3) + { + a1=1000*CMath::RandomReal()-500; + a2=a1+(2*CMath::RandomInteger(2)-1)*(0.1+0.9*CMath::RandomReal()); + } +//--- function calls + CreateNetwork(network,nkind,a1,a2,nin,nhid1,nhid2,nout); + CMLPBase::MLPProperties(network,n1,n2,wcount); +//--- change values + h=0.0001; + etol=0.05; +//--- Initialize + ArrayResize(x,nin); + ArrayResize(x1,nin); + ArrayResize(x2,nin); + ArrayResize(y,nout); + ArrayResize(y1,nout); + ArrayResize(y2,nout); + ArrayResize(grad1,wcount); + ArrayResize(grad2,wcount); + ArrayResize(grad3,wcount); + h1.Resize(wcount,wcount); + h2.Resize(wcount,wcount); +//--- Process + for(pass=1;pass<=passcount;pass++) + { + //--- function call + CMLPBase::MLPRandomizeFull(network); + //--- 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+CMath::RandomInteger(10); + xy.Resize(ssize,nin+nout); + for(i=0;i<=wcount-1;i++) + grad1[i]=0; + //--- change values + for(i=0;i<=wcount-1;i++) + { + for(j=0;j<=wcount-1;j++) + h1[i].Set(j,0); + } + //--- calculation + e1=0; + for(i=0;i<=ssize-1;i++) + { + //--- X,Y + for(j=0;j<=nin-1;j++) + x1[j]=4*CMath::RandomReal()-2; + for(i_=0;i_<=nin-1;i_++) + xy[i].Set(i_,x1[i_]); + //--- check + if(CMLPBase::MLPIsSoftMax(network)) + { + for(j=0;j<=nout-1;j++) + y1[j]=0; + //--- change values + xy[i].Set(nin,CMath::RandomInteger(nout)); + y1[(int)MathRound(xy[i][nin])]=1; + } + else + { + //--- change values + for(j=0;j<=nout-1;j++) + y1[j]=4*CMath::RandomReal()-2; + i1_=-nin; + for(i_=nin;i_<=nin+nout-1;i_++) + xy[i].Set(i_,y1[i_+i1_]); + } + //--- E1,Grad1 + if(hkind==0) + CMLPBase::MLPGrad(network,x1,y1,v,grad2); + else + CMLPBase::MLPGradN(network,x1,y1,v,grad2); + //--- change values + e1=e1+v; + for(i_=0;i_<=wcount-1;i_++) + grad1[i_]=grad1[i_]+grad2[i_]; + //--- H1 + for(j=0;j<=wcount-1;j++) + { + wprev=network.m_weights[j]; + network.m_weights[j]=wprev-2*h; + //--- check + if(hkind==0) + CMLPBase::MLPGrad(network,x1,y1,v,grad2); + else + CMLPBase::MLPGradN(network,x1,y1,v,grad2); + network.m_weights[j]=wprev-h; + //--- check + if(hkind==0) + CMLPBase::MLPGrad(network,x1,y1,v,grad3); + else + CMLPBase::MLPGradN(network,x1,y1,v,grad3); + //--- change values + for(i_=0;i_<=wcount-1;i_++) + grad2[i_]=grad2[i_]-8*grad3[i_]; + network.m_weights[j]=wprev+h; + //--- check + if(hkind==0) + CMLPBase::MLPGrad(network,x1,y1,v,grad3); + else + CMLPBase::MLPGradN(network,x1,y1,v,grad3); + //--- change values + for(i_=0;i_<=wcount-1;i_++) + grad2[i_]=grad2[i_]+8*grad3[i_]; + network.m_weights[j]=wprev+2*h; + //--- check + if(hkind==0) + CMLPBase::MLPGrad(network,x1,y1,v,grad3); + else + CMLPBase::MLPGradN(network,x1,y1,v,grad3); + //--- change values + for(i_=0;i_<=wcount-1;i_++) + grad2[i_]=grad2[i_]-grad3[i_]; + v=1/(12*h); + for(i_=0;i_<=wcount-1;i_++) + h1[j].Set(i_,h1[j][i_]+v*grad2[i_]); + network.m_weights[j]=wprev; + } + } + //--- check + if(hkind==0) + CMLPBase::MLPHessianBatch(network,xy,ssize,e2,grad2,h2); + else + CMLPBase::MLPHessianNBatch(network,xy,ssize,e2,grad2,h2); + //--- search errors + err=err || MathAbs(e1-e2)/e1>etol; + for(i=0;i<=wcount-1;i++) + { + //--- check + if(MathAbs(grad1[i])>1.0E-2) + err=err || MathAbs((grad2[i]-grad1[i])/grad1[i])>etol; + else + err=err || MathAbs(grad2[i]-grad1[i])>etol; + } + //--- search errors + for(i=0;i<=wcount-1;i++) + { + for(j=0;j<=wcount-1;j++) + { + //--- check + if(MathAbs(h1[i][j])>5.0E-2) + err=err || MathAbs((h1[i][j]-h2[i][j])/h1[i][j])>etol; + else + err=err || MathAbs(h2[i][j]-h1[i][j])>etol; + } + } + } + } + } +//+------------------------------------------------------------------+ +//| Testing class CMLPE | +//+------------------------------------------------------------------+ +class CTestMLPEUnit + { +private: + //--- private methods + static void CreateEnsemble(CMLPEnsemble &ensemble,const int nkind,const double a1,const double a2,const int nin,const int nhid1,const int nhid2,const int nout,const int ec); + static void UnsetEnsemble(CMLPEnsemble &ensemble); + static void TestInformational(const int nkind,const int nin,const int nhid1,const int nhid2,const int nout,const int ec,const int passcount,bool &err); + static void TestProcessing(const int nkind,const int nin,const int nhid1,const int nhid2,const int nout,const int ec,const int passcount,bool &err); +public: + //--- constructor, destructor + CTestMLPEUnit(void); + ~CTestMLPEUnit(void); + //--- public method + static bool TestMLPE(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestMLPEUnit::CTestMLPEUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestMLPEUnit::~CTestMLPEUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CMLPE | +//+------------------------------------------------------------------+ +static bool CTestMLPEUnit::TestMLPE(const bool silent) + { +//--- create variables + bool waserrors; + int passcount=0; + int maxn=0; + int maxhid=0; + int nf=0; + int nhid=0; + int nl=0; + int nhid1=0; + int nhid2=0; + int ec=0; + int nkind=0; + int algtype=0; + int tasktype=0; + int pass=0; + int i=0; + int j=0; + int nin=0; + int nout=0; + int npoints=0; + double e=0; + int info=0; + int nless=0; + int nall=0; + int nclasses=0; + bool inferrors; + bool procerrors; + bool trnerrors; +//--- create matrix + CMatrixDouble xy; +//--- objects of classes + CMLPEnsemble ensemble; + CMLPReport rep; + CMLPCVReport oobrep; +//--- initialization + waserrors=false; + inferrors=false; + procerrors=false; + trnerrors=false; + passcount=10; + maxn=4; + maxhid=4; +//--- General MLP ensembles tests + for(nf=1;nf<=maxn;nf++) + { + for(nl=1;nl<=maxn;nl++) + { + for(nhid1=0;nhid1<=maxhid;nhid1++) + { + for(nhid2=0;nhid2<=0;nhid2++) + { + for(nkind=0;nkind<=3;nkind++) + { + for(ec=1;ec<=3;ec++) + { + //--- Skip meaningless parameters combinations + if(nkind==1 && nl<2) + continue; + //--- check + if(nhid1==0 && nhid2!=0) + continue; + //--- Tests + TestInformational(nkind,nf,nhid1,nhid2,nl,ec,passcount,inferrors); + TestProcessing(nkind,nf,nhid1,nhid2,nl,ec,passcount,procerrors); + } + } + } + } + } + } +//--- network training must reduce error +//--- test on random regression task + nin=3; + nout=2; + nhid=5; + npoints=100; + nless=0; + nall=0; +//--- calculation + for(pass=1;pass<=10;pass++) + { + for(algtype=0;algtype<=1;algtype++) + { + for(tasktype=0;tasktype<=1;tasktype++) + { + //--- check + if(tasktype==0) + { + //--- allocation + xy.Resize(npoints,nin+nout); + //--- change values + for(i=0;i<=npoints-1;i++) + { + for(j=0;j<=nin+nout-1;j++) + xy[i].Set(j,2*CMath::RandomReal()-1); + } + //--- function call + CMLPE::MLPECreate1(nin,nhid,nout,1+CMath::RandomInteger(3),ensemble); + } + else + { + //--- allocation + xy.Resize(npoints,nin+1); + //--- change values + nclasses=2+CMath::RandomInteger(2); + for(i=0;i<=npoints-1;i++) + { + for(j=0;j<=nin-1;j++) + xy[i].Set(j,2*CMath::RandomReal()-1); + xy[i].Set(nin,CMath::RandomInteger(nclasses)); + } + //--- function call + CMLPE::MLPECreateC1(nin,nhid,nclasses,1+CMath::RandomInteger(3),ensemble); + } + e=CMLPE::MLPERMSError(ensemble,xy,npoints); + //--- check + if(algtype==0) + CMLPE::MLPEBaggingLM(ensemble,xy,npoints,0.001,1,info,rep,oobrep); + else + CMLPE::MLPEBaggingLBFGS(ensemble,xy,npoints,0.001,1,0.01,0,info,rep,oobrep); + //--- check + if(info<0) + trnerrors=true; + else + { + //--- check + if(CMLPE::MLPERMSError(ensemble,xy,npoints)0.3*nall; +//--- Final report + waserrors=(inferrors || procerrors) || trnerrors; +//--- check + if(!silent) + { + Print("MLP ENSEMBLE TEST"); + Print("INFORMATIONAL FUNCTIONS: "); + //--- check + if(!inferrors) + Print("OK"); + else + Print("FAILED"); + Print("BASIC PROCESSING: "); + //--- check + if(!procerrors) + Print("OK"); + else + Print("FAILED"); + Print("TRAINING: "); + //--- check + if(!trnerrors) + Print("OK"); + else + Print("FAILED"); + //--- check + if(waserrors) + Print("TEST SUMMARY: FAILED"); + else + Print("TEST SUMMARY: PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Network creation | +//+------------------------------------------------------------------+ +static void CTestMLPEUnit::CreateEnsemble(CMLPEnsemble &ensemble,const int nkind, + const double a1,const double a2, + const int nin,const int nhid1, + const int nhid2,const int nout, + const int ec) + { +//--- check + if(!CAp::Assert(((nin>0 && nhid1>=0) && nhid2>=0) && nout>0,"CreateNetwork error")) + return; +//--- check + if(!CAp::Assert(nhid1!=0 || nhid2==0,"CreateNetwork error")) + return; +//--- check + if(!CAp::Assert(nkind!=1 || nout>=2,"CreateNetwork error")) + return; +//--- check + if(nhid1==0) + { + //--- No hidden layers + if(nkind==0) + CMLPE::MLPECreate0(nin,nout,ec,ensemble); + else + { + //--- check + if(nkind==1) + CMLPE::MLPECreateC0(nin,nout,ec,ensemble); + else + { + //--- check + if(nkind==2) + CMLPE::MLPECreateB0(nin,nout,a1,a2,ec,ensemble); + else + { + //--- check + if(nkind==3) + CMLPE::MLPECreateR0(nin,nout,a1,a2,ec,ensemble); + } + } + } + //--- exit the function + return; + } +//--- check + if(nhid2==0) + { + //--- One hidden layer + if(nkind==0) + CMLPE::MLPECreate1(nin,nhid1,nout,ec,ensemble); + else + { + //--- check + if(nkind==1) + CMLPE::MLPECreateC1(nin,nhid1,nout,ec,ensemble); + else + { + //--- check + if(nkind==2) + CMLPE::MLPECreateB1(nin,nhid1,nout,a1,a2,ec,ensemble); + else + { + //--- check + if(nkind==3) + CMLPE::MLPECreateR1(nin,nhid1,nout,a1,a2,ec,ensemble); + } + } + } + //--- exit the function + return; + } +//--- Two hidden layers + if(nkind==0) + CMLPE::MLPECreate2(nin,nhid1,nhid2,nout,ec,ensemble); + else + { + //--- check + if(nkind==1) + CMLPE::MLPECreateC2(nin,nhid1,nhid2,nout,ec,ensemble); + else + { + //--- check + if(nkind==2) + CMLPE::MLPECreateB2(nin,nhid1,nhid2,nout,a1,a2,ec,ensemble); + else + { + //--- check + if(nkind==3) + CMLPE::MLPECreateR2(nin,nhid1,nhid2,nout,a1,a2,ec,ensemble); + } + } + } + } +//+------------------------------------------------------------------+ +//| Unsets network (initialize it to smallest network possible | +//+------------------------------------------------------------------+ +static void CTestMLPEUnit::UnsetEnsemble(CMLPEnsemble &ensemble) + { +//--- function call + CMLPE::MLPECreate0(1,1,1,ensemble); + } +//+------------------------------------------------------------------+ +//| Iformational functions test | +//+------------------------------------------------------------------+ +static void CTestMLPEUnit::TestInformational(const int nkind,const int nin, + const int nhid1,const int nhid2, + const int nout,const int ec, + const int passcount,bool &err) + { +//--- create variables + int n1=0; + int n2=0; +//--- object of class + CMLPEnsemble ensemble; +//--- function calls + CreateEnsemble(ensemble,nkind,-1.0,1.0,nin,nhid1,nhid2,nout,ec); + CMLPE::MLPEProperties(ensemble,n1,n2); +//--- search errors + err=(err || n1!=nin) || n2!=nout; + } +//+------------------------------------------------------------------+ +//| Processing functions test | +//+------------------------------------------------------------------+ +static void CTestMLPEUnit::TestProcessing(const int nkind,const int nin, + const int nhid1,const int nhid2, + const int nout,const int ec, + const int passcount,bool &err) + { +//--- create variables + double a1=0; + double a2=0; + int pass=0; + int i=0; + bool allsame; + int rlen=0; + double v=0; +//--- create arrays + double x1[]; + double x2[]; + double y1[]; + double y2[]; + double ra[]; + double ra2[]; +//--- objects of classes êëàññà + CMLPEnsemble ensemble; + CMLPEnsemble ensemble2; +//--- Prepare network + a1=0; + a2=0; +//--- check + if(nkind==2) + { + a1=1000*CMath::RandomReal()-500; + a2=2*CMath::RandomReal()-1; + } +//--- check + if(nkind==3) + { + a1=1000*CMath::RandomReal()-500; + a2=a1+(2*CMath::RandomInteger(2)-1)*(0.1+0.9*CMath::RandomReal()); + } +//--- Initialize arrays + ArrayResize(x1,nin); + ArrayResize(x2,nin); + ArrayResize(y1,nout); + ArrayResize(y2,nout); +//--- Main cycle + for(pass=1;pass<=passcount;pass++) + { + //--- function call + CreateEnsemble(ensemble,nkind,a1,a2,nin,nhid1,nhid2,nout,ec); + //--- Same inputs leads to same outputs + for(i=0;i<=nin-1;i++) + { + x1[i]=2*CMath::RandomReal()-1; + x2[i]=x1[i]; + } + for(i=0;i<=nout-1;i++) + { + y1[i]=2*CMath::RandomReal()-1; + y2[i]=2*CMath::RandomReal()-1; + } + //--- function calls + CMLPE::MLPEProcess(ensemble,x1,y1); + CMLPE::MLPEProcess(ensemble,x2,y2); + //--- search errors + allsame=true; + for(i=0;i<=nout-1;i++) + allsame=allsame && y1[i]==y2[i]; + err=err || !allsame; + //--- Same inputs on original network leads to same outputs + //--- on copy created using MLPCopy + UnsetEnsemble(ensemble2); + CMLPE::MLPECopy(ensemble,ensemble2); + for(i=0;i<=nin-1;i++) + { + x1[i]=2*CMath::RandomReal()-1; + x2[i]=x1[i]; + } + for(i=0;i<=nout-1;i++) + { + y1[i]=2*CMath::RandomReal()-1; + y2[i]=2*CMath::RandomReal()-1; + } + //--- function calls + CMLPE::MLPEProcess(ensemble,x1,y1); + CMLPE::MLPEProcess(ensemble2,x2,y2); + //--- search errors + allsame=true; + for(i=0;i<=nout-1;i++) + allsame=allsame && y1[i]==y2[i]; + err=err || !allsame; + //--- Same inputs on original network leads to same outputs + //--- on copy created using MLPSerialize + UnsetEnsemble(ensemble2); + CMLPE::MLPESerialize(ensemble,ra,rlen); + //--- allocation + ArrayResize(ra2,rlen); + //--- copy + for(i=0;i<=rlen-1;i++) + ra2[i]=ra[i]; + //--- function call + CMLPE::MLPEUnserialize(ra2,ensemble2); + for(i=0;i<=nin-1;i++) + { + x1[i]=2*CMath::RandomReal()-1; + x2[i]=x1[i]; + } + for(i=0;i<=nout-1;i++) + { + y1[i]=2*CMath::RandomReal()-1; + y2[i]=2*CMath::RandomReal()-1; + } + //--- function calls + CMLPE::MLPEProcess(ensemble,x1,y1); + CMLPE::MLPEProcess(ensemble2,x2,y2); + //--- search errors + allsame=true; + for(i=0;i<=nout-1;i++) + allsame=allsame && y1[i]==y2[i]; + err=err || !allsame; + //--- Different inputs leads to different outputs (non-zero network) + for(i=0;i<=nin-1;i++) + { + x1[i]=2*CMath::RandomReal()-1; + x2[i]=2*CMath::RandomReal()-1; + } + for(i=0;i<=nout-1;i++) + { + y1[i]=2*CMath::RandomReal()-1; + y2[i]=y1[i]; + } + //--- function calls + CMLPE::MLPEProcess(ensemble,x1,y1); + CMLPE::MLPEProcess(ensemble,x2,y2); + //--- search errors + allsame=true; + for(i=0;i<=nout-1;i++) + allsame=allsame && y1[i]==y2[i]; + err=err || allsame; + //--- Randomization changes outputs (when inputs are unchanged,non-zero network) + for(i=0;i<=nin-1;i++) + { + x1[i]=2*CMath::RandomReal()-1; + x2[i]=2*CMath::RandomReal()-1; + } + for(i=0;i<=nout-1;i++) + { + y1[i]=2*CMath::RandomReal()-1; + y2[i]=y1[i]; + } + //--- function calls + CMLPE::MLPECopy(ensemble,ensemble2); + CMLPE::MLPERandomize(ensemble2); + CMLPE::MLPEProcess(ensemble,x1,y1); + CMLPE::MLPEProcess(ensemble2,x1,y2); + //--- search errors + allsame=true; + for(i=0;i<=nout-1;i++) + allsame=allsame && y1[i]==y2[i]; + err=err || allsame; + //--- Normalization properties + if(nkind==1) + { + //--- Classifier network outputs are normalized + for(i=0;i<=nin-1;i++) + x1[i]=2*CMath::RandomReal()-1; + //--- function call + CMLPE::MLPEProcess(ensemble,x1,y1); + v=0; + //--- search errors + for(i=0;i<=nout-1;i++) + { + v=v+y1[i]; + err=err || y1[i]<0.0; + } + err=err || MathAbs(v-1)>1000*CMath::m_machineepsilon; + } + //--- check + if(nkind==2) + { + //--- B-type network outputs are bounded from above/below + for(i=0;i<=nin-1;i++) + x1[i]=2*CMath::RandomReal()-1; + //--- function call + CMLPE::MLPEProcess(ensemble,x1,y1); + for(i=0;i<=nout-1;i++) + { + //--- check + if(a2>=0.0) + err=err || y1[i]a1; + } + } + //--- check + if(nkind==3) + { + //--- R-type network outputs are within [A1,A2] (or [A2,A1]) + for(i=0;i<=nin-1;i++) + x1[i]=2*CMath::RandomReal()-1; + //--- function call + CMLPE::MLPEProcess(ensemble,x1,y1); + //--- search errors + for(i=0;i<=nout-1;i++) + err=(err || y1[i]MathMax(a1,a2); + } + } + } +//+------------------------------------------------------------------+ +//| Testing class CPCAnalysis | +//+------------------------------------------------------------------+ +class CTestPCAUnit + { +private: + //--- private method + static void CalculateMV(double &x[],const int n,double &mean,double &means,double &stddev,double &stddevs); +public: + //--- constructor, destructor + CTestPCAUnit(void); + ~CTestPCAUnit(void); + //--- public method + static bool TestPCA(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestPCAUnit::CTestPCAUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestPCAUnit::~CTestPCAUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CPCAnalysis | +//+------------------------------------------------------------------+ +static bool CTestPCAUnit::TestPCA(const bool silent) + { +//--- create variables + int passcount=0; + int maxn=0; + int maxm=0; + double threshold=0; + int m=0; + int n=0; + int i=0; + int j=0; + int k=0; + int info=0; + double t=0; + double h=0; + double tmean=0; + double tmeans=0; + double tstddev=0; + double tstddevs=0; + double tmean2=0; + double tmeans2=0; + double tstddev2=0; + double tstddevs2=0; + bool pcaconverrors; + bool pcaorterrors; + bool pcavarerrors; + bool pcaopterrors; + bool waserrors; + int i_=0; +//--- create arrays + double means[]; + double s[]; + double t2[]; + double t3[]; +//--- create matrix + CMatrixDouble v; + CMatrixDouble x; +//--- Primary settings + maxm=10; + maxn=100; + passcount=1; + threshold=1000*CMath::m_machineepsilon; + waserrors=false; + pcaconverrors=false; + pcaorterrors=false; + pcavarerrors=false; + pcaopterrors=false; +//--- Test 1: N random points in M-dimensional space + for(m=1;m<=maxm;m++) + { + for(n=1;n<=maxn;n++) + { + //--- Generate task + x.Resize(n,m); + ArrayResize(means,m); + //--- change values + for(j=0;j<=m-1;j++) + means[j]=1.5*CMath::RandomReal()-0.75; + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + x[i].Set(j,means[j]+(2*CMath::RandomReal()-1)); + } + //--- Solve + CPCAnalysis::PCABuildBasis(x,n,m,info,s,v); + //--- check + if(info!=1) + { + pcaconverrors=true; + continue; + } + //--- Orthogonality test + for(i=0;i<=m-1;i++) + { + for(j=0;j<=m-1;j++) + { + //--- change value + t=0.0; + for(i_=0;i_<=m-1;i_++) + t+=v[i_][i]*v[i_][j]; + //--- check + if(i==j) + t=t-1; + //--- search errors + pcaorterrors=pcaorterrors || MathAbs(t)>threshold; + } + } + //--- Variance test + ArrayResize(t2,n); + for(k=0;k<=m-1;k++) + { + for(i=0;i<=n-1;i++) + { + //--- change value + t=0.0; + for(i_=0;i_<=m-1;i_++) + t+=x[i][i_]*v[i_][k]; + t2[i]=t; + } + //--- function call + CalculateMV(t2,n,tmean,tmeans,tstddev,tstddevs); + //--- check + if(n!=1) + t=CMath::Sqr(tstddev)*n/(n-1); + else + t=0; + //--- search errors + pcavarerrors=pcavarerrors || MathAbs(t-s[k])>threshold; + } + //--- search errors + for(k=0;k<=m-2;k++) + pcavarerrors=pcavarerrors || s[k]tstddev+threshold; + } + } + } +//--- Special test for N=0 + for(m=1;m<=maxm;m++) + { + //--- Solve + CPCAnalysis::PCABuildBasis(x,0,m,info,s,v); + //--- check + if(info!=1) + { + pcaconverrors=true; + continue; + } + //--- Orthogonality test + for(i=0;i<=m-1;i++) + { + for(j=0;j<=m-1;j++) + { + //--- change value + t=0.0; + for(i_=0;i_<=m-1;i_++) + t+=v[i_][i]*v[i_][j]; + //--- check + if(i==j) + t=t-1; + //--- search errors + pcaorterrors=pcaorterrors || MathAbs(t)>threshold; + } + } + } +//--- Final report + waserrors=((pcaconverrors || pcaorterrors) || pcavarerrors) || pcaopterrors; +//--- check + if(!silent) + { + Print("PCA TEST"); + Print("TOTAL RESULTS: "); + //--- check + if(!waserrors) + Print("OK"); + else + Print("FAILED"); + Print("* CONVERGENCE "); + //--- check + if(!pcaconverrors) + Print("OK"); + else + Print("FAILED"); + Print("* ORTOGONALITY "); + //--- check + if(!pcaorterrors) + Print("OK"); + else + Print("FAILED"); + Print("* VARIANCE REPORT "); + //--- check + if(!pcavarerrors) + Print("OK"); + else + Print("FAILED"); + Print("* OPTIMALITY "); + //--- check + if(!pcaopterrors) + Print("OK"); + else + Print("FAILED"); + //--- check + if(waserrors) + Print("TEST SUMMARY: FAILED"); + else + Print("TEST SUMMARY: PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Moments estimates and their errors | +//+------------------------------------------------------------------+ +static void CTestPCAUnit::CalculateMV(double &x[],const int n,double &mean, + double &means,double &stddev,double &stddevs) + { +//--- create variables + int i=0; + double v1=0; + double v2=0; + double variance=0; +//--- initialization + mean=0; + means=1; + stddev=0; + stddevs=1; + variance=0; +//--- check + if(n<=1) + return; +//--- Mean + for(i=0;i<=n-1;i++) + mean=mean+x[i]; + mean=mean/n; +//--- Variance (using corrected two-pass algorithm) + if(n!=1) + { + //--- change values + v1=0; + for(i=0;i<=n-1;i++) + v1=v1+CMath::Sqr(x[i]-mean); + v2=0; + for(i=0;i<=n-1;i++) + v2=v2+(x[i]-mean); + v2=CMath::Sqr(v2)/n; + variance=(v1-v2)/n; + //--- check + if(variance<0.0) + variance=0; + stddev=MathSqrt(variance); + } +//--- Errors + means=stddev/MathSqrt(n); + stddevs=stddev*MathSqrt(2)/MathSqrt(n-1); + } +//+------------------------------------------------------------------+ +//| Testing class CODESolver | +//+------------------------------------------------------------------+ +class CTestODESolverUnit + { +private: + //--- private methods + static void Unset2D(CMatrixDouble &x); + static void Unset1D(double &x[]); + static void UnsetRep(CODESolverReport &rep); +public: + //--- constructor, destructor + CTestODESolverUnit(void); + ~CTestODESolverUnit(void); + //--- public method + static bool TestODESolver(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestODESolverUnit::CTestODESolverUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestODESolverUnit::~CTestODESolverUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Test | +//+------------------------------------------------------------------+ +static bool CTestODESolverUnit::TestODESolver(const bool silent) + { +//--- create variables + int passcount=0; + bool curerrors; + bool rkckerrors; + bool waserrors; + double h=0; + double eps=0; + int solver=0; + int pass=0; + int mynfev=0; + double v=0; + int m=0; + int m2=0; + int i=0; + double err=0; + int i_=0; +//--- create arrays + double xtbl[]; + double xg[]; + double y[]; +//--- create matrix + CMatrixDouble ytbl; +//--- objects of classes + CODESolverReport rep; + CODESolverState state; +//--- initialization + rkckerrors=false; + waserrors=false; + passcount=10; +//--- simple test: just A*sin(x)+B*cos(x) + if(!CAp::Assert(passcount>=2)) + return(false); + for(pass=0;pass<=passcount-1;pass++) + { + for(solver=0;solver<=0;solver++) + { + //--- prepare + h=1.0E-2; + eps=1.0E-5; + //--- check + if(pass%2==0) + eps=-eps; + //--- allocation + ArrayResize(y,2); + //--- change values + for(i=0;i<=1;i++) + y[i]=2*CMath::RandomReal()-1; + m=2+CMath::RandomInteger(10); + //--- allocation + ArrayResize(xg,m); + xg[0]=(m-1)*CMath::RandomReal(); + for(i=1;i<=m-1;i++) + xg[i]=xg[i-1]+CMath::RandomReal(); + //--- change values + v=2*M_PI/(xg[m-1]-xg[0]); + for(i_=0;i_<=m-1;i_++) + xg[i_]=v*xg[i_]; + //--- check + if(CMath::RandomReal()>0.5) + { + for(i_=0;i_<=m-1;i_++) + xg[i_]=-1*xg[i_]; + } + mynfev=0; + //--- choose solver + if(solver==0) + CODESolver::ODESolverRKCK(y,2,xg,m,eps,h,state); + //--- solve + while(CODESolver::ODESolverIteration(state)) + { + state.m_dy[0]=state.m_y[1]; + state.m_dy[1]=-state.m_y[0]; + mynfev=mynfev+1; + } + //--- function call + CODESolver::ODESolverResults(state,m2,xtbl,ytbl,rep); + //--- check results + curerrors=false; + //--- check + if(rep.m_terminationtype<=0) + curerrors=true; + else + { + //--- search errors + curerrors=curerrors || m2!=m; + err=0; + for(i=0;i<=m-1;i++) + { + err=MathMax(err,MathAbs(ytbl[i][0]-(y[0]*MathCos(xtbl[i]-xtbl[0])+y[1]*MathSin(xtbl[i]-xtbl[0])))); + err=MathMax(err,MathAbs(ytbl[i][1]-(-(y[0]*MathSin(xtbl[i]-xtbl[0]))+y[1]*MathCos(xtbl[i]-xtbl[0])))); + } + curerrors=curerrors || err>10*MathAbs(eps); + curerrors=curerrors || mynfev!=rep.m_nfev; + } + //--- check + 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. + if(!CAp::Assert(passcount>=2)) + return(false); + for(pass=0;pass<=passcount-1;pass++) + { + h=1.0E-4; + eps=1.0E-4; + //--- check + if(pass%2==0) + eps=-eps; + //--- allocation + ArrayResize(y,1); + y[0]=0; + m=21; + //--- allocation + ArrayResize(xg,m); + for(i=0;i<=m-1;i++) + xg[i]=(double)(2*i)/(double)(m-1); + mynfev=0; + //--- function call + CODESolver::ODESolverRKCK(y,1,xg,m,eps,h,state); + //--- cycle + while(CODESolver::ODESolverIteration(state)) + { + state.m_dy[0]=MathMax(state.m_x-1,0); + mynfev=mynfev+1; + } + //--- function call + CODESolver::ODESolverResults(state,m2,xtbl,ytbl,rep); + //--- check + if(rep.m_terminationtype<=0) + rkckerrors=true; + else + { + //--- search errors + rkckerrors=rkckerrors || m2!=m; + err=0; + for(i=0;i<=m-1;i++) + err=MathMax(err,MathAbs(ytbl[i][0]-CMath::Sqr(MathMax(xg[i]-1,0))/2)); + rkckerrors=rkckerrors || err>MathAbs(eps); + rkckerrors=rkckerrors || mynfev!=rep.m_nfev; + } + } +//--- end + waserrors=rkckerrors; +//--- check + if(!silent) + { + Print("TESTING ODE SOLVER"); + Print("* RK CASH-KARP: "); + //--- check + if(rkckerrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Unsets real matrix | +//+------------------------------------------------------------------+ +static void CTestODESolverUnit::Unset2D(CMatrixDouble &x) + { +//--- allocation + x.Resize(1,1); +//--- change value + x[0].Set(0,2*CMath::RandomReal()-1); + } +//+------------------------------------------------------------------+ +//| Unsets real vector | +//+------------------------------------------------------------------+ +static void CTestODESolverUnit::Unset1D(double &x[]) + { +//--- allocation + ArrayResize(x,1); +//--- change value + x[0]=2*CMath::RandomReal()-1; + } +//+------------------------------------------------------------------+ +//| Unsets report | +//+------------------------------------------------------------------+ +static void CTestODESolverUnit::UnsetRep(CODESolverReport &rep) + { +//--- change value + rep.m_nfev=0; + } +//+------------------------------------------------------------------+ +//| Testing class CFastFourierTransform | +//+------------------------------------------------------------------+ +class CTestFFTUnit + { +private: + //--- private methods + static void RefFFTC1D(complex &a[],const int n); + static void RefFFTC1DInv(complex &a[],const int n); + static void RefInternalCFFT(double &a[],const int nn,const bool inversefft); + static void RefInternalRFFT(double &a[],const int nn,complex &f[]); +public: + //--- constructor, destructor + CTestFFTUnit(void); + ~CTestFFTUnit(void); + //--- public method + static bool TestFFT(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestFFTUnit::CTestFFTUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestFFTUnit::~CTestFFTUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Test | +//+------------------------------------------------------------------+ +static bool CTestFFTUnit::TestFFT(const bool silent) + { +//--- create variables + int n=0; + int i=0; + int k=0; + int maxn=0; + double bidierr=0; + double bidirerr=0; + double referr=0; + double refrerr=0; + double reinterr=0; + double errtol=0; + bool referrors; + bool bidierrors; + bool refrerrors; + bool bidirerrors; + bool reinterrors; + bool waserrors; + int i_=0; +//--- create arrays + complex a1[]; + complex a2[]; + complex a3[]; + double r1[]; + double r2[]; + double buf[]; +//--- object of class + CFtPlan plan; +//--- initialization + maxn=128; + errtol=100000*MathPow(maxn,3.0/2.0)*CMath::m_machineepsilon; + bidierrors=false; + referrors=false; + bidirerrors=false; + refrerrors=false; + reinterrors=false; + waserrors=false; +//--- Test bi-directional error: norm(x-invFFT(FFT(x))) + bidierr=0; + bidirerr=0; + for(n=1;n<=maxn;n++) + { + //--- Complex FFT/invFFT + ArrayResize(a1,n); + ArrayResize(a2,n); + ArrayResize(a3,n); + for(i=0;i<=n-1;i++) + { + a1[i].re=2*CMath::RandomReal()-1; + a1[i].im=2*CMath::RandomReal()-1; + a2[i]=a1[i]; + a3[i]=a1[i]; + } + //--- function calls + CFastFourierTransform::FFTC1D(a2,n); + CFastFourierTransform::FFTC1DInv(a2,n); + CFastFourierTransform::FFTC1DInv(a3,n); + CFastFourierTransform::FFTC1D(a3,n); + //--- search errors + for(i=0;i<=n-1;i++) + { + bidierr=MathMax(bidierr,CMath::AbsComplex(a1[i]-a2[i])); + bidierr=MathMax(bidierr,CMath::AbsComplex(a1[i]-a3[i])); + } + //--- Real + ArrayResize(r1,n); + ArrayResize(r2,n); + //--- change values + for(i=0;i<=n-1;i++) + { + r1[i]=2*CMath::RandomReal()-1; + r2[i]=r1[i]; + } + //--- function call + CFastFourierTransform::FFTR1D(r2,n,a1); + for(i_=0;i_<=n-1;i_++) + r2[i_]=0*r2[i_]; + //--- function call + CFastFourierTransform::FFTR1DInv(a1,n,r2); + //--- search errors + for(i=0;i<=n-1;i++) + bidirerr=MathMax(bidirerr,CMath::AbsComplex(r1[i]-r2[i])); + } +//--- search errors + bidierrors=bidierrors || bidierr>errtol; + bidirerrors=bidirerrors || bidirerr>errtol; +//--- Test against reference O(N^2) implementation + referr=0; + refrerr=0; + for(n=1;n<=maxn;n++) + { + //--- Complex FFT + ArrayResize(a1,n); + ArrayResize(a2,n); + for(i=0;i<=n-1;i++) + { + a1[i].re=2*CMath::RandomReal()-1; + a1[i].im=2*CMath::RandomReal()-1; + a2[i]=a1[i]; + } + //--- function calls + CFastFourierTransform::FFTC1D(a1,n); + RefFFTC1D(a2,n); + //--- search errors + for(i=0;i<=n-1;i++) + referr=MathMax(referr,CMath::AbsComplex(a1[i]-a2[i])); + //--- Complex inverse FFT + ArrayResize(a1,n); + ArrayResize(a2,n); + for(i=0;i<=n-1;i++) + { + a1[i].re=2*CMath::RandomReal()-1; + a1[i].im=2*CMath::RandomReal()-1; + a2[i]=a1[i]; + } + //--- function calls + CFastFourierTransform::FFTC1DInv(a1,n); + RefFFTC1DInv(a2,n); + //--- search errors + for(i=0;i<=n-1;i++) + referr=MathMax(referr,CMath::AbsComplex(a1[i]-a2[i])); + //--- 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 + ArrayResize(r1,n); + ArrayResize(r2,n); + for(i=0;i<=n-1;i++) + { + r1[i]=2*CMath::RandomReal()-1; + r2[i]=r1[i]; + } + //--- function calls + CFastFourierTransform::FFTR1D(r1,n,a1); + RefInternalRFFT(r2,n,a2); + //--- search errors + for(i=0;i<=n-1;i++) + refrerr=MathMax(refrerr,CMath::AbsComplex(a1[i]-a2[i])); + //--- allocation + ArrayResize(a3,(int)MathFloor((double)n/2.0)+1); + for(i=0;i<=(int)MathFloor((double)n/2.0);i++) + a3[i]=a2[i]; + a3[0].im=2*CMath::RandomReal()-1; + //--- check + if(n%2==0) + a3[(int)MathFloor((double)n/2.0)].im=2*CMath::RandomReal()-1; + for(i=0;i<=n-1;i++) + r1[i]=0; + //--- function call + CFastFourierTransform::FFTR1DInv(a3,n,r1); + //--- search errors + for(i=0;i<=n-1;i++) + refrerr=MathMax(refrerr,MathAbs(r2[i]-r1[i])); + } +//--- search errors + referrors=referrors || referr>errtol; + refrerrors=refrerrors || refrerr>errtol; +//--- test internal real even FFT + reinterr=0; + for(k=1;k<=maxn/2;k++) + { + n=2*k; + //--- Real forward FFT + ArrayResize(r1,n); + ArrayResize(r2,n); + for(i=0;i<=n-1;i++) + { + r1[i]=2*CMath::RandomReal()-1; + r2[i]=r1[i]; + } + //--- function call + CFtBase::FtBaseGenerateComplexFFtPlan(n/2,plan); + //--- allocation + ArrayResize(buf,n); + //--- function calls + CFastFourierTransform::FFTR1DInternalEven(r1,n,buf,plan); + RefInternalRFFT(r2,n,a2); + //--- search errors + reinterr=MathMax(reinterr,MathAbs(r1[0]-a2[0].re)); + reinterr=MathMax(reinterr,MathAbs(r1[1]-a2[n/2].re)); + for(i=1;i<=n/2-1;i++) + { + reinterr=MathMax(reinterr,MathAbs(r1[2*i+0]-a2[i].re)); + reinterr=MathMax(reinterr,MathAbs(r1[2*i+1]-a2[i].im)); + } + //--- Real backward FFT + ArrayResize(r1,n); + for(i=0;i<=n-1;i++) + r1[i]=2*CMath::RandomReal()-1; + ArrayResize(a2,(int)MathFloor((double)n/2.0)+1); + a2[0]=r1[0]; + for(i=1;i<=(int)MathFloor((double)n/2.0)-1;i++) + { + a2[i].re=r1[2*i+0]; + a2[i].im=r1[2*i+1]; + } + a2[(int)MathFloor((double)n/2.0)]=r1[1]; + //--- function call + CFtBase::FtBaseGenerateComplexFFtPlan(n/2,plan); + //--- allocation + ArrayResize(buf,n); + //--- function calls + CFastFourierTransform::FFTR1DInvInternalEven(r1,n,buf,plan); + CFastFourierTransform::FFTR1DInv(a2,n,r2); + //--- search errors + for(i=0;i<=n-1;i++) + reinterr=MathMax(reinterr,MathAbs(r1[i]-r2[i])); + } +//--- search errors + reinterrors=reinterrors || reinterr>errtol; +//--- end + waserrors=(((bidierrors || bidirerrors) || referrors) || refrerrors) || reinterrors; +//--- check + if(!silent) + { + Print("TESTING FFT"); + Print("FINAL RESULT: "); + //--- check + if(waserrors) + Print("FAILED"); + else + Print("OK"); + Print("* BI-DIRECTIONAL COMPLEX TEST: "); + //--- check + if(bidierrors) + Print("FAILED"); + else + Print("OK"); + Print("* AGAINST REFERENCE COMPLEX FFT: "); + //--- check + if(referrors) + Print("FAILED"); + else + Print("OK"); + Print("* BI-DIRECTIONAL REAL TEST: "); + //--- check + if(bidirerrors) + Print("FAILED"); + else + Print("OK"); + Print("* AGAINST REFERENCE REAL FFT: "); + //--- check + if(refrerrors) + Print("FAILED"); + else + Print("OK"); + Print("* INTERNAL EVEN FFT: "); + //--- check + if(reinterrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Reference FFT | +//+------------------------------------------------------------------+ +static void CTestFFTUnit::RefFFTC1D(complex &a[],const int n) + { +//--- create variables + int i=0; +//--- create array + double buf[]; +//--- check + if(!CAp::Assert(n>0,"FFTC1D: incorrect N!")) + return; +//--- allocation + ArrayResize(buf,2*n); +//--- copy + for(i=0;i<=n-1;i++) + { + buf[2*i+0]=a[i].re; + buf[2*i+1]=a[i].im; + } +//--- function call + RefInternalCFFT(buf,n,false); +//--- copy + for(i=0;i<=n-1;i++) + { + a[i].re=buf[2*i+0]; + a[i].im=buf[2*i+1]; + } + } +//+------------------------------------------------------------------+ +//| Reference inverse FFT | +//+------------------------------------------------------------------+ +static void CTestFFTUnit::RefFFTC1DInv(complex &a[],const int n) + { +//--- create variables + int i=0; +//--- create array + double buf[]; +//--- check + if(!CAp::Assert(n>0,"FFTC1DInv: incorrect N!")) + return; +//--- allocation + ArrayResize(buf,2*n); +//--- copy + for(i=0;i<=n-1;i++) + { + buf[2*i+0]=a[i].re; + buf[2*i+1]=a[i].im; + } +//--- function call + RefInternalCFFT(buf,n,true); +//--- copy + for(i=0;i<=n-1;i++) + { + a[i].re=buf[2*i+0]; + a[i].im=buf[2*i+1]; + } + } +//+------------------------------------------------------------------+ +//| Internal complex FFT stub. | +//| Uses straightforward formula with O(N^2) complexity. | +//+------------------------------------------------------------------+ +static void CTestFFTUnit::RefInternalCFFT(double &a[],const int nn, + const bool inversefft) + { +//--- create variables + int i=0; + int k=0; + double hre=0; + double him=0; + double c=0; + double s=0; + double re=0; + double im=0; +//--- create array + double tmp[]; +//--- allocation + ArrayResize(tmp,2*nn); +//--- check + if(!inversefft) + { + for(i=0;i<=nn-1;i++) + { + //--- change values + hre=0; + him=0; + //--- calculation + for(k=0;k<=nn-1;k++) + { + re=a[2*k]; + im=a[2*k+1]; + c=MathCos(-(2*M_PI*k*i/nn)); + s=MathSin(-(2*M_PI*k*i/nn)); + hre=hre+c*re-s*im; + him=him+c*im+s*re; + } + //--- change values + tmp[2*i]=hre; + tmp[2*i+1]=him; + } + for(i=0;i<=2*nn-1;i++) + a[i]=tmp[i]; + } + else + { + for(k=0;k<=nn-1;k++) + { + //--- change values + hre=0; + him=0; + //--- calculation + for(i=0;i<=nn-1;i++) + { + re=a[2*i]; + im=a[2*i+1]; + c=MathCos(2*M_PI*k*i/nn); + s=MathSin(2*M_PI*k*i/nn); + hre=hre+c*re-s*im; + him=him+c*im+s*re; + } + //--- change values + tmp[2*k]=hre/nn; + tmp[2*k+1]=him/nn; + } + for(i=0;i<=2*nn-1;i++) + a[i]=tmp[i]; + } + } +//+------------------------------------------------------------------+ +//| Internal real FFT stub. | +//| Uses straightforward formula with O(N^2) complexity. | +//+------------------------------------------------------------------+ +static void CTestFFTUnit::RefInternalRFFT(double &a[],const int nn,complex &f[]) + { +//--- create a variable + int i=0; +//--- create array + double tmp[]; +//--- allocation + ArrayResize(tmp,2*nn); +//--- copy + for(i=0;i<=nn-1;i++) + { + tmp[2*i]=a[i]; + tmp[2*i+1]=0; + } +//--- function call + RefInternalCFFT(tmp,nn,false); +//--- allocation + ArrayResize(f,nn); +//--- copy + for(i=0;i<=nn-1;i++) + { + f[i].re=tmp[2*i+0]; + f[i].im=tmp[2*i+1]; + } + } +//+------------------------------------------------------------------+ +//| Testing class CConv | +//+------------------------------------------------------------------+ +class CTestConvUnit + { +private: + //--- private methods + static void RefConvC1D(complex &a[],const int m,complex &b[],const int n,complex &r[]); + static void RefConvC1DCircular(complex &a[],const int m,complex &b[],const int n,complex &r[]); + static void RefConvR1D(double &a[],const int m,double &b[],const int n,double &r[]); + static void RefConvR1DCircular(double &a[],const int m,double &b[],const int n,double &r[]); +public: + //--- constructor, destructor + CTestConvUnit(void); + ~CTestConvUnit(void); + //--- public method + static bool TestConv(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestConvUnit::CTestConvUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestConvUnit::~CTestConvUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Test | +//+------------------------------------------------------------------+ +static bool CTestConvUnit::TestConv(const bool silent) + { +//--- create variables + int m=0; + int n=0; + int i=0; + int rkind=0; + int circkind=0; + int maxn=0; + double referr=0; + double refrerr=0; + double inverr=0; + double invrerr=0; + double errtol=0; + bool referrors; + bool refrerrors; + bool inverrors; + bool invrerrors; + bool waserrors; +//--- create arrays + double ra[]; + double rb[]; + double rr1[]; + double rr2[]; + complex ca[]; + complex cb[]; + complex cr1[]; + complex cr2[]; +//--- initialization + maxn=32; + errtol=100000*MathPow(maxn,3.0/2.0)*CMath::m_machineepsilon; + referrors=false; + refrerrors=false; + inverrors=false; + invrerrors=false; + waserrors=false; +//--- Test against reference O(N^2) implementation. +//--- Automatic ConvC1D() and different algorithms of ConvC1DX() are tested. + referr=0; + refrerr=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 + CConv::ConvC1DX(ca,m,cb,n,circkind!=0,rkind,0,cr1); + } + else + { + //--- test internal subroutine - circular mode only + if(!CAp::Assert(circkind==0,"Convolution test: internal error!")) + return(false); + //--- function call + CConv::ConvC1DX(cb,n,ca,m,false,rkind,0,cr1); + } + } + //--- check + if(circkind==0) + RefConvC1D(ca,m,cb,n,cr2); + else + RefConvC1DCircular(ca,m,cb,n,cr2); + //--- check + if(circkind==0) + { + for(i=0;i<=m+n-2;i++) + referr=MathMax(referr,CMath::AbsComplex(cr1[i]-cr2[i])); + } + else + { + for(i=0;i<=m-1;i++) + referr=MathMax(referr,CMath::AbsComplex(cr1[i]-cr2[i])); + } + //--- Real convolution + ArrayResize(ra,m); + for(i=0;i<=m-1;i++) + ra[i]=2*CMath::RandomReal()-1; + //--- allocation + ArrayResize(rb,n); + for(i=0;i<=n-1;i++) + rb[i]=2*CMath::RandomReal()-1; + //--- allocation + ArrayResize(rr1,1); + //--- check + if(rkind==-3) + { + //--- test wrapper subroutine: + //--- * circular/non-circular + if(circkind==0) + CConv::ConvR1D(ra,m,rb,n,rr1); + else + CConv::ConvR1DCircular(ra,m,rb,n,rr1); + } + else + { + //--- check + if(m>=n) + { + //--- test internal subroutine: + //--- * circular/non-circular mode + CConv::ConvR1DX(ra,m,rb,n,circkind!=0,rkind,0,rr1); + } + else + { + //--- test internal subroutine - non-circular mode only + CConv::ConvR1DX(rb,n,ra,m,circkind!=0,rkind,0,rr1); + } + } + //--- check + if(circkind==0) + RefConvR1D(ra,m,rb,n,rr2); + else + RefConvR1DCircular(ra,m,rb,n,rr2); + //--- check + if(circkind==0) + { + for(i=0;i<=m+n-2;i++) + refrerr=MathMax(refrerr,MathAbs(rr1[i]-rr2[i])); + } + else + { + for(i=0;i<=m-1;i++) + refrerr=MathMax(refrerr,MathAbs(rr1[i]-rr2[i])); + } + } + } + } + } +//--- search errors + referrors=referrors || referr>errtol; + refrerrors=refrerrors || refrerr>errtol; +//--- Test inverse convolution + inverr=0; + invrerr=0; + for(m=1;m<=maxn;m++) + { + for(n=1;n<=maxn;n++) + { + //--- Complex circilar and non-circular + ArrayResize(ca,m); + for(i=0;i<=m-1;i++) + { + ca[i].re=2*CMath::RandomReal()-1; + ca[i].im=2*CMath::RandomReal()-1; + } + //--- allocation + ArrayResize(cb,n); + for(i=0;i<=n-1;i++) + { + cb[i].re=2*CMath::RandomReal()-1; + cb[i].im=2*CMath::RandomReal()-1; + } + //--- allocation + ArrayResize(cr1,1); + ArrayResize(cr2,1); + //--- function calls + CConv::ConvC1D(ca,m,cb,n,cr2); + CConv::ConvC1DInv(cr2,m+n-1,cb,n,cr1); + //--- search errors + for(i=0;i<=m-1;i++) + { + inverr=MathMax(inverr,CMath::AbsComplex(cr1[i]-ca[i])); + } + //--- allocation + ArrayResize(cr1,1); + ArrayResize(cr2,1); + //--- function calls + CConv::ConvC1DCircular(ca,m,cb,n,cr2); + CConv::ConvC1DCircularInv(cr2,m,cb,n,cr1); + //--- search errors + for(i=0;i<=m-1;i++) + inverr=MathMax(inverr,CMath::AbsComplex(cr1[i]-ca[i])); + //--- Real circilar and non-circular + ArrayResize(ra,m); + for(i=0;i<=m-1;i++) + ra[i]=2*CMath::RandomReal()-1; + //--- allocation + ArrayResize(rb,n); + for(i=0;i<=n-1;i++) + rb[i]=2*CMath::RandomReal()-1; + //--- allocation + ArrayResize(rr1,1); + ArrayResize(rr2,1); + //--- function calls + CConv::ConvR1D(ra,m,rb,n,rr2); + CConv::ConvR1DInv(rr2,m+n-1,rb,n,rr1); + //--- search errors + for(i=0;i<=m-1;i++) + invrerr=MathMax(invrerr,MathAbs(rr1[i]-ra[i])); + //--- allocation + ArrayResize(rr1,1); + ArrayResize(rr2,1); + //--- function calls + CConv::ConvR1DCircular(ra,m,rb,n,rr2); + CConv::ConvR1DCircularInv(rr2,m,rb,n,rr1); + //--- search errors + for(i=0;i<=m-1;i++) + invrerr=MathMax(invrerr,MathAbs(rr1[i]-ra[i])); + } + } +//--- search errors + inverrors=inverrors || inverr>errtol; + invrerrors=invrerrors || invrerr>errtol; +//--- end + waserrors=((referrors || refrerrors) || inverrors) || invrerrors; +//--- check + if(!silent) + { + Print("TESTING CONVOLUTION"); + Print("FINAL RESULT: "); + //--- check + if(waserrors) + Print("FAILED"); + else + Print("OK"); + Print("* AGAINST REFERENCE COMPLEX CONV: "); + //--- check + if(referrors) + Print("FAILED"); + else + Print("OK"); + Print("* AGAINST REFERENCE REAL CONV: "); + //--- check + if(refrerrors) + Print("FAILED"); + else + Print("OK"); + Print("* COMPLEX INVERSE: "); + //--- check + if(inverrors) + Print("FAILED"); + else + Print("OK"); + Print("* REAL INVERSE: "); + //--- check + if(invrerrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Reference implementation | +//+------------------------------------------------------------------+ +static void CTestConvUnit::RefConvC1D(complex &a[],const int m,complex &b[], + const int n,complex &r[]) + { +//--- create variables + int i=0; + complex v=0; + int i_=0; + int i1_=0; +//--- allocation + ArrayResize(r,m+n-1); +//--- initialization + for(i=0;i<=m+n-2;i++) + r[i]=0; +//--- calculation + for(i=0;i<=m-1;i++) + { + v=a[i]; + i1_=-i; + for(i_=i;i_<=i+n-1;i_++) + r[i_]=r[i_]+v*b[i_+i1_]; + } + } +//+------------------------------------------------------------------+ +//| Reference implementation | +//+------------------------------------------------------------------+ +static void CTestConvUnit::RefConvC1DCircular(complex &a[],const int m, + complex &b[],const int n, + complex &r[]) + { +//--- create variables + int i1=0; + int i2=0; + int j2=0; + int i_=0; + int i1_=0; +//--- create array + complex buf[]; +//--- function call + RefConvC1D(a,m,b,n,buf); +//--- allocation + ArrayResize(r,m); +//--- copy + for(i_=0;i_<=m-1;i_++) + r[i_]=buf[i_]; +//--- calculation + i1=m; + while(i1<=m+n-2) + { + //--- change values + i2=MathMin(i1+m-1,m+n-2); + j2=i2-i1; + i1_=i1; + for(i_=0;i_<=j2;i_++) + r[i_]=r[i_]+buf[i_+i1_]; + i1=i1+m; + } + } +//+------------------------------------------------------------------+ +//| Reference FFT | +//+------------------------------------------------------------------+ +static void CTestConvUnit::RefConvR1D(double &a[],const int m,double &b[], + const int n,double &r[]) + { +//--- create variables + int i=0; + double v=0; + int i_=0; + int i1_=0; +//--- allocation + ArrayResize(r,m+n-1); +//--- initialization + for(i=0;i<=m+n-2;i++) + r[i]=0; +//--- calculation + for(i=0;i<=m-1;i++) + { + v=a[i]; + i1_=-i; + for(i_=i;i_<=i+n-1;i_++) + r[i_]=r[i_]+v*b[i_+i1_]; + } + } +//+------------------------------------------------------------------+ +//| Reference implementation | +//+------------------------------------------------------------------+ +static void CTestConvUnit::RefConvR1DCircular(double &a[],const int m, + double &b[],const int n, + double &r[]) + { +//--- create variables + int i1=0; + int i2=0; + int j2=0; + int i_=0; + int i1_=0; +//--- create array + double buf[]; +//--- function call + RefConvR1D(a,m,b,n,buf); +//--- allocation + ArrayResize(r,m); +//--- copy + for(i_=0;i_<=m-1;i_++) + r[i_]=buf[i_]; +//--- calculation + i1=m; + while(i1<=m+n-2) + { + //--- change values + i2=MathMin(i1+m-1,m+n-2); + j2=i2-i1; + i1_=i1; + for(i_=0;i_<=j2;i_++) + r[i_]=r[i_]+buf[i_+i1_]; + i1=i1+m; + } + } +//+------------------------------------------------------------------+ +//| Testing class CCorr | +//+------------------------------------------------------------------+ +class CTestCorrUnit + { +private: + //--- private methods + static void RefCorrC1D(complex &signal[],const int n,complex &pattern[],const int m,complex &r[]); + static void RefCorrC1DCircular(complex &signal[],const int n,complex &pattern[],const int m,complex &r[]); + static void RefCorrR1D(double &signal[],const int n,double &pattern[],const int m,double &r[]); + static void RefCorrR1DCircular(double &signal[],const int n,double &pattern[],const int m,double &r[]); + static void RefConvC1D(complex &a[],const int m,complex &b[],const int n,complex &r[]); + static void RefConvC1DCircular(complex &a[],const int m,complex &b[],const int n,complex &r[]); + static void RefConvR1D(double &a[],const int m,double &b[],const int n,double &r[]); + static void RefConvR1DCircular(double &a[],const int m,double &b[],const int n,double &r[]); +public: + //--- constructor, destructor + CTestCorrUnit(void); + ~CTestCorrUnit(void); + //--- public method + static bool TestCorr(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestCorrUnit::CTestCorrUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestCorrUnit::~CTestCorrUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CCorr | +//+------------------------------------------------------------------+ +static bool CTestCorrUnit::TestCorr(const bool silent) + { +//--- create variables + int m=0; + int n=0; + int i=0; + int maxn=0; + double referr=0; + double refrerr=0; + double errtol=0; + bool referrors; + bool refrerrors; + bool inverrors; + bool invrerrors; + bool waserrors; +//--- create arrays + double ra[]; + double rb[]; + double rr1[]; + double rr2[]; + complex ca[]; + complex cb[]; + complex cr1[]; + complex cr2[]; +//--- initialization + maxn=32; + errtol=100000*MathPow(maxn,3.0/2.0)*CMath::m_machineepsilon; + referrors=false; + refrerrors=false; + inverrors=false; + invrerrors=false; + waserrors=false; +//--- Test against reference O(N^2) implementation. + referr=0; + refrerr=0; + for(m=1;m<=maxn;m++) + { + for(n=1;n<=maxn;n++) + { + //--- Complex correlation + ArrayResize(ca,m); + for(i=0;i<=m-1;i++) + { + ca[i].re=2*CMath::RandomReal()-1; + ca[i].im=2*CMath::RandomReal()-1; + } + //--- allocation + ArrayResize(cb,n); + for(i=0;i<=n-1;i++) + { + cb[i].re=2*CMath::RandomReal()-1; + cb[i].im=2*CMath::RandomReal()-1; + } + //--- allocation + ArrayResize(cr1,1); + //--- function calls + CCorr::CorrC1D(ca,m,cb,n,cr1); + RefCorrC1D(ca,m,cb,n,cr2); + //--- search errors + for(i=0;i<=m+n-2;i++) + referr=MathMax(referr,CMath::AbsComplex(cr1[i]-cr2[i])); + //--- allocation + ArrayResize(cr1,1); + //--- function calls + CCorr::CorrC1DCircular(ca,m,cb,n,cr1); + RefCorrC1DCircular(ca,m,cb,n,cr2); + //--- search errors + for(i=0;i<=m-1;i++) + referr=MathMax(referr,CMath::AbsComplex(cr1[i]-cr2[i])); + //--- Real correlation + ArrayResize(ra,m); + for(i=0;i<=m-1;i++) + ra[i]=2*CMath::RandomReal()-1; + //--- allocation + ArrayResize(rb,n); + for(i=0;i<=n-1;i++) + rb[i]=2*CMath::RandomReal()-1; + //--- allocation + ArrayResize(rr1,1); + //--- function calls + CCorr::CorrR1D(ra,m,rb,n,rr1); + RefCorrR1D(ra,m,rb,n,rr2); + //--- search errors + for(i=0;i<=m+n-2;i++) + refrerr=MathMax(refrerr,MathAbs(rr1[i]-rr2[i])); + //--- allocation + ArrayResize(rr1,1); + //--- function calls + CCorr::CorrR1DCircular(ra,m,rb,n,rr1); + RefCorrR1DCircular(ra,m,rb,n,rr2); + //--- search errors + for(i=0;i<=m-1;i++) + refrerr=MathMax(refrerr,MathAbs(rr1[i]-rr2[i])); + } + } +//--- search errors + referrors=referrors || referr>errtol; + refrerrors=refrerrors || refrerr>errtol; +//--- end + waserrors=referrors || refrerrors; +//--- check + if(!silent) + { + Print("TESTING CORRELATION"); + Print("FINAL RESULT: "); + //--- check + if(waserrors) + Print("FAILED"); + else + Print("OK"); + Print("* AGAINST REFERENCE COMPLEX CORR: "); + //--- check + if(referrors) + Print("FAILED"); + else + Print("OK"); + Print("* AGAINST REFERENCE REAL CORR: "); + //--- check + if(refrerrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Reference implementation | +//+------------------------------------------------------------------+ +static void CTestCorrUnit::RefCorrC1D(complex &signal[],const int n, + complex &pattern[],const int m, + complex &r[]) + { +//--- create variables + int i=0; + int j=0; + complex v=0; + int i_=0; +//--- create array + complex s[]; +//--- allocation + ArrayResize(s,m+n-1); +//--- change values + for(i_=0;i_<=n-1;i_++) + s[i_]=signal[i_]; + for(i=n;i<=m+n-2;i++) + s[i]=0; +//--- allocation + ArrayResize(r,m+n-1); +//--- calculation + for(i=0;i<=n-1;i++) + { + v=0; + for(j=0;j<=m-1;j++) + { + //--- check + if(i+j>=n) + break; + v=v+CMath::Conj(pattern[j])*s[i+j]; + } + r[i]=v; + } +//--- calculation + for(i=1;i<=m-1;i++) + { + v=0; + for(j=i;j<=m-1;j++) + v=v+CMath::Conj(pattern[j])*s[j-i]; + r[m+n-1-i]=v; + } + } +//+------------------------------------------------------------------+ +//| Reference implementation | +//+------------------------------------------------------------------+ +static void CTestCorrUnit::RefCorrC1DCircular(complex &signal[],const int n, + complex &pattern[],const int m, + complex &r[]) + { +//--- create variables + int i=0; + int j=0; + complex v=0; +//--- allocation + ArrayResize(r,n); +//--- calculation + for(i=0;i<=n-1;i++) + { + //--- change value + v=0; + for(j=0;j<=m-1;j++) + v=v+CMath::Conj(pattern[j])*signal[(i+j)%n]; + r[i]=v; + } + } +//+------------------------------------------------------------------+ +//| Reference implementation | +//+------------------------------------------------------------------+ +static void CTestCorrUnit::RefCorrR1D(double &signal[],const int n, + double &pattern[],const int m, + double &r[]) + { +//--- create variables + int i=0; + int j=0; + double v=0; + int i_=0; +//--- create array + double s[]; +//--- allocation + ArrayResize(s,m+n-1); +//--- change values + for(i_=0;i_<=n-1;i_++) + s[i_]=signal[i_]; + for(i=n;i<=m+n-2;i++) + s[i]=0; +//--- allocation + ArrayResize(r,m+n-1); +//--- calculation + for(i=0;i<=n-1;i++) + { + v=0; + for(j=0;j<=m-1;j++) + { + //--- check + if(i+j>=n) + break; + v=v+pattern[j]*s[i+j]; + } + r[i]=v; + } +//--- calculation + for(i=1;i<=m-1;i++) + { + v=0; + for(j=i;j<=m-1;j++) + v=v+pattern[j]*s[-i+j]; + r[m+n-1-i]=v; + } + } +//+------------------------------------------------------------------+ +//| Reference implementation | +//+------------------------------------------------------------------+ +static void CTestCorrUnit::RefCorrR1DCircular(double &signal[],const int n, + double &pattern[],const int m, + double &r[]) + { +//--- create variables + int i=0; + int j=0; + double v=0; +//--- allocation + ArrayResize(r,n); +//--- calculation + for(i=0;i<=n-1;i++) + { + v=0; + for(j=0;j<=m-1;j++) + v=v+pattern[j]*signal[(i+j)%n]; + r[i]=v; + } + } +//+------------------------------------------------------------------+ +//| Reference implementation | +//+------------------------------------------------------------------+ +static void CTestCorrUnit::RefConvC1D(complex &a[],const int m,complex &b[], + const int n,complex &r[]) + { +//--- create variables + int i=0; + complex v=0; + int i_=0; + int i1_=0; +//--- allocation + ArrayResize(r,m+n-1); +//--- initialization + for(i=0;i<=m+n-2;i++) + r[i]=0; +//--- calculation + for(i=0;i<=m-1;i++) + { + v=a[i]; + i1_=-i; + for(i_=i;i_<=i+n-1;i_++) + r[i_]=r[i_]+v*b[i_+i1_]; + } + } +//+------------------------------------------------------------------+ +//| Reference implementation | +//+------------------------------------------------------------------+ +static void CTestCorrUnit::RefConvC1DCircular(complex &a[],const int m, + complex &b[],const int n, + complex &r[]) + { +//--- create variables + int i1=0; + int i2=0; + int j2=0; + int i_=0; + int i1_=0; +//--- create array + complex buf[]; +//--- function call + RefConvC1D(a,m,b,n,buf); +//--- allocation + ArrayResize(r,m); +//--- copy + for(i_=0;i_<=m-1;i_++) + r[i_]=buf[i_]; +//--- calculation + i1=m; + while(i1<=m+n-2) + { + //--- change values + i2=MathMin(i1+m-1,m+n-2); + j2=i2-i1; + i1_=i1; + for(i_=0;i_<=j2;i_++) + r[i_]=r[i_]+buf[i_+i1_]; + i1=i1+m; + } + } +//+------------------------------------------------------------------+ +//| Reference FFT | +//+------------------------------------------------------------------+ +static void CTestCorrUnit::RefConvR1D(double &a[],const int m,double &b[], + const int n,double &r[]) + { +//--- create variables + int i=0; + double v=0; + int i_=0; + int i1_=0; +//--- allocation + ArrayResize(r,m+n-1); +//--- initialization + for(i=0;i<=m+n-2;i++) + r[i]=0; +//--- calculation + for(i=0;i<=m-1;i++) + { + v=a[i]; + i1_=-i; + for(i_=i;i_<=i+n-1;i_++) + r[i_]=r[i_]+v*b[i_+i1_]; + } + } +//+------------------------------------------------------------------+ +//| Reference implementation | +//+------------------------------------------------------------------+ +static void CTestCorrUnit::RefConvR1DCircular(double &a[],const int m, + double &b[],const int n, + double &r[]) + { +//--- create variables + int i1=0; + int i2=0; + int j2=0; + int i_=0; + int i1_=0; +//--- create array + double buf[]; +//--- function call + RefConvR1D(a,m,b,n,buf); +//--- allocation + ArrayResize(r,m); +//--- copy + for(i_=0;i_<=m-1;i_++) + r[i_]=buf[i_]; +//--- calculation + i1=m; + while(i1<=m+n-2) + { + //--- change values + i2=MathMin(i1+m-1,m+n-2); + j2=i2-i1; + i1_=i1; + for(i_=0;i_<=j2;i_++) + r[i_]=r[i_]+buf[i_+i1_]; + i1=i1+m; + } + } +//+------------------------------------------------------------------+ +//| Testing class CFastHartleyTransform | +//+------------------------------------------------------------------+ +class CTestFHTUnit + { +private: + //--- private methods + static void RefFHTR1D(double &a[],const int n); + static void RefFHTR1DInv(double &a[],const int n); +public: + //--- constructor, destructor + CTestFHTUnit(void); + ~CTestFHTUnit(void); + //--- public method + static bool TestFHT(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestFHTUnit::CTestFHTUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestFHTUnit::~CTestFHTUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Test | +//+------------------------------------------------------------------+ +static bool CTestFHTUnit::TestFHT(const bool silent) + { +//--- create variables + int n=0; + int i=0; + int maxn=0; + double bidierr=0; + double referr=0; + double errtol=0; + bool referrors; + bool bidierrors; + bool waserrors; +//--- create arrays + double r1[]; + double r2[]; + double r3[]; +//--- initialization + maxn=128; + errtol=100000*MathPow(maxn,3.0/2.0)*CMath::m_machineepsilon; + bidierrors=false; + referrors=false; + waserrors=false; +//--- Test bi-directional error: norm(x-invFHT(FHT(x))) + bidierr=0; + for(n=1;n<=maxn;n++) + { + //--- FHT/invFHT + ArrayResize(r1,n); + ArrayResize(r2,n); + ArrayResize(r3,n); + for(i=0;i<=n-1;i++) + { + r1[i]=2*CMath::RandomReal()-1; + r2[i]=r1[i]; + r3[i]=r1[i]; + } + //--- function calls + CFastHartleyTransform::FHTR1D(r2,n); + CFastHartleyTransform::FHTR1DInv(r2,n); + CFastHartleyTransform::FHTR1DInv(r3,n); + CFastHartleyTransform::FHTR1D(r3,n); + //--- search errors + for(i=0;i<=n-1;i++) + { + bidierr=MathMax(bidierr,MathAbs(r1[i]-r2[i])); + bidierr=MathMax(bidierr,MathAbs(r1[i]-r3[i])); + } + } +//--- search errors + bidierrors=bidierrors || bidierr>errtol; +//--- Test against reference O(N^2) implementation + referr=0; + for(n=1;n<=maxn;n++) + { + //--- FHT + ArrayResize(r1,n); + ArrayResize(r2,n); + for(i=0;i<=n-1;i++) + { + r1[i]=2*CMath::RandomReal()-1; + r2[i]=r1[i]; + } + //--- function calls + CFastHartleyTransform::FHTR1D(r1,n); + RefFHTR1D(r2,n); + //--- search errors + for(i=0;i<=n-1;i++) + referr=MathMax(referr,MathAbs(r1[i]-r2[i])); + //--- inverse FHT + ArrayResize(r1,n); + ArrayResize(r2,n); + for(i=0;i<=n-1;i++) + { + r1[i]=2*CMath::RandomReal()-1; + r2[i]=r1[i]; + } + //--- function calls + CFastHartleyTransform::FHTR1DInv(r1,n); + RefFHTR1DInv(r2,n); + //--- search errors + for(i=0;i<=n-1;i++) + referr=MathMax(referr,MathAbs(r1[i]-r2[i])); + } +//--- search errors + referrors=referrors || referr>errtol; +//--- end + waserrors=bidierrors || referrors; +//--- check + if(!silent) + { + Print("TESTING FHT"); + Print("FINAL RESULT: "); + //--- check + if(waserrors) + Print("FAILED"); + else + Print("OK"); + Print("* BI-DIRECTIONAL TEST: "); + //--- check + if(bidierrors) + Print("FAILED"); + else + Print("OK"); + Print("* AGAINST REFERENCE FHT: "); + //--- check + if(referrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Reference FHT | +//+------------------------------------------------------------------+ +static void CTestFHTUnit::RefFHTR1D(double &a[],const int n) + { +//--- create variables + int i=0; + int j=0; + double v=0; +//--- create array + double buf[]; +//--- check + if(!CAp::Assert(n>0,"RefFHTR1D: incorrect N!")) + return; +//--- allocation + ArrayResize(buf,n); +//--- calculation + for(i=0;i<=n-1;i++) + { + v=0; + for(j=0;j<=n-1;j++) + v=v+a[j]*(MathCos(2*M_PI*i*j/n)+MathSin(2*M_PI*i*j/n)); + buf[i]=v; + } +//--- copy + for(i=0;i<=n-1;i++) + a[i]=buf[i]; + } +//+------------------------------------------------------------------+ +//| Reference inverse FHT | +//+------------------------------------------------------------------+ +static void CTestFHTUnit::RefFHTR1DInv(double &a[],const int n) + { +//--- create a variable + int i=0; +//--- check + if(!CAp::Assert(n>0,"RefFHTR1DInv: incorrect N!")) + return; +//--- function call + RefFHTR1D(a,n); +//--- change values + for(i=0;i<=n-1;i++) + a[i]=a[i]/n; + } +//+------------------------------------------------------------------+ +//| Testing class CGaussQ | +//+------------------------------------------------------------------+ +class CTestGQUnit + { +private: + //--- private methods + static double MapKind(const int k); + static void BuildGaussLegendreQuadrature(const int n,double &x[],double &w[]); + static void BuildGaussJacobiQuadrature(const int n,const double alpha,const double beta,double &x[],double &w[]); + static void BuildGaussLaguerreQuadrature(const int n,const double alpha,double &x[],double &w[]); + static void BuildGaussHermiteQuadrature(const int n,double &x[],double &w[]); +public: + //--- constructor, destructor + CTestGQUnit(void); + ~CTestGQUnit(void); + //--- public method + static bool TestGQ(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestGQUnit::CTestGQUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestGQUnit::~CTestGQUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Test | +//+------------------------------------------------------------------+ +static bool CTestGQUnit::TestGQ(const bool silent) + { +//--- create variables + double err=0; + int n=0; + int i=0; + int info=0; + int akind=0; + int bkind=0; + double alphac=0; + double betac=0; + double errtol=0; + double nonstricterrtol=0; + double stricterrtol=0; + bool recerrors; + bool specerrors; + bool waserrors; +//--- create arrays + double alpha[]; + double beta[]; + double x[]; + double w[]; + double x2[]; + double w2[]; +//--- initialization + recerrors=false; + specerrors=false; + waserrors=false; + errtol=1.0E-12; + nonstricterrtol=1.0E-6; + stricterrtol=1000*CMath::m_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=0; + ArrayResize(alpha,2); + ArrayResize(beta,2); + alpha[0]=0; + alpha[1]=0; + beta[1]=1.0/(double)(4*1*1-1); +//--- function call + CGaussQ::GQGenerateRec(alpha,beta,2.0,2,info,x,w); +//--- check + if(info>0) + { + //--- search errors + err=MathMax(err,MathAbs(x[0]+MathSqrt(3)/3)); + err=MathMax(err,MathAbs(x[1]-MathSqrt(3)/3)); + err=MathMax(err,MathAbs(w[0]-1)); + err=MathMax(err,MathAbs(w[1]-1)); + for(i=0;i<=0;i++) + recerrors=recerrors || x[i]>=x[i+1]; + } + else + recerrors=true; +//--- allocation + ArrayResize(alpha,5); + ArrayResize(beta,5); +//--- change values + alpha[0]=0; + for(i=1;i<=4;i++) + { + alpha[i]=0; + beta[i]=CMath::Sqr(i)/(4*CMath::Sqr(i)-1); + } +//--- function call + CGaussQ::GQGenerateRec(alpha,beta,2.0,5,info,x,w); +//--- check + if(info>0) + { + //--- search errors + err=MathMax(err,MathAbs(x[0]+MathSqrt(245+14*MathSqrt(70))/21)); + err=MathMax(err,MathAbs(x[0]+x[4])); + err=MathMax(err,MathAbs(x[1]+MathSqrt(245-14*MathSqrt(70))/21)); + err=MathMax(err,MathAbs(x[1]+x[3])); + err=MathMax(err,MathAbs(x[2])); + err=MathMax(err,MathAbs(w[0]-(322-13*MathSqrt(70))/900)); + err=MathMax(err,MathAbs(w[0]-w[4])); + err=MathMax(err,MathAbs(w[1]-(322+13*MathSqrt(70))/900)); + err=MathMax(err,MathAbs(w[1]-w[3])); + err=MathMax(err,MathAbs(w[2]-128.0/225.0)); + for(i=0;i<=3;i++) + recerrors=recerrors || x[i]>=x[i+1]; + } + else + recerrors=true; +//--- calculation + n=1; + while(n<=512) + { + //--- allocation + ArrayResize(alpha,n); + ArrayResize(beta,n); + for(i=0;i<=n-1;i++) + { + alpha[i]=0; + //--- check + if(i==0) + beta[i]=0; + //--- check + if(i==1) + beta[i]=1.0/2.0; + //--- check + if(i>1) + beta[i]=1.0/4.0; + } + //--- function call + CGaussQ::GQGenerateRec(alpha,beta,M_PI,n,info,x,w); + //--- check + if(info>0) + { + //--- search errors + for(i=0;i<=n-1;i++) + { + err=MathMax(err,MathAbs(x[i]-MathCos(M_PI*(n-i-0.5)/n))); + err=MathMax(err,MathAbs(w[i]-M_PI/n)); + } + for(i=0;i<=n-2;i++) + recerrors=recerrors || x[i]>=x[i+1]; + } + else + recerrors=true; + n=n*2; + } +//--- search errors + recerrors=recerrors || 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=0; + ArrayResize(alpha,2); + ArrayResize(beta,2); + alpha[0]=0; + alpha[1]=0; + beta[0]=0; + beta[1]=(double)(1*1)/(double)(4*1*1-1); +//--- function call + CGaussQ::GQGenerateGaussLobattoRec(alpha,beta,2.0,-1,1,3,info,x,w); +//--- check + if(info>0) + { + //--- search errors + err=MathMax(err,MathAbs(x[0]+1)); + err=MathMax(err,MathAbs(x[1])); + err=MathMax(err,MathAbs(x[2]-1)); + err=MathMax(err,MathAbs(w[0]-1.0/3.0)); + err=MathMax(err,MathAbs(w[1]-4.0/3.0)); + err=MathMax(err,MathAbs(w[2]-1.0/3.0)); + for(i=0;i<=1;i++) + recerrors=recerrors || x[i]>=x[i+1]; + } + else + recerrors=true; +//--- allocation + ArrayResize(alpha,3); + ArrayResize(beta,3); +//--- change values + alpha[0]=0; + alpha[1]=0; + alpha[2]=0; + beta[0]=0; + beta[1]=(double)(1*1)/(double)(4*1*1-1); + beta[2]=(double)(2*2)/(double)(4*2*2-1); +//--- function call + CGaussQ::GQGenerateGaussLobattoRec(alpha,beta,2.0,-1,1,4,info,x,w); +//--- check + if(info>0) + { + //--- search errors + err=MathMax(err,MathAbs(x[0]+1)); + err=MathMax(err,MathAbs(x[1]+MathSqrt(5)/5)); + err=MathMax(err,MathAbs(x[2]-MathSqrt(5)/5)); + err=MathMax(err,MathAbs(x[3]-1)); + err=MathMax(err,MathAbs(w[0]-1.0/6.0)); + err=MathMax(err,MathAbs(w[1]-5.0/6.0)); + err=MathMax(err,MathAbs(w[2]-5.0/6.0)); + err=MathMax(err,MathAbs(w[3]-1.0/6.0)); + for(i=0;i<=2;i++) + recerrors=recerrors || x[i]>=x[i+1]; + } + else + recerrors=true; +//--- allocation + ArrayResize(alpha,5); + ArrayResize(beta,5); +//--- change values + alpha[0]=0; + alpha[1]=0; + alpha[2]=0; + alpha[3]=0; + alpha[4]=0; + beta[0]=0; + beta[1]=(double)(1*1)/(double)(4*1*1-1); + beta[2]=(double)(2*2)/(double)(4*2*2-1); + beta[3]=(double)(3*3)/(double)(4*3*3-1); + beta[4]=(double)(4*4)/(double)(4*4*4-1); +//--- function call + CGaussQ::GQGenerateGaussLobattoRec(alpha,beta,2.0,-1,1,6,info,x,w); +//--- check + if(info>0) + { + //--- search errors + err=MathMax(err,MathAbs(x[0]+1)); + err=MathMax(err,MathAbs(x[1]+MathSqrt((7+2*MathSqrt(7))/21))); + err=MathMax(err,MathAbs(x[2]+MathSqrt((7-2*MathSqrt(7))/21))); + err=MathMax(err,MathAbs(x[3]-MathSqrt((7-2*MathSqrt(7))/21))); + err=MathMax(err,MathAbs(x[4]-MathSqrt((7+2*MathSqrt(7))/21))); + err=MathMax(err,MathAbs(x[5]-1)); + err=MathMax(err,MathAbs(w[0]-1.0/(double)15)); + err=MathMax(err,MathAbs(w[1]-(14-MathSqrt(7))/30)); + err=MathMax(err,MathAbs(w[2]-(14+MathSqrt(7))/30)); + err=MathMax(err,MathAbs(w[3]-(14+MathSqrt(7))/30)); + err=MathMax(err,MathAbs(w[4]-(14-MathSqrt(7))/30)); + err=MathMax(err,MathAbs(w[5]-1.0/(double)15)); + for(i=0;i<=4;i++) + recerrors=recerrors || x[i]>=x[i+1]; + } + else + recerrors=true; + recerrors=recerrors || 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=0; + ArrayResize(alpha,1); + ArrayResize(beta,2); + alpha[0]=0; + beta[0]=0; + beta[1]=(double)(1*1)/(double)(4*1*1-1); +//--- function call + CGaussQ::GQGenerateGaussRadauRec(alpha,beta,2.0,-1,2,info,x,w); +//--- check + if(info>0) + { + //--- search errors + err=MathMax(err,MathAbs(x[0]+1)); + err=MathMax(err,MathAbs(x[1]-1.0/3.0)); + err=MathMax(err,MathAbs(w[0]-0.5)); + err=MathMax(err,MathAbs(w[1]-1.5)); + for(i=0;i<=0;i++) + recerrors=recerrors || x[i]>=x[i+1]; + } + else + recerrors=true; +//--- allocation + ArrayResize(alpha,2); + ArrayResize(beta,3); +//--- change values + alpha[0]=0; + alpha[1]=0; + for(i=0;i<=2;i++) + beta[i]=CMath::Sqr(i)/(4*CMath::Sqr(i)-1); +//--- function call + CGaussQ::GQGenerateGaussRadauRec(alpha,beta,2.0,-1,3,info,x,w); +//--- check + if(info>0) + { + //--- search errors + err=MathMax(err,MathAbs(x[0]+1)); + err=MathMax(err,MathAbs(x[1]-(1-MathSqrt(6))/5)); + err=MathMax(err,MathAbs(x[2]-(1+MathSqrt(6))/5)); + err=MathMax(err,MathAbs(w[0]-2.0/9.0)); + err=MathMax(err,MathAbs(w[1]-(16+MathSqrt(6))/18)); + err=MathMax(err,MathAbs(w[2]-(16-MathSqrt(6))/18)); + for(i=0;i<=1;i++) + recerrors=recerrors || x[i]>=x[i+1]; + } + else + recerrors=true; +//--- allocation + ArrayResize(alpha,2); + ArrayResize(beta,3); + alpha[0]=0; + alpha[1]=0; + for(i=0;i<=2;i++) + beta[i]=CMath::Sqr(i)/(4*CMath::Sqr(i)-1); +//--- function call + CGaussQ::GQGenerateGaussRadauRec(alpha,beta,2.0,1,3,info,x,w); +//--- check + if(info>0) + { + //--- search errors + err=MathMax(err,MathAbs(x[2]-1)); + err=MathMax(err,MathAbs(x[1]+(1-MathSqrt(6))/5)); + err=MathMax(err,MathAbs(x[0]+(1+MathSqrt(6))/5)); + err=MathMax(err,MathAbs(w[2]-2.0/9.0)); + err=MathMax(err,MathAbs(w[1]-(16+MathSqrt(6))/18)); + err=MathMax(err,MathAbs(w[0]-(16-MathSqrt(6))/18)); + for(i=0;i<=1;i++) + recerrors=recerrors || x[i]>=x[i+1]; + } + else + recerrors=true; +//--- search errors + recerrors=recerrors || 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=0; + CGaussQ::GQGenerateGaussLegendre(n,info,x,w); + //--- check + if(info>0) + { + BuildGaussLegendreQuadrature(n,x2,w2); + //--- search errors + for(i=0;i<=n-1;i++) + { + err=MathMax(err,MathAbs(x[i]-x2[i])); + err=MathMax(err,MathAbs(w[i]-w2[i])); + } + } + else + specerrors=true; + //--- search errors + specerrors=specerrors || err>errtol; + //--- Test Gauss-Jacobi. + //--- Since task is much more difficult we will use less strict + //--- threshold. + err=0; + for(akind=0;akind<=9;akind++) + { + for(bkind=0;bkind<=9;bkind++) + { + alphac=MapKind(akind); + betac=MapKind(bkind); + //--- function call + CGaussQ::GQGenerateGaussJacobi(n,alphac,betac,info,x,w); + //--- check + if(info>0) + { + BuildGaussJacobiQuadrature(n,alphac,betac,x2,w2); + //--- search errors + for(i=0;i<=n-1;i++) + { + err=MathMax(err,MathAbs(x[i]-x2[i])); + err=MathMax(err,MathAbs(w[i]-w2[i])); + } + } + else + specerrors=true; + } + } + //--- search errors + specerrors=specerrors || err>nonstricterrtol; + //--- special test for Gauss-Jacobi (Chebyshev weight + //--- function with analytically known nodes/weights) + err=0; + CGaussQ::GQGenerateGaussJacobi(n,-0.5,-0.5,info,x,w); + //--- check + if(info>0) + { + //--- search errors + for(i=0;i<=n-1;i++) + { + err=MathMax(err,MathAbs(x[i]+MathCos(M_PI*(i+0.5)/n))); + err=MathMax(err,MathAbs(w[i]-M_PI/n)); + } + } + else + specerrors=true; + //--- search errors + specerrors=specerrors || err>stricterrtol; + //--- Test Gauss-Laguerre + err=0; + for(akind=0;akind<=9;akind++) + { + alphac=MapKind(akind); + //--- function call + CGaussQ::GQGenerateGaussLaguerre(n,alphac,info,x,w); + //--- check + if(info>0) + { + BuildGaussLaguerreQuadrature(n,alphac,x2,w2); + //--- search errors + for(i=0;i<=n-1;i++) + { + err=MathMax(err,MathAbs(x[i]-x2[i])); + err=MathMax(err,MathAbs(w[i]-w2[i])); + } + } + else + specerrors=true; + } + //--- search errors + specerrors=specerrors || err>nonstricterrtol; + //--- Test Gauss-Hermite + err=0; + CGaussQ::GQGenerateGaussHermite(n,info,x,w); + //--- check + if(info>0) + { + BuildGaussHermiteQuadrature(n,x2,w2); + //--- search errors + for(i=0;i<=n-1;i++) + { + err=MathMax(err,MathAbs(x[i]-x2[i])); + err=MathMax(err,MathAbs(w[i]-w2[i])); + } + } + else + specerrors=true; + //--- search errors + specerrors=specerrors || err>nonstricterrtol; + } +//--- end + waserrors=recerrors || specerrors; +//--- check + if(!silent) + { + Print("TESTING GAUSS QUADRATURES"); + Print("FINAL RESULT: "); + //--- check + if(waserrors) + Print("FAILED"); + else + Print("OK"); + Print("* SPECIAL CASES (LEGENDRE/JACOBI/..) "); + //--- check + if(specerrors) + Print("FAILED"); + else + Print("OK"); + Print("* RECURRENCE-BASED: "); + //--- check + if(recerrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| 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 CTestGQUnit::MapKind(const int k) + { +//--- create a variable + double result=0; +//--- check + if(k==0) + result=-0.9; +//--- check + if(k==1) + result=-0.5; +//--- check + if(k==2) + result=-0.1; +//--- check + if(k==3) + result=0.0; +//--- check + if(k==4) + result=0.1; +//--- check + if(k==5) + result=0.5; +//--- check + if(k==6) + result=0.9; +//--- check + if(k==7) + result=1.0; +//--- check + if(k==8) + result=1.5; +//--- check + if(k==9) + result=2.0; +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Gauss-Legendre, another variant | +//+------------------------------------------------------------------+ +static void CTestGQUnit::BuildGaussLegendreQuadrature(const int n,double &x[], + double &w[]) + { +//--- create variables + int i=0; + int j=0; + double r=0; + double r1=0; + double p1=0; + double p2=0; + double p3=0; + double dp3=0; + double tmp=0; +//--- allocation + ArrayResize(x,n); + ArrayResize(w,n); +//--- calculation + for(i=0;i<=(n+1)/2-1;i++) + { + r=MathCos(M_PI*(4*i+3)/(4*n+2)); + //--- cycle + do + { + //--- change values + p2=0; + p3=1; + //--- calculation + 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(MathAbs(r-r1)>=CMath::m_machineepsilon*(1+MathAbs(r))*100); + //--- calculation + x[i]=r; + x[n-1-i]=-r; + w[i]=2/((1-r*r)*dp3*dp3); + w[n-1-i]=2/((1-r*r)*dp3*dp3); + } +//--- shift + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-2-i;j++) + { + //--- check + if(x[j]>=x[j+1]) + { + tmp=x[j]; + x[j]=x[j+1]; + x[j+1]=tmp; + tmp=w[j]; + w[j]=w[j+1]; + w[j+1]=tmp; + } + } + } + } +//+------------------------------------------------------------------+ +//| Gauss-Jacobi, another variant | +//+------------------------------------------------------------------+ +static void CTestGQUnit::BuildGaussJacobiQuadrature(const int n,const double alpha, + const double beta,double &x[], + double &w[]) + { +//--- create variables + int i=0; + int j=0; + double r=0; + double r1=0; + double t1=0; + double t2=0; + double t3=0; + double p1=0; + double p2=0; + double p3=0; + double pp=0; + double an=0; + double bn=0; + double a=0; + double b=0; + double c=0; + double tmpsgn=0; + double tmp=0; + double alfbet=0; + double temp=0; +//--- allocation + ArrayResize(x,n); + ArrayResize(w,n); + for(i=0;i<=n-1;i++) + { + //--- check + if(i==0) + { + //--- calculation + 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 + { + //--- check + if(i==1) + { + //--- calculation + 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*MathAbs(alpha))/n; + r=r-t1*t2*t3*(1-r); + } + else + { + //--- check + if(i==2) + { + //--- calculation + 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[0]-r); + } + else + { + //--- check + if(i=CMath::m_machineepsilon*(1+MathAbs(r))*100); + //--- change values + x[i]=r; + w[i]=MathExp(CGammaFunc::LnGamma(alpha+n,tmpsgn)+CGammaFunc::LnGamma(beta+n,tmpsgn)-CGammaFunc::LnGamma(n+1,tmpsgn)-CGammaFunc::LnGamma(n+alfbet+1,tmpsgn))*temp*MathPow(2,alfbet)/(pp*p2); + } +//--- shift + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-2-i;j++) + { + //--- check + if(x[j]>=x[j+1]) + { + tmp=x[j]; + x[j]=x[j+1]; + x[j+1]=tmp; + tmp=w[j]; + w[j]=w[j+1]; + w[j+1]=tmp; + } + } + } + } +//+------------------------------------------------------------------+ +//| Gauss-Laguerre, another variant | +//+------------------------------------------------------------------+ +static void CTestGQUnit::BuildGaussLaguerreQuadrature(const int n,const double alpha, + double &x[],double &w[]) + { +//--- create variables + int i=0; + int j=0; + double r=0; + double r1=0; + double p1=0; + double p2=0; + double p3=0; + double dp3=0; + double tsg=0; + double tmp=0; +//--- allocation + ArrayResize(x,n); + ArrayResize(w,n); +//--- calculation + for(i=0;i<=n-1;i++) + { + //--- check + if(i==0) + r=(1+alpha)*(3+0.92*alpha)/(1+2.4*n+1.8*alpha); + else + { + //--- check + 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[i-2]); + } + do + { + //--- change values + p2=0; + p3=1; + //--- calculation + 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; + } + //--- change values + while(MathAbs(r-r1)>=CMath::m_machineepsilon*(1+MathAbs(r))*100); + //--- change values + x[i]=r; + w[i]=-(MathExp(CGammaFunc::LnGamma(alpha+n,tsg)-CGammaFunc::LnGamma(n,tsg))/(dp3*n*p2)); + } +//--- shift + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-2-i;j++) + { + //--- check + if(x[j]>=x[j+1]) + { + tmp=x[j]; + x[j]=x[j+1]; + x[j+1]=tmp; + tmp=w[j]; + w[j]=w[j+1]; + w[j+1]=tmp; + } + } + } + } +//+------------------------------------------------------------------+ +//| Gauss-Hermite, another variant | +//+------------------------------------------------------------------+ +static void CTestGQUnit::BuildGaussHermiteQuadrature(const int n,double &x[], + double &w[]) + { +//--- create variables + int i=0; + int j=0; + double r=0; + double r1=0; + double p1=0; + double p2=0; + double p3=0; + double dp3=0; + double pipm4=0; + double tmp=0; +//--- allocation + ArrayResize(x,n); + ArrayResize(w,n); +//--- calculation + pipm4=MathPow(M_PI,-0.25); + for(i=0;i<=(n+1)/2-1;i++) + { + //--- check + if(i==0) + r=MathSqrt(2*n+1)-1.85575*MathPow(2*n+1,-(1.0/6.0)); + else + { + //--- check + if(i==1) + r=r-1.14*MathPow(n,0.426)/r; + else + { + //--- check + if(i==2) + r=1.86*r-0.86*x[0]; + else + { + //--- check + if(i==3) + r=1.91*r-0.91*x[1]; + else + r=2*r-x[i-2]; + } + } + } + //--- cycle + do + { + //--- change values + p2=0; + p3=pipm4; + //--- calculation + for(j=0;j<=n-1;j++) + { + p1=p2; + p2=p3; + p3=p2*r*MathSqrt(2.0/(double)(j+1))-p1*MathSqrt((double)j/(double)(j+1)); + } + dp3=MathSqrt(2*j)*p2; + r1=r; + r=r-p3/dp3; + } + while(MathAbs(r-r1)>=CMath::m_machineepsilon*(1+MathAbs(r))*100); + //--- change values + x[i]=r; + w[i]=2/(dp3*dp3); + x[n-1-i]=-x[i]; + w[n-1-i]=w[i]; + } +//--- shift + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-2-i;j++) + { + //--- check + if(x[j]>=x[j+1]) + { + tmp=x[j]; + x[j]=x[j+1]; + x[j+1]=tmp; + tmp=w[j]; + w[j]=w[j+1]; + w[j+1]=tmp; + } + } + } + } +//+------------------------------------------------------------------+ +//| Testing class CGaussKronrodQ | +//+------------------------------------------------------------------+ +class CTestGKQUnit + { +private: + //--- private method + static double MapKind(const int k); +public: + //--- constructor, destructor + CTestGKQUnit(void); + ~CTestGKQUnit(void); + //--- public method + static bool TestGKQ(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestGKQUnit::CTestGKQUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestGKQUnit::~CTestGKQUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Test | +//+------------------------------------------------------------------+ +static bool CTestGKQUnit::TestGKQ(const bool silent) + { +//--- create variables + int pkind=0; + double errtol=0; + double eps=0; + double nonstricterrtol=0; + int n=0; + int i=0; + int k=0; + int info=0; + double err=0; + int akind=0; + int bkind=0; + double alphac=0; + double betac=0; + int info1=0; + int info2=0; + bool successatleastonce; + bool intblerrors; + bool vstblerrors; + bool generrors; + bool waserrors; +//--- create arrays + double x1[]; + double wg1[]; + double wk1[]; + double x2[]; + double wg2[]; + double wk2[]; +//--- initialization + intblerrors=false; + vstblerrors=false; + generrors=false; + waserrors=false; + errtol=10000*CMath::m_machineepsilon; + nonstricterrtol=1000*errtol; +//--- test recurrence-based Legendre nodes against the precalculated table + for(pkind=0;pkind<=5;pkind++) + { + n=0; + //--- check + if(pkind==0) + n=15; + //--- check + if(pkind==1) + n=21; + //--- check + if(pkind==2) + n=31; + //--- check + if(pkind==3) + n=41; + //--- check + if(pkind==4) + n=51; + //--- check + if(pkind==5) + n=61; + //--- function calls + CGaussKronrodQ::GKQLegendreCalc(n,info,x1,wk1,wg1); + CGaussKronrodQ::GKQLegendreTbl(n,x2,wk2,wg2,eps); + //--- check + if(info<=0) + { + generrors=true; + break; + } + //--- search errors + for(i=0;i<=n-1;i++) + { + vstblerrors=vstblerrors || MathAbs(x1[i]-x2[i])>errtol; + vstblerrors=vstblerrors || MathAbs(wk1[i]-wk2[i])>errtol; + vstblerrors=vstblerrors || MathAbs(wg1[i]-wg2[i])>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=0; + CGaussKronrodQ::GKQGenerateGaussLegendre(n,info1,x1,wk1,wg1); + CGaussQ::GQGenerateGaussLegendre(k,info2,x2,wg2); + //--- check + if(info1>0 && info2>0) + { + //--- search errors + for(i=0;i<=k-1;i++) + { + err=MathMax(err,MathAbs(x1[2*i+1]-x2[i])); + err=MathMax(err,MathAbs(wg1[2*i+1]-wg2[i])); + } + } + else + generrors=true; + //--- search errors + generrors=generrors || err>errtol; + } +//--- calculation + for(k=1;k<=15;k++) + { + n=2*k+1; + //--- Gauss-Jacobi + successatleastonce=false; + err=0; + for(akind=0;akind<=9;akind++) + { + for(bkind=0;bkind<=9;bkind++) + { + //--- change values + alphac=MapKind(akind); + betac=MapKind(bkind); + //--- function calls + CGaussKronrodQ::GKQGenerateGaussJacobi(n,alphac,betac,info1,x1,wk1,wg1); + CGaussQ::GQGenerateGaussJacobi(k,alphac,betac,info2,x2,wg2); + //--- check + if(info1>0 && info2>0) + { + successatleastonce=true; + //--- search errors + for(i=0;i<=k-1;i++) + { + err=MathMax(err,MathAbs(x1[2*i+1]-x2[i])); + err=MathMax(err,MathAbs(wg1[2*i+1]-wg2[i])); + } + } + else + generrors=generrors || info1!=-5; + } + } + //--- search errors + generrors=(generrors || err>errtol) || !successatleastonce; + } +//--- end + waserrors=(intblerrors || vstblerrors) || generrors; +//--- check + if(!silent) + { + Print("TESTING GAUSS-KRONROD QUADRATURES"); + Print("FINAL RESULT: "); + //--- check + if(waserrors) + Print("FAILED"); + else + Print("OK"); + Print("* PRE-CALCULATED TABLE: "); + //--- check + if(intblerrors) + Print("FAILED"); + else + Print("OK"); + Print("* CALCULATED AGAINST THE TABLE: "); + //--- check + if(vstblerrors) + Print("FAILED"); + else + Print("OK"); + Print("* GENERAL PROPERTIES: "); + //--- check + if(generrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| 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 CTestGKQUnit::MapKind(const int k) + { +//--- create variables + double result=0; +//--- check + if(k==0) + result=-0.9; +//--- check + if(k==1) + result=-0.5; +//--- check + if(k==2) + result=-0.1; +//--- check + if(k==3) + result=0.0; +//--- check + if(k==4) + result=0.1; +//--- check + if(k==5) + result=0.5; +//--- check + if(k==6) + result=0.9; +//--- check + if(k==7) + result=1.0; +//--- check + if(k==8) + result=1.5; +//--- check + if(k==9) + result=2.0; +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Testing class CAutoGK | +//+------------------------------------------------------------------+ +class CTestAutoGKUnit + { +public: + //--- constructor, destructor + CTestAutoGKUnit(void); + ~CTestAutoGKUnit(void); + //--- public method + static bool TestAutoGK(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestAutoGKUnit::CTestAutoGKUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestAutoGKUnit::~CTestAutoGKUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Test | +//+------------------------------------------------------------------+ +static bool CTestAutoGKUnit::TestAutoGK(const bool silent) + { +//--- create variables + double a=0; + double b=0; + double v=0; + double exact=0; + double eabs=0; + double alpha=0; + int pkind=0; + double errtol=0; + bool simpleerrors; + bool sngenderrors; + bool waserrors; +//--- objects of classes + CAutoGKState state; + CAutoGKReport rep; +//--- initialization + simpleerrors=false; + sngenderrors=false; + waserrors=false; + errtol=10000*CMath::m_machineepsilon; +//--- Simple test: integral(exp(x),+-1,+-2),no maximum width requirements + a=(2*CMath::RandomInteger(2)-1)*1.0; + b=(2*CMath::RandomInteger(2)-1)*2.0; +//--- function call + CAutoGK::AutoGKSmooth(a,b,state); +//--- cycle + while(CAutoGK::AutoGKIteration(state)) + state.m_f=MathExp(state.m_x); +//--- function call + CAutoGK::AutoGKResults(state,v,rep); +//--- change values + exact=MathExp(b)-MathExp(a); + eabs=MathAbs(MathExp(b)-MathExp(a)); +//--- check + if(rep.m_terminationtype<=0) + simpleerrors=true; + else + simpleerrors=simpleerrors || MathAbs(exact-v)>errtol*eabs; +//--- Simple test: integral(exp(x),+-1,+-2),XWidth=0.1 + a=(2*CMath::RandomInteger(2)-1)*1.0; + b=(2*CMath::RandomInteger(2)-1)*2.0; +//--- function call + CAutoGK::AutoGKSmoothW(a,b,0.1,state); +//--- cycle + while(CAutoGK::AutoGKIteration(state)) + state.m_f=MathExp(state.m_x); +//--- function call + CAutoGK::AutoGKResults(state,v,rep); +//--- change values + exact=MathExp(b)-MathExp(a); + eabs=MathAbs(MathExp(b)-MathExp(a)); +//--- check + if(rep.m_terminationtype<=0) + simpleerrors=true; + else + simpleerrors=simpleerrors || MathAbs(exact-v)>errtol*eabs; +//--- Simple test: integral(cos(100*x),0,2*pi),no maximum width requirements + a=0; + b=2*M_PI; +//--- function call + CAutoGK::AutoGKSmooth(a,b,state); +//--- cycle + while(CAutoGK::AutoGKIteration(state)) + state.m_f=MathCos(100*state.m_x); +//--- function call + CAutoGK::AutoGKResults(state,v,rep); +//--- change values + exact=0; + eabs=4; +//--- check + if(rep.m_terminationtype<=0) + simpleerrors=true; + else + simpleerrors=simpleerrors || MathAbs(exact-v)>errtol*eabs; +//--- Simple test: integral(cos(100*x),0,2*pi),XWidth=0.3 + a=0; + b=2*M_PI; +//--- function call + CAutoGK::AutoGKSmoothW(a,b,0.3,state); +//--- cycle + while(CAutoGK::AutoGKIteration(state)) + state.m_f=MathCos(100*state.m_x); +//--- function call + CAutoGK::AutoGKResults(state,v,rep); +//--- change values + exact=0; + eabs=4; +//--- check + if(rep.m_terminationtype<=0) + simpleerrors=true; + else + simpleerrors=simpleerrors || MathAbs(exact-v)>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; + //--- check + if(pkind==0) + alpha=-0.9; + //--- check + if(pkind==1) + alpha=-0.5; + //--- check + if(pkind==2) + alpha=-0.1; + //--- check + if(pkind==3) + alpha=0.0; + //--- check + if(pkind==4) + alpha=0.1; + //--- check + if(pkind==5) + alpha=0.5; + //--- check + 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=MathPow(b-a,alpha+2)/(alpha+2)+(1+a)*MathPow(b-a,alpha+1)/(alpha+1); + eabs=MathAbs(exact); + //--- function call + CAutoGK::AutoGKSingular(a,b,alpha,0.0,state); + //--- cycle + while(CAutoGK::AutoGKIteration(state)) + { + //--- check + if(state.m_xminusa<0.01) + state.m_f=MathPow(state.m_xminusa,alpha)*(1+state.m_x); + else + state.m_f=MathPow(state.m_x-a,alpha)*(1+state.m_x); + } + //--- function call + CAutoGK::AutoGKResults(state,v,rep); + //--- check + if(rep.m_terminationtype<=0) + sngenderrors=true; + else + sngenderrors=sngenderrors || MathAbs(v-exact)>errtol*eabs; + //--- function call + CAutoGK::AutoGKSingular(b,a,0.0,alpha,state); + //--- cycle + while(CAutoGK::AutoGKIteration(state)) + { + //--- check + if(state.m_bminusx>-0.01) + state.m_f=MathPow(-state.m_bminusx,alpha)*(1+state.m_x); + else + state.m_f=MathPow(state.m_x-a,alpha)*(1+state.m_x); + } + //--- function call + CAutoGK::AutoGKResults(state,v,rep); + //--- check + if(rep.m_terminationtype<=0) + sngenderrors=true; + else + sngenderrors=sngenderrors || MathAbs(-v-exact)>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)*MathPow(b-a,alpha+1)/(alpha+1)-MathPow(b-a,alpha+2)/(alpha+2); + eabs=MathAbs(exact); + //--- function call + CAutoGK::AutoGKSingular(a,b,0.0,alpha,state); + //--- cycle + while(CAutoGK::AutoGKIteration(state)) + { + //--- check + if(state.m_bminusx<0.01) + state.m_f=MathPow(state.m_bminusx,alpha)*(1+state.m_x); + else + state.m_f=MathPow(b-state.m_x,alpha)*(1+state.m_x); + } + //--- function call + CAutoGK::AutoGKResults(state,v,rep); + //--- check + if(rep.m_terminationtype<=0) + sngenderrors=true; + else + sngenderrors=sngenderrors || MathAbs(v-exact)>errtol*eabs; + //--- function call + CAutoGK::AutoGKSingular(b,a,alpha,0.0,state); + //--- cycle + while(CAutoGK::AutoGKIteration(state)) + { + //--- check + if(state.m_xminusa>-0.01) + state.m_f=MathPow(-state.m_xminusa,alpha)*(1+state.m_x); + else + state.m_f=MathPow(b-state.m_x,alpha)*(1+state.m_x); + } + //--- function call + CAutoGK::AutoGKResults(state,v,rep); + //--- check + if(rep.m_terminationtype<=0) + sngenderrors=true; + else + sngenderrors=sngenderrors || MathAbs(-v-exact)>errtol*eabs; + } +//--- end + waserrors=simpleerrors || sngenderrors; +//--- check + if(!silent) + { + Print("TESTING AUTOGK"); + Print("INTEGRATION WITH GIVEN ACCURACY: "); + //--- check + if(simpleerrors || sngenderrors) + Print("FAILED"); + else + Print("OK"); + Print("* SIMPLE PROBLEMS: "); + //--- check + if(simpleerrors) + Print("FAILED"); + else + Print("OK"); + Print("* SINGULAR PROBLEMS (ENDS OF INTERVAL): "); + //--- check + if(sngenderrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Testing class CIDWInt | +//+------------------------------------------------------------------+ +class CTestIDWIntUnit + { +private: + //--- private methods + static void Unset2D(CMatrixComplex &a); + static void Unset1D(double &a[]); + static void TestXY(CMatrixDouble &xy,const int n,const int nx,const int d,const int nq,const int nw,bool &idwerrors); + static void TestRXY(CMatrixDouble &xy,const int n,const int nx,const double r,bool &idwerrors); + static void TestDegree(const int n,const int nx,const int d,const int dtask,bool &idwerrors); + static void TestNoisy(bool &idwerrors); +public: + //--- constructor, destructor + CTestIDWIntUnit(void); + ~CTestIDWIntUnit(void); + //--- public method + static bool TestIDWInt(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestIDWIntUnit::CTestIDWIntUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestIDWIntUnit::~CTestIDWIntUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing IDW interpolation | +//+------------------------------------------------------------------+ +static bool CTestIDWIntUnit::TestIDWInt(const bool silent) + { +//--- create variables + int i=0; + int j=0; + double vx=0; + double vy=0; + double vz=0; + int d=0; + int dtask=0; + int nx=0; + int nq=0; + int nw=0; + int smalln=0; + int largen=0; + bool waserrors; + bool idwerrors; +//--- create matrix + CMatrixDouble xy; +//--- initialization + idwerrors=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++) + { + //--- allocation + xy.Resize(largen,nx+1); + for(i=0;i<=largen-1;i++) + { + for(j=0;j<=nx-1;j++) + xy[i].Set(j,2*CMath::RandomReal()-1); + //--- check + if(nx>=1) + vx=xy[i][0]; + else + vx=0; + //--- check + if(nx>=2) + vy=xy[i][1]; + else + vy=0; + //--- check + if(nx>=3) + vz=xy[i][2]; + else + vz=0; + //--- calculation + xy[i].Set(nx,vx*vx*vx+MathSin(M_PI*vy)*CMath::Sqr(vz)-CMath::Sqr(vx+vy)); + } + for(d=-1;d<=2;d++) + TestXY(xy,largen,nx,d,nq,nw,idwerrors); + } +//--- 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; + xy.Resize(5,nx+1); +//--- change values + xy[0].Set(0,0); + xy[0].Set(1,0); + xy[0].Set(2,2*CMath::RandomReal()-1); + xy[1].Set(0,1); + xy[1].Set(1,0); + xy[1].Set(2,2*CMath::RandomReal()-1); + xy[2].Set(0,0); + xy[2].Set(1,1); + xy[2].Set(2,2*CMath::RandomReal()-1); + xy[3].Set(0,-1); + xy[3].Set(1,0); + xy[3].Set(2,2*CMath::RandomReal()-1); + xy[4].Set(0,0); + xy[4].Set(1,-1); + xy[4].Set(2,2*CMath::RandomReal()-1); +//--- calculation + for(d=-1;d<=2;d++) + TestXY(xy,5,nx,d,nq,nw,idwerrors); +//--- 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++) + { + TestDegree(smalln,nx,d,dtask,idwerrors); + } + } +//--- Noisy test + TestNoisy(idwerrors); +//--- report + waserrors=idwerrors; +//--- check + if(!silent) + { + Print("TESTING INVERSE DISTANCE WEIGHTING"); + Print("* IDW: "); + //--- check + if(!idwerrors) + Print("OK"); + else + Print("FAILED"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Unsets 2D array. | +//+------------------------------------------------------------------+ +static void CTestIDWIntUnit::Unset2D(CMatrixComplex &a) + { +//--- allocation + a.Resize(1,1); +//--- change value + a[0].Set(0,2*CMath::RandomReal()-1); + } +//+------------------------------------------------------------------+ +//| Unsets 1D array. | +//+------------------------------------------------------------------+ +static void CTestIDWIntUnit::Unset1D(double &a[]) + { +//--- allocation + ArrayResize(a,1); +//--- change value + a[0]=2*CMath::RandomReal()-1; + } +//+------------------------------------------------------------------+ +//| Testing IDW: | +//| * generate model using N/NX/D/NQ/NW | +//| * test basic properties | +//+------------------------------------------------------------------+ +static void CTestIDWIntUnit::TestXY(CMatrixDouble &xy,const int n,const int nx, + const int d,const int nq,const int nw, + bool &idwerrors) + { +//--- create variables + double threshold=0; + double lipschitzstep=0; + int i=0; + int i1=0; + int i2=0; + double v=0; + double v1=0; + double v2=0; + double t=0; + double l1=0; + double l2=0; + int i_=0; +//--- create array + double x[]; +//--- object of class + CIDWInterpolant z1; +//--- initialization + threshold=1000*CMath::m_machineepsilon; + lipschitzstep=0.001; +//--- allocation + ArrayResize(x,nx); +//--- build + CIDWInt::IDWBuildModifiedShepard(xy,n,nx,d,nq,nw,z1); +//--- first,test interpolation properties at nodes + for(i=0;i<=n-1;i++) + { + for(i_=0;i_<=nx-1;i_++) + x[i_]=xy[i][i_]; + //--- search errors + idwerrors=idwerrors || CIDWInt::IDWCalc(z1,x)!=xy[i][nx]; + } +//--- test Lipschitz continuity + i1=CMath::RandomInteger(n); + do + { + i2=CMath::RandomInteger(n); + } + while(i2==i1); +//--- change values + l1=0; + t=0; +//--- cycle + while(t<1.0) + { + //--- calculation + v=1-t; + for(i_=0;i_<=nx-1;i_++) + x[i_]=v*xy[i1][i_]; + v=t; + for(i_=0;i_<=nx-1;i_++) + x[i_]=x[i_]+v*xy[i2][i_]; + v1=CIDWInt::IDWCalc(z1,x); + v=1-(t+lipschitzstep); + //--- calculation + for(i_=0;i_<=nx-1;i_++) + x[i_]=v*xy[i1][i_]; + v=t+lipschitzstep; + for(i_=0;i_<=nx-1;i_++) + x[i_]=x[i_]+v*xy[i2][i_]; + v2=CIDWInt::IDWCalc(z1,x); + l1=MathMax(l1,MathAbs(v2-v1)/lipschitzstep); + t=t+lipschitzstep; + } +//--- change values + l2=0; + t=0; +//--- cycle + while(t<1.0) + { + //--- calculation + v=1-t; + for(i_=0;i_<=nx-1;i_++) + x[i_]=v*xy[i1][i_]; + v=t; + for(i_=0;i_<=nx-1;i_++) + x[i_]=x[i_]+v*xy[i2][i_]; + v1=CIDWInt::IDWCalc(z1,x); + v=1-(t+lipschitzstep/3); + //--- calculation + for(i_=0;i_<=nx-1;i_++) + x[i_]=v*xy[i1][i_]; + v=t+lipschitzstep/3; + for(i_=0;i_<=nx-1;i_++) + x[i_]=x[i_]+v*xy[i2][i_]; + v2=CIDWInt::IDWCalc(z1,x); + l2=MathMax(l2,MathAbs(v2-v1)/(lipschitzstep/3)); + t=t+lipschitzstep/3; + } +//--- search errors + idwerrors=idwerrors || l2>2.0*l1; + } +//+------------------------------------------------------------------+ +//| Testing IDW: | +//| * generate model using R-based model | +//| * test basic properties | +//+------------------------------------------------------------------+ +static void CTestIDWIntUnit::TestRXY(CMatrixDouble &xy,const int n,const int nx, + const double r,bool &idwerrors) + { +//--- create variables + double threshold=0; + double lipschitzstep=0; + int i=0; + int i1=0; + int i2=0; + double v=0; + double v1=0; + double v2=0; + double t=0; + double l1=0; + double l2=0; + int i_=0; +//--- create array + double x[]; +//--- object of class + CIDWInterpolant z1; +//--- initialization + threshold=1000*CMath::m_machineepsilon; + lipschitzstep=0.001; +//--- allocation + ArrayResize(x,nx); +//--- build + CIDWInt::IDWBuildModifiedShepardR(xy,n,nx,r,z1); +//--- first,test interpolation properties at nodes + for(i=0;i<=n-1;i++) + { + for(i_=0;i_<=nx-1;i_++) + x[i_]=xy[i][i_]; + //--- search errors + idwerrors=idwerrors || CIDWInt::IDWCalc(z1,x)!=xy[i][nx]; + } +//--- test Lipschitz continuity + i1=CMath::RandomInteger(n); + do + { + i2=CMath::RandomInteger(n); + } + while(i2==i1); +//--- change values + l1=0; + t=0; +//--- cycle + while(t<1.0) + { + //--- calculation + v=1-t; + for(i_=0;i_<=nx-1;i_++) + x[i_]=v*xy[i1][i_]; + v=t; + for(i_=0;i_<=nx-1;i_++) + x[i_]=x[i_]+v*xy[i2][i_]; + v1=CIDWInt::IDWCalc(z1,x); + v=1-(t+lipschitzstep); + //--- calculation + for(i_=0;i_<=nx-1;i_++) + x[i_]=v*xy[i1][i_]; + v=t+lipschitzstep; + for(i_=0;i_<=nx-1;i_++) + x[i_]=x[i_]+v*xy[i2][i_]; + v2=CIDWInt::IDWCalc(z1,x); + l1=MathMax(l1,MathAbs(v2-v1)/lipschitzstep); + t=t+lipschitzstep; + } +//--- change values + l2=0; + t=0; +//--- cycle + while(t<1.0) + { + //--- calculation + v=1-t; + for(i_=0;i_<=nx-1;i_++) + x[i_]=v*xy[i1][i_]; + v=t; + for(i_=0;i_<=nx-1;i_++) + x[i_]=x[i_]+v*xy[i2][i_]; + v1=CIDWInt::IDWCalc(z1,x); + v=1-(t+lipschitzstep/3); + //--- calculation + for(i_=0;i_<=nx-1;i_++) + x[i_]=v*xy[i1][i_]; + v=t+lipschitzstep/3; + for(i_=0;i_<=nx-1;i_++) + x[i_]=x[i_]+v*xy[i2][i_]; + v2=CIDWInt::IDWCalc(z1,x); + l2=MathMax(l2,MathAbs(v2-v1)/(lipschitzstep/3)); + t=t+lipschitzstep/3; + } +//--- search errors + idwerrors=idwerrors || l2>2.0*l1; + } +//+------------------------------------------------------------------+ +//| 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 CTestIDWIntUnit::TestDegree(const int n,const int nx,const int d, + const int dtask,bool &idwerrors) + { +//--- create variables + double threshold=0; + int nq=0; + int nw=0; + int i=0; + int j=0; + double v=0; + double c0=0; + double v1=0; + double v2=0; + int i_=0; +//--- create arrays + double c1[]; + double x[]; +//--- create matrix + CMatrixDouble c2; + CMatrixDouble xy; +//--- object of class + CIDWInterpolant z1; +//--- initialization + threshold=1.0E6*CMath::m_machineepsilon; + nq=2*(nx*nx+nx+1); + nw=10; +//--- check + if(!CAp::Assert(nq<=n,"TestDegree: internal error")) + return; +//--- prepare model + c0=2*CMath::RandomReal()-1; +//--- allocation + ArrayResize(c1,nx); + for(i=0;i<=nx-1;i++) + c1[i]=2*CMath::RandomReal()-1; +//--- allocation + c2.Resize(nx,nx); + for(i=0;i<=nx-1;i++) + { + for(j=i+1;j<=nx-1;j++) + { + c2[i].Set(j,2*CMath::RandomReal()-1); + c2[j].Set(i,c2[i][j]); + } + //--- cycle + do + { + c2[i].Set(i,2*CMath::RandomReal()-1); + } + while(MathAbs(c2[i][i])<=0.3); + } +//--- prepare points + xy.Resize(n,nx+1); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=nx-1;j++) + xy[i].Set(j,4*CMath::RandomReal()-2); + xy[i].Set(nx,c0); + //--- check + if(dtask>=1) + { + //--- change value + v=0.0; + for(i_=0;i_<=nx-1;i_++) + v+=c1[i_]*xy[i][i_]; + xy[i].Set(nx,xy[i][nx]+v); + } + //--- check + if(dtask==2) + { + for(j=0;j<=nx-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=nx-1;i_++) + v+=c2[j][i_]*xy[i][i_]; + xy[i].Set(nx,xy[i][nx]+xy[i][j]*v); + } + } + } +//--- build interpolant,calculate value at random point + CIDWInt::IDWBuildModifiedShepard(xy,n,nx,d,nq,nw,z1); + ArrayResize(x,nx); + for(i=0;i<=nx-1;i++) + x[i]=4*CMath::RandomReal()-2; + v1=CIDWInt::IDWCalc(z1,x); +//--- calculate model value at the same point + v2=c0; +//--- check + if(dtask>=1) + { + //--- change value + v=0.0; + for(i_=0;i_<=nx-1;i_++) + v+=c1[i_]*x[i_]; + v2=v2+v; + } +//--- check + if(dtask==2) + { + for(j=0;j<=nx-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=nx-1;i_++) + v+=c2[j][i_]*x[i_]; + v2=v2+x[j]*v; + } + } +//--- Compare + if(dtask<=d) + idwerrors=idwerrors || MathAbs(v2-v1)>threshold; + else + idwerrors=idwerrors || MathAbs(v2-v1)rms1; + } + } + } +//+------------------------------------------------------------------+ +//| Testing class CRatInt | +//+------------------------------------------------------------------+ +class CTestRatIntUnit + { +private: + //--- private methods + static void PolDiff2(double &x[],double &cf[],int n,double t,double &p,double &dp,double &d2p); + static void BRCunSet(CBarycentricInterpolant &b); + static bool Is1DSolution(const int n,double &y[],double &w[],double c); +public: + //--- constructor, destructor + CTestRatIntUnit(void); + ~CTestRatIntUnit(void); + //--- public method + static bool TestRatInt(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestRatIntUnit::CTestRatIntUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestRatIntUnit::~CTestRatIntUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CRatInt | +//+------------------------------------------------------------------+ +static bool CTestRatIntUnit::TestRatInt(const bool silent) + { +//--- create variables + bool waserrors; + bool bcerrors; + bool nperrors; + double threshold=0; + double lipschitztol=0; + int maxn=0; + int passcount=0; + double h=0; + double s1=0; + double s2=0; + int n=0; + int n2=0; + int i=0; + int j=0; + int k=0; + int d=0; + int pass=0; + double maxerr=0; + double t=0; + double a=0; + double b=0; + double s=0; + double v0=0; + double v1=0; + double v2=0; + double v3=0; + double d0=0; + double d1=0; + double d2=0; +//--- create arrays + double x[]; + double x2[]; + double y[]; + double y2[]; + double w[]; + double w2[]; + double xc[]; + double yc[]; + int dc[]; +//--- objects of classes + CBarycentricInterpolant b1; + CBarycentricInterpolant b2; +//--- initialization + nperrors=false; + bcerrors=false; + waserrors=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*CMath::m_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*CMath::RandomReal()-0.2; + v1=2*CMath::RandomReal()-1; + v2=2*CMath::RandomReal()-1; + v3=2*CMath::RandomReal()-1; + //--- allocation + ArrayResize(x,n); + ArrayResize(y,n); + ArrayResize(w,n); + //--- calculation + for(i=0;i<=n-1;i++) + { + //--- check + if(n==1) + x[i]=0; + else + x[i]=v0*MathCos(i*M_PI/(n-1)); + y[i]=MathSin(v1*x[i])+MathCos(v2*x[i])+MathExp(v3*x[i]); + } + //--- calculation + for(j=0;j<=n-1;j++) + { + w[j]=1; + for(k=0;k<=n-1;k++) + { + //--- check + if(k!=j) + w[j]=w[j]/(x[j]-x[k]); + } + } + //--- function call + CRatInt::BarycentricBuildXYW(x,y,w,n,b1); + //--- unpack,then pack again and compare + BRCunSet(b2); + CRatInt::BarycentricUnpack(b1,n2,x2,y2,w2); + //--- search errors + bcerrors=bcerrors || n2!=n; + //--- function call + CRatInt::BarycentricBuildXYW(x2,y2,w2,n2,b2); + t=2*CMath::RandomReal()-1; + //--- search errors + bcerrors=bcerrors || MathAbs(CRatInt::BarycentricCalc(b1,t)-CRatInt::BarycentricCalc(b2,t))>threshold; + //--- copy,compare + BRCunSet(b2); + CRatInt::BarycentricCopy(b1,b2); + t=2*CMath::RandomReal()-1; + //--- search errors + bcerrors=bcerrors || MathAbs(CRatInt::BarycentricCalc(b1,t)-CRatInt::BarycentricCalc(b2,t))>threshold; + //--- test interpolation properties + for(i=0;i<=n-1;i++) + { + //--- test interpolation at nodes + bcerrors=bcerrors || MathAbs(CRatInt::BarycentricCalc(b1,x[i])-y[i])>threshold*MathAbs(y[i]); + //--- compare with polynomial interpolation + t=2*CMath::RandomReal()-1; + PolDiff2(x,y,n,t,v0,v1,v2); + //--- search errors + bcerrors=bcerrors || MathAbs(CRatInt::BarycentricCalc(b1,t)-v0)>threshold*MathMax(MathAbs(v0),1); + //--- 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=0; + for(j=0;j<=k-1;j++) + { + v1=x[i]+(t-x[i])*j/k; + v2=x[i]+(t-x[i])*(j+1)/k; + s1=MathMax(s1,MathAbs(CRatInt::BarycentricCalc(b1,v2)-CRatInt::BarycentricCalc(b1,v1))/MathAbs(v2-v1)); + } + //--- change values + k=2*k; + s2=0; + for(j=0;j<=k-1;j++) + { + v1=x[i]+(t-x[i])*j/k; + v2=x[i]+(t-x[i])*(j+1)/k; + s2=MathMax(s2,MathAbs(CRatInt::BarycentricCalc(b1,v2)-CRatInt::BarycentricCalc(b1,v1))/MathAbs(v2-v1)); + } + //--- search errors + bcerrors=bcerrors || (s2>lipschitztol*s1 && s1>threshold*k); + } + //--- test differentiation properties + for(i=0;i<=n-1;i++) + { + t=2*CMath::RandomReal()-1; + PolDiff2(x,y,n,t,v0,v1,v2); + d0=0; + d1=0; + d2=0; + //--- function call + CRatInt::BarycentricDiff1(b1,t,d0,d1); + //--- search errors + bcerrors=bcerrors || MathAbs(v0-d0)>threshold*MathMax(MathAbs(v0),1); + bcerrors=bcerrors || MathAbs(v1-d1)>threshold*MathMax(MathAbs(v1),1); + //--- change values + d0=0; + d1=0; + d2=0; + //--- function call + CRatInt::BarycentricDiff2(b1,t,d0,d1,d2); + //--- search errors + bcerrors=bcerrors || MathAbs(v0-d0)>threshold*MathMax(MathAbs(v0),1); + bcerrors=bcerrors || MathAbs(v1-d1)>threshold*MathMax(MathAbs(v1),1); + bcerrors=bcerrors || MathAbs(v2-d2)>MathSqrt(threshold)*MathMax(MathAbs(v2),1); + } + //--- test linear translation + t=2*CMath::RandomReal()-1; + a=2*CMath::RandomReal()-1; + b=2*CMath::RandomReal()-1; + //--- function calls + BRCunSet(b2); + CRatInt::BarycentricCopy(b1,b2); + CRatInt::BarycentricLinTransX(b2,a,b); + //--- search errors + bcerrors=bcerrors || MathAbs(CRatInt::BarycentricCalc(b1,a*t+b)-CRatInt::BarycentricCalc(b2,t))>threshold; + //--- change values + a=0; + b=2*CMath::RandomReal()-1; + //--- function calls + BRCunSet(b2); + CRatInt::BarycentricCopy(b1,b2); + CRatInt::BarycentricLinTransX(b2,a,b); + //--- search errors + bcerrors=bcerrors || MathAbs(CRatInt::BarycentricCalc(b1,a*t+b)-CRatInt::BarycentricCalc(b2,t))>threshold; + //--- change values + a=2*CMath::RandomReal()-1; + b=2*CMath::RandomReal()-1; + //--- function calls + BRCunSet(b2); + CRatInt::BarycentricCopy(b1,b2); + CRatInt::BarycentricLinTransY(b2,a,b); + //--- search errors + bcerrors=bcerrors || MathAbs(a*CRatInt::BarycentricCalc(b1,t)+b-CRatInt::BarycentricCalc(b2,t))>threshold; + } + } +//--- calculation + for(pass=0;pass<=3;pass++) + { + //--- Crash-test: small numbers,large numbers + ArrayResize(x,4); + ArrayResize(y,4); + ArrayResize(w,4); + h=1; + //--- check + if(pass%2==0) + h=100*CMath::m_minrealnumber; + //--- check + if(pass%2==1) + h=0.01*CMath::m_maxrealnumber; + //--- change values + x[0]=0*h; + x[1]=1*h; + x[2]=2*h; + x[3]=3*h; + y[0]=0*h; + y[1]=1*h; + y[2]=2*h; + y[3]=3*h; + w[0]=-(1/(x[1]-x[0])); + w[1]=1*(1/(x[1]-x[0])+1/(x[2]-x[1])); + w[2]=-(1*(1/(x[2]-x[1])+1/(x[3]-x[2]))); + w[3]=1/(x[3]-x[2]); + //--- check + if(pass/2==0) + v0=0; + //--- check + if(pass/2==1) + v0=0.6*h; + //--- function calls + CRatInt::BarycentricBuildXYW(x,y,w,4,b1); + t=CRatInt::BarycentricCalc(b1,v0); + //--- change values + d0=0; + d1=0; + d2=0; + //--- function call + CRatInt::BarycentricDiff1(b1,v0,d0,d1); + //--- search errors + bcerrors=bcerrors || MathAbs(t-v0)>threshold*v0; + bcerrors=bcerrors || MathAbs(d0-v0)>threshold*v0; + bcerrors=bcerrors || MathAbs(d1-1)>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. + ArrayResize(x,4); + ArrayResize(y,4); + ArrayResize(w,4); +//--- change values + h=0.01*CMath::m_maxrealnumber; + x[0]=0*h; + x[1]=1*h; + x[2]=2*h; + x[3]=3*h; + y[0]=0*h; + y[1]=1*h; + y[2]=2*h; + y[3]=3*h; + w[0]=-(1/(x[1]-x[0])); + w[1]=1*(1/(x[1]-x[0])+1/(x[2]-x[1])); + w[2]=-(1*(1/(x[2]-x[1])+1/(x[3]-x[2]))); + w[3]=1/(x[3]-x[2]); + v0=100*CMath::m_minrealnumber; +//--- function call + CRatInt::BarycentricBuildXYW(x,y,w,4,b1); + t=CRatInt::BarycentricCalc(b1,v0); +//--- change values + d0=0; + d1=0; + d2=0; +//--- function call + CRatInt::BarycentricDiff1(b1,v0,d0,d1); +//--- search errors + bcerrors=bcerrors || MathAbs(t)>v0*(1+threshold); + bcerrors=bcerrors || MathAbs(d0)>v0*(1+threshold); + bcerrors=bcerrors || MathAbs(d1-1)>1000*threshold; +//--- crash test: test safe barycentric formula + ArrayResize(x,4); + ArrayResize(y,4); + ArrayResize(w,4); +//--- change values + h=2*CMath::m_minrealnumber; + x[0]=0*h; + x[1]=1*h; + x[2]=2*h; + x[3]=3*h; + y[0]=0*h; + y[1]=1*h; + y[2]=2*h; + y[3]=3*h; + w[0]=-(1/(x[1]-x[0])); + w[1]=1*(1/(x[1]-x[0])+1/(x[2]-x[1])); + w[2]=-(1*(1/(x[2]-x[1])+1/(x[3]-x[2]))); + w[3]=1/(x[3]-x[2]); + v0=CMath::m_minrealnumber; +//--- function calls + CRatInt::BarycentricBuildXYW(x,y,w,4,b1); + t=CRatInt::BarycentricCalc(b1,v0); +//--- search errors + bcerrors=bcerrors || MathAbs(t-v0)/v0>threshold; +//--- Testing "No Poles" interpolation + maxerr=0; + for(pass=1;pass<=passcount-1;pass++) + { + //--- allocation + ArrayResize(x,1); + ArrayResize(y,1); + x[0]=2*CMath::RandomReal()-1; + y[0]=2*CMath::RandomReal()-1; + //--- function call + CRatInt::BarycentricBuildFloaterHormann(x,y,1,1,b1); + //--- search errors + maxerr=MathMax(maxerr,MathAbs(CRatInt::BarycentricCalc(b1,2*CMath::RandomReal()-1)-y[0])); + } +//--- calculation + for(n=2;n<=10;n++) + { + //--- compare interpolant built by subroutine + //--- with interpolant built by hands + ArrayResize(x,n); + ArrayResize(y,n); + ArrayResize(w,n); + ArrayResize(w2,n); + //--- D=1,non-equidistant nodes + for(pass=1;pass<=passcount;pass++) + { + //--- Initialize X,Y,W + a=-1-1*CMath::RandomReal(); + b=1+1*CMath::RandomReal(); + for(i=0;i<=n-1;i++) + x[i]=MathArctan((b-a)*i/(n-1)+a); + for(i=0;i<=n-1;i++) + y[i]=2*CMath::RandomReal()-1; + w[0]=-(1/(x[1]-x[0])); + s=1; + //--- calculation + for(i=1;i<=n-2;i++) + { + w[i]=s*(1/(x[i]-x[i-1])+1/(x[i+1]-x[i])); + s=-s; + } + w[n-1]=s/(x[n-1]-x[n-2]); + //--- calculation + for(i=0;i<=n-1;i++) + { + k=CMath::RandomInteger(n); + //--- check + if(k!=i) + { + t=x[i]; + x[i]=x[k]; + x[k]=t; + t=y[i]; + y[i]=y[k]; + y[k]=t; + t=w[i]; + w[i]=w[k]; + w[k]=t; + } + } + //--- Build and test + CRatInt::BarycentricBuildFloaterHormann(x,y,n,1,b1); + CRatInt::BarycentricBuildXYW(x,y,w,n,b2); + //--- search errors + for(i=1;i<=2*n;i++) + { + t=a+(b-a)*CMath::RandomReal(); + maxerr=MathMax(maxerr,MathAbs(CRatInt::BarycentricCalc(b1,t)-CRatInt::BarycentricCalc(b2,t))); + } + } + //--- 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*CMath::RandomReal(); + b=1+1*CMath::RandomReal(); + for(i=0;i<=n-1;i++) + x[i]=(b-a)*i/(n-1)+a; + for(i=0;i<=n-1;i++) + y[i]=2*CMath::RandomReal()-1; + s=1; + //--- check + if(d==0) + { + for(i=0;i<=n-1;i++) + { + w[i]=s; + s=-s; + } + } + //--- check + if(d==1) + { + w[0]=-s; + for(i=1;i<=n-2;i++) + { + w[i]=2*s; + s=-s; + } + w[n-1]=s; + } + //--- check + if(d==2) + { + //--- calculation + w[0]=s; + w[1]=-(3*s); + for(i=2;i<=n-3;i++) + { + w[i]=4*s; + s=-s; + } + w[n-2]=3*s; + w[n-1]=-s; + } + //--- Mix + for(i=0;i<=n-1;i++) + { + k=CMath::RandomInteger(n); + //--- check + if(k!=i) + { + t=x[i]; + x[i]=x[k]; + x[k]=t; + t=y[i]; + y[i]=y[k]; + y[k]=t; + t=w[i]; + w[i]=w[k]; + w[k]=t; + } + } + //--- Build and test + CRatInt::BarycentricBuildFloaterHormann(x,y,n,d,b1); + CRatInt::BarycentricBuildXYW(x,y,w,n,b2); + //--- search errors + for(i=1;i<=2*n;i++) + { + t=a+(b-a)*CMath::RandomReal(); + maxerr=MathMax(maxerr,MathAbs(CRatInt::BarycentricCalc(b1,t)-CRatInt::BarycentricCalc(b2,t))); + } + } + } + } +//--- check + if(maxerr>threshold) + nperrors=true; +//--- report + waserrors=bcerrors || nperrors; +//--- check + if(!silent) + { + Print("TESTING RATIONAL INTERPOLATION"); + Print("BASIC BARYCENTRIC FUNCTIONS: "); + //--- check + if(bcerrors) + Print("FAILED"); + else + Print("OK"); + Print("FLOATER-HORMANN: "); + //--- check + if(nperrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- end + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestRatIntUnit::PolDiff2(double &x[],double &cf[],int n, + double t,double &p,double &dp, + double &d2p) + { +//--- create variables + int m=0; + int i=0; +//--- create arrays + double df[]; + double d2f[]; + double f[]; +//--- copy + ArrayCopy(f,cf); +//--- change values + p=0; + dp=0; + d2p=0; + n=n-1; +//--- allocation + ArrayResize(df,n+1); + ArrayResize(d2f,n+1); + for(i=0;i<=n;i++) + { + d2f[i]=0; + df[i]=0; + } +//--- calculation + for(m=1;m<=n;m++) + { + for(i=0;i<=n-m;i++) + { + d2f[i]=((t-x[i+m])*d2f[i]+(x[i]-t)*d2f[i+1]+2*df[i]-2*df[i+1])/(x[i]-x[i+m]); + df[i]=((t-x[i+m])*df[i]+f[i]+(x[i]-t)*df[i+1]-f[i+1])/(x[i]-x[i+m]); + f[i]=((t-x[i+m])*f[i]+(x[i]-t)*f[i+1])/(x[i]-x[i+m]); + } + } +//--- change values + p=f[0]; + dp=df[0]; + d2p=d2f[0]; + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestRatIntUnit::BRCunSet(CBarycentricInterpolant &b) + { +//--- create arrays + double x[]; + double y[]; + double w[]; +//--- allocation + ArrayResize(x,1); + ArrayResize(y,1); + ArrayResize(w,1); +//--- change values + x[0]=0; + y[0]=0; + w[0]=1; +//--- function call + CRatInt::BarycentricBuildXYW(x,y,w,1,b); + } +//+------------------------------------------------------------------+ +//| Tests whether constant C is solution of 1D LLS problem | +//+------------------------------------------------------------------+ +static bool CTestRatIntUnit::Is1DSolution(const int n,double &y[], + double &w[],double c) + { +//--- create variables + bool result; + int i=0; + double s1=0; + double s2=0; + double s3=0; + double delta=0; +//--- initialization + delta=0.001; +//--- Test result + s1=0; + for(i=0;i<=n-1;i++) + s1=s1+CMath::Sqr(w[i]*(c-y[i])); +//--- calculation + s2=0; + s3=0; + for(i=0;i<=n-1;i++) + { + s2=s2+CMath::Sqr(w[i]*(c+delta-y[i])); + s3=s3+CMath::Sqr(w[i]*(c-delta-y[i])); + } + result=s2>=s1 && s3>=s1; +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Testing class CPolInt | +//+------------------------------------------------------------------+ +class CTestPolIntUnit + { +private: + //--- private methods + static double InternalPolInt(double &x[],double &cf[],int n,const double t); + static void BRCunSet(CBarycentricInterpolant &b); +public: + //--- constructor, destructor + CTestPolIntUnit(void); + ~CTestPolIntUnit(void); + //--- public method + static bool TestPolInt(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestPolIntUnit::CTestPolIntUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestPolIntUnit::~CTestPolIntUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Unit test | +//+------------------------------------------------------------------+ +static bool CTestPolIntUnit::TestPolInt(const bool silent) + { +//--- create variables + bool waserrors; + bool interrors; + double threshold=0; + double a=0; + double b=0; + double t=0; + int i=0; + int k=0; + double v=0; + double v0=0; + double v1=0; + double v2=0; + double v3=0; + double v4=0; + double pscale=0; + double poffset=0; + int n=0; + int maxn=0; + int pass=0; + int passcount=0; +//--- create arrays + double x[]; + double y[]; + double w[]; + double c[]; + double x2[]; + double y2[]; + double w2[]; + double xfull[]; + double yfull[]; + double xc[]; + double yc[]; + int dc[]; +//--- objects of classes + CBarycentricInterpolant p; + CBarycentricInterpolant p1; + CBarycentricInterpolant p2; +//--- initialization + waserrors=false; + interrors=false; + maxn=5; + passcount=20; + threshold=1.0E8*CMath::m_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*CMath::RandomReal()-1; + b=2*CMath::RandomReal()-1; + } + while(MathAbs(a-b)<=0.2); + //--- change value + t=a+(1.2*CMath::RandomReal()-0.1)*(b-a); + //--- function call + CApServ::TaskGenInt1DEquidist(a,b,n,x,y); + //--- test "fast" equidistant interpolation (no barycentric model) + interrors=interrors || MathAbs(CPolInt::PolynomialCalcEqDist(a,b,y,n,t)-InternalPolInt(x,y,n,t))>threshold; + //--- test "slow" equidistant interpolation (create barycentric model) + BRCunSet(p); + CPolInt::PolynomialBuild(x,y,n,p); + //--- search errors + interrors=interrors || MathAbs(CRatInt::BarycentricCalc(p,t)-InternalPolInt(x,y,n,t))>threshold; + //--- test "fast" interpolation (create "fast" barycentric model) + BRCunSet(p); + CPolInt::PolynomialBuildEqDist(a,b,y,n,p); + //--- search errors + interrors=interrors || MathAbs(CRatInt::BarycentricCalc(p,t)-InternalPolInt(x,y,n,t))>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*CMath::RandomReal()-1; + b=2*CMath::RandomReal()-1; + } + while(MathAbs(a-b)<=0.2); + //--- change value + t=a+(1.2*CMath::RandomReal()-0.1)*(b-a); + //--- function call + CApServ::TaskGenInt1DCheb1(a,b,n,x,y); + //--- test "fast" interpolation (no barycentric model) + interrors=interrors || MathAbs(CPolInt::PolynomialCalcCheb1(a,b,y,n,t)-InternalPolInt(x,y,n,t))>threshold; + //--- test "slow" interpolation (create barycentric model) + BRCunSet(p); + CPolInt::PolynomialBuild(x,y,n,p); + //--- search errors + interrors=interrors || MathAbs(CRatInt::BarycentricCalc(p,t)-InternalPolInt(x,y,n,t))>threshold; + //--- test "fast" interpolation (create "fast" barycentric model) + BRCunSet(p); + CPolInt::PolynomialBuildCheb1(a,b,y,n,p); + //--- search errors + interrors=interrors || MathAbs(CRatInt::BarycentricCalc(p,t)-InternalPolInt(x,y,n,t))>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*CMath::RandomReal()-1; + b=2*CMath::RandomReal()-1; + } + while(MathAbs(a-b)<=0.2); + //--- change value + t=a+(1.2*CMath::RandomReal()-0.1)*(b-a); + //--- function call + CApServ::TaskGenInt1DCheb2(a,b,n,x,y); + //--- test "fast" interpolation (no barycentric model) + interrors=interrors || MathAbs(CPolInt::PolynomialCalcCheb2(a,b,y,n,t)-InternalPolInt(x,y,n,t))>threshold; + //--- test "slow" interpolation (create barycentric model) + BRCunSet(p); + CPolInt::PolynomialBuild(x,y,n,p); + //--- search errors + interrors=interrors || MathAbs(CRatInt::BarycentricCalc(p,t)-InternalPolInt(x,y,n,t))>threshold; + //--- test "fast" interpolation (create "fast" barycentric model) + BRCunSet(p); + CPolInt::PolynomialBuildCheb2(a,b,y,n,p); + //--- search errors + interrors=interrors || MathAbs(CRatInt::BarycentricCalc(p,t)-InternalPolInt(x,y,n,t))>threshold; + } + } +//--- Testing conversion Barycentric<->Chebyshev + for(pass=1;pass<=passcount;pass++) + { + for(k=1;k<=3;k++) + { + //--- Allocate + ArrayResize(x,k); + ArrayResize(y,k); + //--- Generate problem + a=2*CMath::RandomReal()-1; + b=a+(0.1+CMath::RandomReal())*(2*CMath::RandomInteger(2)-1); + v0=2*CMath::RandomReal()-1; + v1=2*CMath::RandomReal()-1; + v2=2*CMath::RandomReal()-1; + //--- check + if(k==1) + { + x[0]=0.5*(a+b); + y[0]=v0; + } + //--- check + if(k==2) + { + x[0]=a; + y[0]=v0-v1; + x[1]=b; + y[1]=v0+v1; + } + //--- check + if(k==3) + { + x[0]=a; + y[0]=v0-v1+v2; + x[1]=0.5*(a+b); + y[1]=v0-v2; + x[2]=b; + y[2]=v0+v1+v2; + } + //--- Test forward conversion + CPolInt::PolynomialBuild(x,y,k,p); + ArrayResize(c,1); + CPolInt::PolynomialBar2Cheb(p,a,b,c); + //--- search errors + interrors=interrors || CAp::Len(c)!=k; + //--- check + if(k>=1) + interrors=interrors || MathAbs(c[0]-v0)>threshold; + //--- check + if(k>=2) + interrors=interrors || MathAbs(c[1]-v1)>threshold; + //--- check + if(k>=3) + interrors=interrors || MathAbs(c[2]-v2)>threshold; + //--- Test backward conversion + CPolInt::PolynomialCheb2Bar(c,k,a,b,p2); + v=a+CMath::RandomReal()*(b-a); + //--- search errors + interrors=interrors || MathAbs(CRatInt::BarycentricCalc(p,v)-CRatInt::BarycentricCalc(p2,v))>threshold; + } + } +//--- Testing conversion Barycentric<->Power + for(pass=1;pass<=passcount;pass++) + { + for(k=1;k<=5;k++) + { + //--- Allocate + ArrayResize(x,k); + ArrayResize(y,k); + //--- Generate problem + poffset=2*CMath::RandomReal()-1; + pscale=(0.1+CMath::RandomReal())*(2*CMath::RandomInteger(2)-1); + v0=2*CMath::RandomReal()-1; + v1=2*CMath::RandomReal()-1; + v2=2*CMath::RandomReal()-1; + v3=2*CMath::RandomReal()-1; + v4=2*CMath::RandomReal()-1; + //--- check + if(k==1) + { + x[0]=poffset; + y[0]=v0; + } + //--- check + if(k==2) + { + x[0]=poffset-pscale; + y[0]=v0-v1; + x[1]=poffset+pscale; + y[1]=v0+v1; + } + //--- check + if(k==3) + { + x[0]=poffset-pscale; + y[0]=v0-v1+v2; + x[1]=poffset; + y[1]=v0; + x[2]=poffset+pscale; + y[2]=v0+v1+v2; + } + //--- check + if(k==4) + { + x[0]=poffset-pscale; + y[0]=v0-v1+v2-v3; + x[1]=poffset-0.5*pscale; + y[1]=v0-0.5*v1+0.25*v2-0.125*v3; + x[2]=poffset+0.5*pscale; + y[2]=v0+0.5*v1+0.25*v2+0.125*v3; + x[3]=poffset+pscale; + y[3]=v0+v1+v2+v3; + } + //--- check + if(k==5) + { + x[0]=poffset-pscale; + y[0]=v0-v1+v2-v3+v4; + x[1]=poffset-0.5*pscale; + y[1]=v0-0.5*v1+0.25*v2-0.125*v3+0.0625*v4; + x[2]=poffset; + y[2]=v0; + x[3]=poffset+0.5*pscale; + y[3]=v0+0.5*v1+0.25*v2+0.125*v3+0.0625*v4; + x[4]=poffset+pscale; + y[4]=v0+v1+v2+v3+v4; + } + //--- Test forward conversion + CPolInt::PolynomialBuild(x,y,k,p); + ArrayResize(c,1); + CPolInt::PolynomialBar2Pow(p,poffset,pscale,c); + //--- search errors + interrors=interrors || CAp::Len(c)!=k; + //--- check + if(k>=1) + interrors=interrors || MathAbs(c[0]-v0)>threshold; + //--- check + if(k>=2) + interrors=interrors || MathAbs(c[1]-v1)>threshold; + //--- check + if(k>=3) + interrors=interrors || MathAbs(c[2]-v2)>threshold; + //--- check + if(k>=4) + interrors=interrors || MathAbs(c[3]-v3)>threshold; + //--- check + if(k>=5) + interrors=interrors || MathAbs(c[4]-v4)>threshold; + //--- Test backward conversion + CPolInt::PolynomialPow2Bar(c,k,poffset,pscale,p2); + v=poffset+(2*CMath::RandomReal()-1)*pscale; + //--- search errors + interrors=interrors || MathAbs(CRatInt::BarycentricCalc(p,v)-CRatInt::BarycentricCalc(p2,v))>threshold; + } + } +//--- crash-test: ability to solve tasks which will overflow/underflow +//--- weights with straightforward implementation + for(n=1;n<=20;n++) + { + a=-(0.1*CMath::m_maxrealnumber); + b=0.1*CMath::m_maxrealnumber; + CApServ::TaskGenInt1DEquidist(a,b,n,x,y); + CPolInt::PolynomialBuild(x,y,n,p); + //--- search errors + for(i=0;i<=n-1;i++) + interrors=interrors || p.m_w[i]==0.0; + } +//--- report + waserrors=interrors; +//--- check + if(!silent) + { + Print("TESTING POLYNOMIAL INTERPOLATION"); + //--- Normal tests + Print("INTERPOLATION TEST: "); + //--- check + if(interrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- end + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static double CTestPolIntUnit::InternalPolInt(double &x[],double &cf[], + int n,const double t) + { +//--- create variables + int i=0; + int j=0; +//--- create array + double f[]; +//--- copy + ArrayCopy(f,cf); +//--- calculation + n=n-1; + for(j=0;j<=n-1;j++) + { + for(i=j+1;i<=n;i++) + f[i]=((t-x[j])*f[i]-(t-x[i])*f[j])/(x[i]-x[j]); + } +//--- return result + return(f[n]); + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestPolIntUnit::BRCunSet(CBarycentricInterpolant &b) + { +//--- create arrays + double x[]; + double y[]; + double w[]; +//--- allocation + ArrayResize(x,1); + ArrayResize(y,1); + ArrayResize(w,1); +//--- change values + x[0]=0; + y[0]=0; + w[0]=1; +//--- function call + CRatInt::BarycentricBuildXYW(x,y,w,1,b); + } +//+------------------------------------------------------------------+ +//| Testing class CSpline1D | +//+------------------------------------------------------------------+ +class CTestSpline1DUnit + { +private: + //--- private methods + static void LConst(const double a,const double b,CSpline1DInterpolant &c,const double lstep,double &l0,double &l1,double &l2); + static bool TestUnpack(CSpline1DInterpolant &c,double &x[]); + static void UnsetSpline1D(CSpline1DInterpolant &c); + static void Unset1D(double &x[]); + static bool Is1DSolution(const int n,double &y[],double &w[],const double c); +public: + //--- constructor, destructor + CTestSpline1DUnit(void); + ~CTestSpline1DUnit(void); + //--- public method + static bool TestSpline1D(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestSpline1DUnit::CTestSpline1DUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestSpline1DUnit::~CTestSpline1DUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CSpline1D | +//+------------------------------------------------------------------+ +static bool CTestSpline1DUnit::TestSpline1D(const bool silent) + { +//--- create variables + bool waserrors; + bool crserrors; + bool cserrors; + bool hserrors; + bool aserrors; + bool lserrors; + bool dserrors; + bool uperrors; + bool cperrors; + bool lterrors; + bool ierrors; + double nonstrictthreshold=0; + double threshold=0; + int passcount=0; + double lstep=0; + double h=0; + int maxn=0; + int bltype=0; + int brtype=0; + bool periodiccond; + int n=0; + int i=0; + int k=0; + int pass=0; + double a=0; + double b=0; + double bl=0; + double br=0; + double t=0; + double sa=0; + double sb=0; + int n2=0; + double v=0; + double l10=0; + double l11=0; + double l12=0; + double l20=0; + double l21=0; + double l22=0; + double p0=0; + double p1=0; + double p2=0; + double s=0; + double ds=0; + double d2s=0; + double s2=0; + double ds2=0; + double d2s2=0; + double vl=0; + double vm=0; + double vr=0; + double err=0; + double tension=0; + double intab=0; + int i_=0; +//--- create arrays + double x[]; + double y[]; + double yp[]; + double w[]; + double w2[]; + double y2[]; + double d[]; + double xc[]; + double yc[]; + double tmp0[]; + double tmp1[]; + double tmp2[]; + double tmpx[]; + int dc[]; +//--- objects of classes + CSpline1DInterpolant c; + CSpline1DInterpolant c2; +//--- initialization + waserrors=false; + passcount=20; + lstep=0.005; + h=0.00001; + maxn=10; + threshold=10000*CMath::m_machineepsilon; + nonstrictthreshold=0.00001; + lserrors=false; + cserrors=false; + crserrors=false; + hserrors=false; + aserrors=false; + dserrors=false; + cperrors=false; + uperrors=false; + lterrors=false; + ierrors=false; +//--- General test: linear,cubic,Hermite,Akima + for(n=2;n<=maxn;n++) + { + //--- allocation + ArrayResize(x,n); + ArrayResize(y,n); + ArrayResize(yp,n); + ArrayResize(d,n); + //--- calculation + 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-CMath::RandomReal(); + b=1+CMath::RandomReal(); + bl=2*CMath::RandomReal()-1; + br=2*CMath::RandomReal()-1; + for(i=0;i<=n-1;i++) + { + x[i]=0.5*(b+a)+0.5*(b-a)*MathCos(M_PI*(2*i+1)/(2*n)); + //--- check + if(i==0) + x[i]=a; + //--- check + if(i==n-1) + x[i]=b; + //--- change values + y[i]=MathCos(1.3*M_PI*x[i]+0.4); + yp[i]=y[i]; + d[i]=-(1.3*M_PI*MathSin(1.3*M_PI*x[i]+0.4)); + } + yp[n-1]=yp[0]; + //--- swap + for(i=0;i<=n-1;i++) + { + k=CMath::RandomInteger(n); + //--- check + if(k!=i) + { + t=x[i]; + x[i]=x[k]; + x[k]=t; + t=y[i]; + y[i]=y[k]; + y[k]=t; + t=yp[i]; + yp[i]=yp[k]; + yp[k]=t; + t=d[i]; + d[i]=d[k]; + d[k]=t; + } + } + //--- Build linear spline + //--- Test for general interpolation scheme properties: + //--- * values at nodes + //--- * continuous function + //--- Test for specific properties is implemented below. + CSpline1D::Spline1DBuildLinear(x,y,n,c); + //--- search errors + err=0; + for(i=0;i<=n-1;i++) + err=MathMax(err,MathAbs(y[i]-CSpline1D::Spline1DCalc(c,x[i]))); + //--- search errors + lserrors=lserrors || err>threshold; + LConst(a,b,c,lstep,l10,l11,l12); + LConst(a,b,c,lstep/3,l20,l21,l22); + //--- search errors + lserrors=lserrors || 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; + //--- check + if(periodiccond && bltype!=brtype) + continue; + //--- build + if(periodiccond) + CSpline1D::Spline1DBuildCubic(x,yp,n,bltype,bl,brtype,br,c); + else + CSpline1D::Spline1DBuildCubic(x,y,n,bltype,bl,brtype,br,c); + //--- interpolation properties + err=0; + //--- check + 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[i]; + vm=v+(b-a)*(CMath::RandomInteger(5)-2); + t=yp[i]-CSpline1D::Spline1DCalc(c,vm); + //--- search errors + err=MathMax(err,MathAbs(t)); + //--- function calls + CSpline1D::Spline1DDiff(c,v,s,ds,d2s); + CSpline1D::Spline1DDiff(c,vm,s2,ds2,d2s2); + //--- search errors + err=MathMax(err,MathAbs(s-s2)); + err=MathMax(err,MathAbs(ds-ds2)); + err=MathMax(err,MathAbs(d2s-d2s2)); + } + //--- periodicity between nodes + v=a+(b-a)*CMath::RandomReal(); + vm=v+(b-a)*(CMath::RandomInteger(5)-2); + //--- search errors + err=MathMax(err,MathAbs(CSpline1D::Spline1DCalc(c,v)-CSpline1D::Spline1DCalc(c,vm))); + //--- function calls + CSpline1D::Spline1DDiff(c,v,s,ds,d2s); + CSpline1D::Spline1DDiff(c,vm,s2,ds2,d2s2); + //--- search errors + err=MathMax(err,MathAbs(s-s2)); + err=MathMax(err,MathAbs(ds-ds2)); + err=MathMax(err,MathAbs(d2s-d2s2)); + } + else + { + //--- * check values at nodes + for(i=0;i<=n-1;i++) + err=MathMax(err,MathAbs(y[i]-CSpline1D::Spline1DCalc(c,x[i]))); + } + //--- search errors + cserrors=cserrors || err>threshold; + //--- check boundary conditions + err=0; + //--- check + if(bltype==0) + { + //--- function calls + CSpline1D::Spline1DDiff(c,a-h,s,ds,d2s); + CSpline1D::Spline1DDiff(c,a+h,s2,ds2,d2s2); + t=(d2s2-d2s)/(2*h); + //--- search errors + err=MathMax(err,MathAbs(t)); + } + //--- check + if(bltype==1) + { + t=(CSpline1D::Spline1DCalc(c,a+h)-CSpline1D::Spline1DCalc(c,a-h))/(2*h); + //--- search errors + err=MathMax(err,MathAbs(bl-t)); + } + //--- check + if(bltype==2) + { + t=(CSpline1D::Spline1DCalc(c,a+h)-2*CSpline1D::Spline1DCalc(c,a)+CSpline1D::Spline1DCalc(c,a-h))/CMath::Sqr(h); + //--- search errors + err=MathMax(err,MathAbs(bl-t)); + } + //--- check + if(brtype==0) + { + CSpline1D::Spline1DDiff(c,b-h,s,ds,d2s); + CSpline1D::Spline1DDiff(c,b+h,s2,ds2,d2s2); + t=(d2s2-d2s)/(2*h); + //--- search errors + err=MathMax(err,MathAbs(t)); + } + //--- check + if(brtype==1) + { + t=(CSpline1D::Spline1DCalc(c,b+h)-CSpline1D::Spline1DCalc(c,b-h))/(2*h); + //--- search errors + err=MathMax(err,MathAbs(br-t)); + } + //--- check + if(brtype==2) + { + t=(CSpline1D::Spline1DCalc(c,b+h)-2*CSpline1D::Spline1DCalc(c,b)+CSpline1D::Spline1DCalc(c,b-h))/CMath::Sqr(h); + //--- search errors + err=MathMax(err,MathAbs(br-t)); + } + //--- check + if(bltype==-1 || brtype==-1) + { + //--- function calls + CSpline1D::Spline1DDiff(c,a+100*CMath::m_machineepsilon,s,ds,d2s); + CSpline1D::Spline1DDiff(c,b-100*CMath::m_machineepsilon,s2,ds2,d2s2); + //--- search errors + err=MathMax(err,MathAbs(s-s2)); + err=MathMax(err,MathAbs(ds-ds2)); + err=MathMax(err,MathAbs(d2s-d2s2)); + } + //--- search errors + cserrors=cserrors || err>1.0E-3; + //--- Check Lipschitz continuity + LConst(a,b,c,lstep,l10,l11,l12); + LConst(a,b,c,lstep/3,l20,l21,l22); + //--- check + if(l10>1.0E-6) + cserrors=cserrors || l20/l10>1.2; + //--- check + if(l11>1.0E-6) + cserrors=cserrors || l21/l11>1.2; + //--- check + if(l12>1.0E-6) + cserrors=cserrors || l22/l12>1.2; + //--- compare spline1dgriddiff() and spline1ddiff() results + err=0; + //--- check + if(periodiccond) + CSpline1D::Spline1DGridDiffCubic(x,yp,n,bltype,bl,brtype,br,tmp1); + else + CSpline1D::Spline1DGridDiffCubic(x,y,n,bltype,bl,brtype,br,tmp1); + //--- check + if(!CAp::Assert(CAp::Len(tmp1)>=n)) + return(false); + for(i=0;i<=n-1;i++) + { + CSpline1D::Spline1DDiff(c,x[i],s,ds,d2s); + //--- search errors + err=MathMax(err,MathAbs(ds-tmp1[i])); + } + //--- check + if(periodiccond) + CSpline1D::Spline1DGridDiff2Cubic(x,yp,n,bltype,bl,brtype,br,tmp1,tmp2); + else + CSpline1D::Spline1DGridDiff2Cubic(x,y,n,bltype,bl,brtype,br,tmp1,tmp2); + for(i=0;i<=n-1;i++) + { + CSpline1D::Spline1DDiff(c,x[i],s,ds,d2s); + //--- search errors + err=MathMax(err,MathAbs(ds-tmp1[i])); + err=MathMax(err,MathAbs(d2s-tmp2[i])); + } + //--- search errors + cserrors=cserrors || err>threshold; + //--- compare spline1dconv()/convdiff()/convdiff2() and spline1ddiff() results + n2=2+CMath::RandomInteger(2*n); + ArrayResize(tmpx,n2); + //--- calculation + for(i=0;i<=n2-1;i++) + tmpx[i]=0.5*(a+b)+(a-b)*(2*CMath::RandomReal()-1); + err=0; + //--- check + if(periodiccond) + CSpline1D::Spline1DConvCubic(x,yp,n,bltype,bl,brtype,br,tmpx,n2,tmp0); + else + CSpline1D::Spline1DConvCubic(x,y,n,bltype,bl,brtype,br,tmpx,n2,tmp0); + for(i=0;i<=n2-1;i++) + { + CSpline1D::Spline1DDiff(c,tmpx[i],s,ds,d2s); + //--- search errors + err=MathMax(err,MathAbs(s-tmp0[i])); + } + //--- check + if(periodiccond) + CSpline1D::Spline1DConvDiffCubic(x,yp,n,bltype,bl,brtype,br,tmpx,n2,tmp0,tmp1); + else + CSpline1D::Spline1DConvDiffCubic(x,y,n,bltype,bl,brtype,br,tmpx,n2,tmp0,tmp1); + for(i=0;i<=n2-1;i++) + { + CSpline1D::Spline1DDiff(c,tmpx[i],s,ds,d2s); + //--- search errors + err=MathMax(err,MathAbs(s-tmp0[i])); + err=MathMax(err,MathAbs(ds-tmp1[i])); + } + //--- check + if(periodiccond) + CSpline1D::Spline1DConvDiff2Cubic(x,yp,n,bltype,bl,brtype,br,tmpx,n2,tmp0,tmp1,tmp2); + else + CSpline1D::Spline1DConvDiff2Cubic(x,y,n,bltype,bl,brtype,br,tmpx,n2,tmp0,tmp1,tmp2); + for(i=0;i<=n2-1;i++) + { + CSpline1D::Spline1DDiff(c,tmpx[i],s,ds,d2s); + //--- search errors + err=MathMax(err,MathAbs(s-tmp0[i])); + err=MathMax(err,MathAbs(ds-tmp1[i])); + err=MathMax(err,MathAbs(d2s-tmp2[i])); + } + //--- search errors + cserrors=cserrors || 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(CMath::RandomReal()>0.5) + { + //--- check + if(CMath::RandomReal()>0.5) + tension=0; + else + tension=1; + } + else + tension=CMath::RandomReal(); + //--- check + if(periodiccond) + CSpline1D::Spline1DBuildCatmullRom(x,yp,n,bltype,tension,c); + else + CSpline1D::Spline1DBuildCatmullRom(x,y,n,bltype,tension,c); + //--- interpolation properties + err=0; + //--- check + 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[i]; + vm=v+(b-a)*(CMath::RandomInteger(5)-2); + t=yp[i]-CSpline1D::Spline1DCalc(c,vm); + //--- search errors + err=MathMax(err,MathAbs(t)); + //--- function calls + CSpline1D::Spline1DDiff(c,v,s,ds,d2s); + CSpline1D::Spline1DDiff(c,vm,s2,ds2,d2s2); + //--- search errors + err=MathMax(err,MathAbs(s-s2)); + err=MathMax(err,MathAbs(ds-ds2)); + } + //--- periodicity between nodes + v=a+(b-a)*CMath::RandomReal(); + vm=v+(b-a)*(CMath::RandomInteger(5)-2); + //--- search errors + err=MathMax(err,MathAbs(CSpline1D::Spline1DCalc(c,v)-CSpline1D::Spline1DCalc(c,vm))); + //--- function calls + CSpline1D::Spline1DDiff(c,v,s,ds,d2s); + CSpline1D::Spline1DDiff(c,vm,s2,ds2,d2s2); + //--- search errors + err=MathMax(err,MathAbs(s-s2)); + err=MathMax(err,MathAbs(ds-ds2)); + } + else + { + //--- * check values at nodes + for(i=0;i<=n-1;i++) + err=MathMax(err,MathAbs(y[i]-CSpline1D::Spline1DCalc(c,x[i]))); + } + //--- search errors + crserrors=crserrors || err>threshold; + //--- check boundary conditions + err=0; + //--- check + if(bltype==0) + { + //--- function calls + CSpline1D::Spline1DDiff(c,a-h,s,ds,d2s); + CSpline1D::Spline1DDiff(c,a+h,s2,ds2,d2s2); + t=(d2s2-d2s)/(2*h); + //--- search errors + err=MathMax(err,MathAbs(t)); + //--- function calls + CSpline1D::Spline1DDiff(c,b-h,s,ds,d2s); + CSpline1D::Spline1DDiff(c,b+h,s2,ds2,d2s2); + t=(d2s2-d2s)/(2*h); + //--- search errors + err=MathMax(err,MathAbs(t)); + } + //--- check + if(bltype==-1) + { + //--- function calls + CSpline1D::Spline1DDiff(c,a+100*CMath::m_machineepsilon,s,ds,d2s); + CSpline1D::Spline1DDiff(c,b-100*CMath::m_machineepsilon,s2,ds2,d2s2); + //--- search errors + err=MathMax(err,MathAbs(s-s2)); + err=MathMax(err,MathAbs(ds-ds2)); + } + //--- search errors + crserrors=crserrors || err>1.0E-3; + //--- Check Lipschitz continuity + LConst(a,b,c,lstep,l10,l11,l12); + LConst(a,b,c,lstep/3,l20,l21,l22); + //--- check + if(l10>1.0E-6) + crserrors=crserrors || l20/l10>1.2; + //--- check + if(l11>1.0E-6) + crserrors=crserrors || l21/l11>1.2; + } + //--- Build Hermite spline. + //--- Test for interpolation scheme properties: + //--- * values and derivatives at nodes + //--- * continuous function + //--- * continuous first derivative + CSpline1D::Spline1DBuildHermite(x,y,d,n,c); + //--- search errors + err=0; + for(i=0;i<=n-1;i++) + err=MathMax(err,MathAbs(y[i]-CSpline1D::Spline1DCalc(c,x[i]))); + //--- search errors + hserrors=hserrors || err>threshold; + err=0; + for(i=0;i<=n-1;i++) + { + t=(CSpline1D::Spline1DCalc(c,x[i]+h)-CSpline1D::Spline1DCalc(c,x[i]-h))/(2*h); + err=MathMax(err,MathAbs(d[i]-t)); + } + //--- search errors + hserrors=hserrors || err>1.0E-3; + LConst(a,b,c,lstep,l10,l11,l12); + LConst(a,b,c,lstep/3,l20,l21,l22); + //--- search errors + hserrors=hserrors || l20/l10>1.2; + hserrors=hserrors || l21/l11>1.2; + //--- Build Akima spline + //--- Test for general interpolation scheme properties: + //--- * values at nodes + //--- * continuous function + //--- * continuous first derivative + //--- Test for specific properties is implemented below. + if(n>=5) + { + CSpline1D::Spline1DBuildAkima(x,y,n,c); + //--- search errors + err=0; + for(i=0;i<=n-1;i++) + err=MathMax(err,MathAbs(y[i]-CSpline1D::Spline1DCalc(c,x[i]))); + //--- search errors + aserrors=aserrors || err>threshold; + LConst(a,b,c,lstep,l10,l11,l12); + LConst(a,b,c,lstep/3,l20,l21,l22); + //--- search errors + hserrors=hserrors || l20/l10>1.2; + hserrors=hserrors || l21/l11>1.2; + } + } + } +//--- Special linear spline test: +//--- test for linearity between x[i] and x[i+1] + for(n=2;n<=maxn;n++) + { + //--- allocation + ArrayResize(x,n); + ArrayResize(y,n); + //--- Prepare task + a=-1; + b=1; + for(i=0;i<=n-1;i++) + { + x[i]=a+(b-a)*i/(n-1); + y[i]=2*CMath::RandomReal()-1; + } + //--- function call + CSpline1D::Spline1DBuildLinear(x,y,n,c); + //--- Test + err=0; + for(k=0;k<=n-2;k++) + { + a=x[k]; + b=x[k+1]; + //--- calculation + for(pass=1;pass<=passcount;pass++) + { + t=a+(b-a)*CMath::RandomReal(); + v=y[k]+(t-a)/(b-a)*(y[k+1]-y[k]); + //--- search errors + err=MathMax(err,MathAbs(CSpline1D::Spline1DCalc(c,t)-v)); + } + } + //--- search errors + lserrors=lserrors || 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++) + { + //--- allocation + ArrayResize(x,n); + ArrayResize(y,n); + ArrayResize(y2,n); + //--- Prepare unperturbed Akima spline + a=-1; + b=1; + for(i=0;i<=n-1;i++) + { + x[i]=a+(b-a)*i/(n-1); + y[i]=MathCos(1.3*M_PI*x[i]+0.4); + } + //--- function call + CSpline1D::Spline1DBuildAkima(x,y,n,c); + //--- Process perturbed tasks + err=0; + for(k=0;k<=n-1;k++) + { + for(i_=0;i_<=n-1;i_++) + y2[i_]=y[i_]; + y2[k]=5; + //--- function call + CSpline1D::Spline1DBuildAkima(x,y2,n,c2); + //--- Test left part independence + if(k-3>=1) + { + a=-1; + b=x[k-3]; + for(pass=1;pass<=passcount;pass++) + { + t=a+(b-a)*CMath::RandomReal(); + //--- search errors + err=MathMax(err,MathAbs(CSpline1D::Spline1DCalc(c,t)-CSpline1D::Spline1DCalc(c2,t))); + } + } + //--- Test right part independence + if(k+3<=n-2) + { + a=x[k+3]; + b=1; + for(pass=1;pass<=passcount;pass++) + { + t=a+(b-a)*CMath::RandomReal(); + //--- search errors + err=MathMax(err,MathAbs(CSpline1D::Spline1DCalc(c,t)-CSpline1D::Spline1DCalc(c2,t))); + } + } + } + //--- search errors + aserrors=aserrors || err>threshold; + } +//--- Differentiation,copy/unpack test + for(n=2;n<=maxn;n++) + { + //--- allocation + ArrayResize(x,n); + ArrayResize(y,n); + //--- Prepare cubic spline + a=-1-CMath::RandomReal(); + b=1+CMath::RandomReal(); + for(i=0;i<=n-1;i++) + { + x[i]=a+(b-a)*i/(n-1); + y[i]=MathCos(1.3*M_PI*x[i]+0.4); + } + //--- function call + CSpline1D::Spline1DBuildCubic(x,y,n,2,0.0,2,0.0,c); + //--- Test diff + err=0; + for(pass=1;pass<=passcount;pass++) + { + t=a+(b-a)*CMath::RandomReal(); + //--- function calls + CSpline1D::Spline1DDiff(c,t,s,ds,d2s); + vl=CSpline1D::Spline1DCalc(c,t-h); + vm=CSpline1D::Spline1DCalc(c,t); + vr=CSpline1D::Spline1DCalc(c,t+h); + //--- search errors + err=MathMax(err,MathAbs(s-vm)); + err=MathMax(err,MathAbs(ds-(vr-vl)/(2*h))); + err=MathMax(err,MathAbs(d2s-(vr-2*vm+vl)/CMath::Sqr(h))); + } + //--- search errors + dserrors=dserrors || err>0.001; + //--- Test copy + UnsetSpline1D(c2); + CSpline1D::Spline1DCopy(c,c2); + //--- search errors + err=0; + for(pass=1;pass<=passcount;pass++) + { + t=a+(b-a)*CMath::RandomReal(); + err=MathMax(err,MathAbs(CSpline1D::Spline1DCalc(c,t)-CSpline1D::Spline1DCalc(c2,t))); + } + //--- search errors + cperrors=cperrors || err>threshold; + //--- Test unpack + uperrors=uperrors || !TestUnpack(c,x); + //--- Test lin.trans. + err=0; + for(pass=1;pass<=passcount;pass++) + { + //--- LinTransX,general A + sa=4*CMath::RandomReal()-2; + sb=2*CMath::RandomReal()-1; + t=a+(b-a)*CMath::RandomReal(); + //--- function calls + CSpline1D::Spline1DCopy(c,c2); + CSpline1D::Spline1DLinTransX(c2,sa,sb); + //--- search errors + err=MathMax(err,MathAbs(CSpline1D::Spline1DCalc(c,t)-CSpline1D::Spline1DCalc(c2,(t-sb)/sa))); + //--- LinTransX,special case: A=0 + sb=2*CMath::RandomReal()-1; + t=a+(b-a)*CMath::RandomReal(); + //--- function calls + CSpline1D::Spline1DCopy(c,c2); + CSpline1D::Spline1DLinTransX(c2,0,sb); + //--- search errors + err=MathMax(err,MathAbs(CSpline1D::Spline1DCalc(c,sb)-CSpline1D::Spline1DCalc(c2,t))); + //--- LinTransY + sa=2*CMath::RandomReal()-1; + sb=2*CMath::RandomReal()-1; + t=a+(b-a)*CMath::RandomReal(); + //--- function calls + CSpline1D::Spline1DCopy(c,c2); + CSpline1D::Spline1DLinTransY(c2,sa,sb); + //--- search errors + err=MathMax(err,MathAbs(sa*CSpline1D::Spline1DCalc(c,t)+sb-CSpline1D::Spline1DCalc(c2,t))); + } + //--- search errors + lterrors=lterrors || err>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=0; + for(n=20;n<=35;n++) + { + //--- allocation + ArrayResize(x,n); + ArrayResize(y,n); + for(pass=1;pass<=passcount;pass++) + { + //--- Prepare cubic spline + a=-1-0.2*CMath::RandomReal(); + b=1+0.2*CMath::RandomReal(); + for(i=0;i<=n-1;i++) + { + x[i]=a+(b-a)*i/(n-1); + y[i]=MathSin(M_PI*x[i]+0.4)+MathExp(x[i]); + } + //--- change values + bl=M_PI*MathCos(M_PI*a+0.4)+MathExp(a); + br=M_PI*MathCos(M_PI*b+0.4)+MathExp(b); + //--- function call + CSpline1D::Spline1DBuildCubic(x,y,n,1,bl,1,br,c); + //--- Test + t=a+(b-a)*CMath::RandomReal(); + v=-(MathCos(M_PI*a+0.4)/M_PI)+MathExp(a); + v=-(MathCos(M_PI*t+0.4)/M_PI)+MathExp(t)-v; + v=v-CSpline1D::Spline1DIntegrate(c,t); + //--- search errors + err=MathMax(err,MathAbs(v)); + } + } +//--- search errors + ierrors=ierrors || err>0.001; + p0=2*CMath::RandomReal()-1; + p1=2*CMath::RandomReal()-1; + p2=2*CMath::RandomReal()-1; + a=-CMath::RandomReal()-0.5; + b=CMath::RandomReal()+0.5; + n=2; +//--- allocation + ArrayResize(x,n); + ArrayResize(y,n); + ArrayResize(d,n); + x[0]=a; + y[0]=p0+p1*a+p2*CMath::Sqr(a); + d[0]=p1+2*p2*a; + x[1]=b; + y[1]=p0+p1*b+p2*CMath::Sqr(b); + d[1]=p1+2*p2*b; +//--- function call + CSpline1D::Spline1DBuildHermite(x,y,d,n,c); + bl=MathMin(a,b)-MathAbs(b-a); + br=MathMin(a,b)+MathAbs(b-a); + err=0; +//--- calculation + for(pass=1;pass<=100;pass++) + { + t=bl+(br-bl)*CMath::RandomReal(); + v=p0*t+p1*CMath::Sqr(t)/2+p2*CMath::Sqr(t)*t/3-(p0*a+p1*CMath::Sqr(a)/2+p2*CMath::Sqr(a)*a/3); + v=v-CSpline1D::Spline1DIntegrate(c,t); + //--- search errors + err=MathMax(err,MathAbs(v)); + } +//--- search errors + ierrors=ierrors || err>threshold; + n=100; +//--- allocation + ArrayResize(x,n); + ArrayResize(y,n); + for(i=0;i<=n-1;i++) + { + x[i]=(double)i/(double)(n-1); + y[i]=MathCos(2*M_PI*x[i])+1; + } +//--- change values + y[0]=2; + y[n-1]=2; +//--- function calls + CSpline1D::Spline1DBuildCubic(x,y,n,-1,0.0,-1,0.0,c); + intab=CSpline1D::Spline1DIntegrate(c,1.0); + v=CMath::RandomReal(); + vr=CSpline1D::Spline1DIntegrate(c,v); +//--- search errors + ierrors=ierrors || MathAbs(intab-1)>0.001; + for(i=-10;i<=10;i++) + { + ierrors=ierrors || MathAbs(CSpline1D::Spline1DIntegrate(c,i+v)-(i*intab+vr))>0.001; + ierrors=ierrors || MathAbs(CSpline1D::Spline1DIntegrate(c,i-1000*CMath::m_machineepsilon)-i*intab)>0.001; + ierrors=ierrors || MathAbs(CSpline1D::Spline1DIntegrate(c,i)-i*intab)>0.001; + ierrors=ierrors || MathAbs(CSpline1D::Spline1DIntegrate(c,i+1000*CMath::m_machineepsilon)-i*intab)>0.001; + } +//--- report + waserrors=((((((((lserrors || cserrors) || crserrors) || hserrors) || aserrors) || dserrors) || cperrors) || uperrors) || lterrors) || ierrors; +//--- check + if(!silent) + { + Print("TESTING SPLINE INTERPOLATION"); + //--- Normal tests + Print("LINEAR SPLINE TEST: "); + //--- check + if(lserrors) + Print("FAILED"); + else + Print("OK"); + Print("CUBIC SPLINE TEST: "); + //--- check + if(cserrors) + Print("FAILED"); + else + Print("OK"); + Print("CATMULL-ROM SPLINE TEST: "); + //--- check + if(crserrors) + Print("FAILED"); + else + Print("OK"); + Print("HERMITE SPLINE TEST: "); + //--- check + if(hserrors) + Print("FAILED"); + else + Print("OK"); + Print("AKIMA SPLINE TEST: "); + //--- check + if(aserrors) + Print("FAILED"); + else + Print("OK"); + Print("DIFFERENTIATION TEST: "); + //--- check + if(dserrors) + Print("FAILED"); + else + Print("OK"); + Print("COPY/SERIALIZATION TEST: "); + //--- check + if(cperrors) + Print("FAILED"); + else + Print("OK"); + Print("UNPACK TEST: "); + //--- check + if(uperrors) + Print("FAILED"); + else + Print("OK"); + Print("LIN.TRANS. TEST: "); + //--- check + if(lterrors) + Print("FAILED"); + else + Print("OK"); + Print("INTEGRATION TEST: "); + //--- check + if(ierrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- end + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Lipschitz constants for spline inself,first and second | +//| derivatives. | +//+------------------------------------------------------------------+ +static void CTestSpline1DUnit::LConst(const double a,const double b, + CSpline1DInterpolant &c, + const double lstep,double &l0, + double &l1,double &l2) + { +//--- create variables + double t=0; + double vl=0; + double vm=0; + double vr=0; + double prevf=0; + double prevd=0; + double prevd2=0; + double f=0; + double d=0; + double d2=0; +//--- change values + l0=0; + l1=0; + l2=0; + t=a-0.1; + vl=CSpline1D::Spline1DCalc(c,t-2*lstep); + vm=CSpline1D::Spline1DCalc(c,t-lstep); + vr=CSpline1D::Spline1DCalc(c,t); + f=vm; + d=(vr-vl)/(2*lstep); + d2=(vr-2*vm+vl)/CMath::Sqr(lstep); +//--- calculation + while(t<=b+0.1) + { + //--- change values + prevf=f; + prevd=d; + prevd2=d2; + vl=vm; + vm=vr; + vr=CSpline1D::Spline1DCalc(c,t+lstep); + f=vm; + d=(vr-vl)/(2*lstep); + d2=(vr-2*vm+vl)/CMath::Sqr(lstep); + l0=MathMax(l0,MathAbs((f-prevf)/lstep)); + l1=MathMax(l1,MathAbs((d-prevd)/lstep)); + l2=MathMax(l2,MathAbs((d2-prevd2)/lstep)); + t=t+lstep; + } + } +//+------------------------------------------------------------------+ +//| Unpack testing | +//+------------------------------------------------------------------+ +static bool CTestSpline1DUnit::TestUnpack(CSpline1DInterpolant &c,double &x[]) + { +//--- create variables + bool result; + int i=0; + int n=0; + double err=0; + double t=0; + double v1=0; + double v2=0; + int pass=0; + int passcount=0; +//--- create matrix + CMatrixDouble tbl; +//--- initialization + passcount=20; + err=0; +//--- function call + CSpline1D::Spline1DUnpack(c,n,tbl); +//--- calculation + for(i=0;i<=n-2;i++) + { + for(pass=1;pass<=passcount;pass++) + { + t=CMath::RandomReal()*(tbl[i][1]-tbl[i][0]); + v1=tbl[i][2]+t*tbl[i][3]+CMath::Sqr(t)*tbl[i][4]+t*CMath::Sqr(t)*tbl[i][5]; + v2=CSpline1D::Spline1DCalc(c,tbl[i][0]+t); + //--- search errors + err=MathMax(err,MathAbs(v1-v2)); + } + } +//--- search errors + for(i=0;i<=n-2;i++) + err=MathMax(err,MathAbs(x[i]-tbl[i][0])); +//--- search errors + for(i=0;i<=n-2;i++) + err=MathMax(err,MathAbs(x[i+1]-tbl[i][1])); +//--- get result + result=err<100*CMath::m_machineepsilon; +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Unset spline,i.e. initialize it with random garbage | +//+------------------------------------------------------------------+ +static void CTestSpline1DUnit::UnsetSpline1D(CSpline1DInterpolant &c) + { +//--- create arrays + double x[]; + double y[]; + double d[]; +//--- allocation + ArrayResize(x,2); + ArrayResize(y,2); + ArrayResize(d,2); +//--- change values + x[0]=-1; + y[0]=CMath::RandomReal(); + d[0]=CMath::RandomReal(); + x[1]=1; + y[1]=CMath::RandomReal(); + d[1]=CMath::RandomReal(); +//--- function call + CSpline1D::Spline1DBuildHermite(x,y,d,2,c); + } +//+------------------------------------------------------------------+ +//| Unsets real vector | +//+------------------------------------------------------------------+ +static void CTestSpline1DUnit::Unset1D(double &x[]) + { +//--- allocation + ArrayResize(x,1); +//--- change value + x[0]=2*CMath::RandomReal()-1; + } +//+------------------------------------------------------------------+ +//| Tests whether constant C is solution of 1D LLS problem | +//+------------------------------------------------------------------+ +static bool CTestSpline1DUnit::Is1DSolution(const int n,double &y[], + double &w[],const double c) + { +//--- create variables + bool result; + int i=0; + double s1=0; + double s2=0; + double s3=0; + double delta=0; +//--- initialization + delta=0.001; +//--- Test result + s1=0; + for(i=0;i<=n-1;i++) + s1=s1+CMath::Sqr(w[i]*(c-y[i])); + s2=0; + s3=0; +//--- calculation + for(i=0;i<=n-1;i++) + s2=s2+CMath::Sqr(w[i]*(c+delta-y[i])); + s3=s3+CMath::Sqr(w[i]*(c-delta-y[i])); + result=s2>=s1 && s3>=s1; +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Testing class CMinLM | +//+------------------------------------------------------------------+ +class CTestMinLMUnit + { +public: + //--- constructor, destructor + CTestMinLMUnit(void); + ~CTestMinLMUnit(void); + //--- public methods + static bool TestMinLM(const bool silent); + static bool RKindVSStateCheck(const int rkind,CMinLMState &state); + static void AXMB(CMinLMState &state,CMatrixDouble &a,double &b[],const int n); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestMinLMUnit::CTestMinLMUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestMinLMUnit::~CTestMinLMUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CMinLM | +//+------------------------------------------------------------------+ +static bool CTestMinLMUnit::TestMinLM(const bool silent) + { +//--- create variables + bool waserrors; + bool referror; + bool lin1error; + bool lin2error; + bool eqerror; + bool converror; + bool scerror; + bool restartserror; + bool othererrors; + int rkind=0; + int ckind=0; + int tmpkind=0; + double epsf=0; + double epsx=0; + double epsg=0; + int maxits=0; + int n=0; + int m=0; + int i=0; + int j=0; + double v=0; + double s=0; + double stpmax=0; + double h=0; + double fprev=0; + double xprev=0; + int i_=0; +//--- create arrays + double x[]; + double xe[]; + double b[]; + double bl[]; + double bu[]; + double xlast[]; +//--- create matrix + CMatrixDouble a; +//--- objects of classes + CMinLMState state; + CMinLMReport rep; +//--- initialization + waserrors=false; + referror=false; + lin1error=false; + lin2error=false; + eqerror=false; + converror=false; + scerror=false; + othererrors=false; + restartserror=false; +//--- 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. + ArrayResize(x,3); + n=3; + m=3; + h=0.0001; +//--- calculation + for(rkind=-2;rkind<=5;rkind++) + { + //--- change values + x[0]=100*CMath::RandomReal()-50; + x[1]=100*CMath::RandomReal()-50; + x[2]=100*CMath::RandomReal()-50; + //--- check + if(rkind==-2) + { + CMinLM::MinLMCreateV(n,m,x,h,state); + CMinLM::MinLMSetAccType(state,1); + } + //--- check + if(rkind==-1) + { + CMinLM::MinLMCreateV(n,m,x,h,state); + CMinLM::MinLMSetAccType(state,0); + } + //--- check + if(rkind==0) + CMinLM::MinLMCreateFJ(n,m,x,state); + //--- check + if(rkind==1) + CMinLM::MinLMCreateFGJ(n,m,x,state); + //--- check + if(rkind==2) + CMinLM::MinLMCreateFGH(n,x,state); + //--- check + if(rkind==3) + { + CMinLM::MinLMCreateVJ(n,m,x,state); + CMinLM::MinLMSetAccType(state,0); + } + //--- check + if(rkind==4) + { + CMinLM::MinLMCreateVJ(n,m,x,state); + CMinLM::MinLMSetAccType(state,1); + } + //--- check + if(rkind==5) + { + CMinLM::MinLMCreateVJ(n,m,x,state); + CMinLM::MinLMSetAccType(state,2); + } + //--- cycle + while(CMinLM::MinLMIteration(state)) + { + //--- (x-2)^2 + y^2 + (z-x)^2 + if(state.m_needfi) + { + state.m_fi[0]=state.m_x[0]-2; + state.m_fi[1]=state.m_x[1]; + state.m_fi[2]=state.m_x[2]-state.m_x[0]; + } + //--- check + if(state.m_needfij) + { + state.m_fi[0]=state.m_x[0]-2; + state.m_fi[1]=state.m_x[1]; + state.m_fi[2]=state.m_x[2]-state.m_x[0]; + state.m_j[0].Set(0,1); + state.m_j[0].Set(1,0); + state.m_j[0].Set(2,0); + state.m_j[1].Set(0,0); + state.m_j[1].Set(1,1); + state.m_j[1].Set(2,0); + state.m_j[2].Set(0,-1); + state.m_j[2].Set(1,0); + state.m_j[2].Set(2,1); + } + //--- check + if((state.m_needf || state.m_needfg) || state.m_needfgh) + state.m_f=CMath::Sqr(state.m_x[0]-2)+CMath::Sqr(state.m_x[1])+CMath::Sqr(state.m_x[2]-state.m_x[0]); + //--- check + if(state.m_needfg || state.m_needfgh) + { + state.m_g[0]=2*(state.m_x[0]-2)+2*(state.m_x[0]-state.m_x[2]); + state.m_g[1]=2*state.m_x[1]; + state.m_g[2]=2*(state.m_x[2]-state.m_x[0]); + } + //--- check + if(state.m_needfgh) + { + state.m_h[0].Set(0,4); + state.m_h[0].Set(1,0); + state.m_h[0].Set(2,-2); + state.m_h[1].Set(0,0); + state.m_h[1].Set(1,2); + state.m_h[1].Set(2,0); + state.m_h[2].Set(0,-2); + state.m_h[2].Set(1,0); + state.m_h[2].Set(2,2); + } + //--- search errors + scerror=scerror || !RKindVSStateCheck(rkind,state); + } + //--- function call + CMinLM::MinLMResults(state,x,rep); + //--- search errors + referror=(((referror || rep.m_terminationtype<=0) || MathAbs(x[0]-2)>0.001) || MathAbs(x[1])>0.001) || MathAbs(x[2]-2)>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++) + { + //--- allocation + ArrayResize(bl,n); + ArrayResize(bu,n); + ArrayResize(xe,n); + ArrayResize(x,n); + for(i=0;i<=n-1;i++) + { + bl[i]=0; + bu[i]=1; + xe[i]=3*CMath::RandomReal()-1; + x[i]=CMath::RandomReal(); + } + //--- check + if(tmpkind==0) + CMinLM::MinLMCreateFGH(n,x,state); + //--- check + if(tmpkind==1) + CMinLM::MinLMCreateV(n,n,x,1.0E-3,state); + //--- function calls + CMinLM::MinLMSetCond(state,1.0E-6,0,0,0); + CMinLM::MinLMSetBC(state,bl,bu); + //--- cycle + while(CMinLM::MinLMIteration(state)) + { + //--- check + if(state.m_needfi) + { + for(i=0;i<=n-1;i++) + state.m_fi[i]=MathPow(state.m_x[i]-xe[i],2); + } + //--- check + if((state.m_needf || state.m_needfg) || state.m_needfgh) + { + //--- change value + state.m_f=0; + for(i=0;i<=n-1;i++) + state.m_f=state.m_f+MathPow(state.m_x[i]-xe[i],4); + } + //--- check + if(state.m_needfg || state.m_needfgh) + { + for(i=0;i<=n-1;i++) + state.m_g[i]=4*MathPow(state.m_x[i]-xe[i],3); + } + //--- check + if(state.m_needfgh) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + state.m_h[i].Set(j,0); + } + for(i=0;i<=n-1;i++) + state.m_h[i].Set(i,12*MathPow(state.m_x[i]-xe[i],2)); + } + } + //--- function call + CMinLM::MinLMResults(state,x,rep); + //--- check + if(rep.m_terminationtype==4) + { + for(i=0;i<=n-1;i++) + referror=referror || MathAbs(x[i]-CApServ::BoundVal(xe[i],bl[i],bu[i]))>(double)(5.0E-2); + } + else + referror=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++) + { + //--- allocation + ArrayResize(x,1); + n=1; + m=1; + h=0.00001; + x[0]=100*CMath::RandomReal()-50; + //--- check + if(rkind==-2) + { + CMinLM::MinLMCreateV(n,m,x,h,state); + CMinLM::MinLMSetAccType(state,1); + } + //--- check + if(rkind==-1) + { + CMinLM::MinLMCreateV(n,m,x,h,state); + CMinLM::MinLMSetAccType(state,0); + } + //--- check + if(rkind==0) + CMinLM::MinLMCreateFJ(n,m,x,state); + //--- check + if(rkind==1) + CMinLM::MinLMCreateFGJ(n,m,x,state); + //--- check + if(rkind==2) + CMinLM::MinLMCreateFGH(n,x,state); + //--- check + if(rkind==3) + { + CMinLM::MinLMCreateVJ(n,m,x,state); + CMinLM::MinLMSetAccType(state,0); + } + //--- check + if(rkind==4) + { + CMinLM::MinLMCreateVJ(n,m,x,state); + CMinLM::MinLMSetAccType(state,1); + } + //--- check + if(rkind==5) + { + CMinLM::MinLMCreateVJ(n,m,x,state); + CMinLM::MinLMSetAccType(state,2); + } + //--- cycle + while(CMinLM::MinLMIteration(state)) + { + //--- check + if(state.m_needfi) + state.m_fi[0]=MathSin(state.m_x[0]); + //--- check + if(state.m_needfij) + { + state.m_fi[0]=MathSin(state.m_x[0]); + state.m_j[0].Set(0,MathCos(state.m_x[0])); + } + //--- check + if((state.m_needf || state.m_needfg) || state.m_needfgh) + state.m_f=CMath::Sqr(MathSin(state.m_x[0])); + //--- check + if(state.m_needfg || state.m_needfgh) + state.m_g[0]=2*MathSin(state.m_x[0])*MathCos(state.m_x[0]); + //--- check + if(state.m_needfgh) + state.m_h[0].Set(0,2*(MathCos(state.m_x[0])*MathCos(state.m_x[0])-MathSin(state.m_x[0])*MathSin(state.m_x[0]))); + //--- search errors + scerror=scerror || !RKindVSStateCheck(rkind,state); + } + //--- function call + CMinLM::MinLMResults(state,x,rep); + //--- search errors + lin1error=rep.m_terminationtype<=0 || MathAbs(x[0]/M_PI-(int)MathRound(x[0]/M_PI))>0.001; + } +//--- Linear equations: test normal optimization and optimization with restarts + for(n=1;n<=10;n++) + { + //--- Prepare task + h=0.00001; + //--- function call + CMatGen::RMatrixRndCond(n,100,a); + //--- allocation + ArrayResize(x,n); + ArrayResize(xe,n); + ArrayResize(b,n); + //--- change values + for(i=0;i<=n-1;i++) + xe[i]=2*CMath::RandomReal()-1; + for(i=0;i<=n-1;i++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a[i][i_]*xe[i_]; + b[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[i]=2*CMath::RandomReal()-1; + //--- check + if(rkind==-2) + { + CMinLM::MinLMCreateV(n,n,x,h,state); + CMinLM::MinLMSetAccType(state,1); + } + //--- check + if(rkind==-1) + { + CMinLM::MinLMCreateV(n,n,x,h,state); + CMinLM::MinLMSetAccType(state,0); + } + //--- check + if(rkind==0) + CMinLM::MinLMCreateFJ(n,n,x,state); + //--- check + if(rkind==1) + CMinLM::MinLMCreateFGJ(n,n,x,state); + //--- check + if(rkind==2) + CMinLM::MinLMCreateFGH(n,x,state); + //--- check + if(rkind==3) + { + CMinLM::MinLMCreateVJ(n,n,x,state); + CMinLM::MinLMSetAccType(state,0); + } + //--- check + if(rkind==4) + { + CMinLM::MinLMCreateVJ(n,n,x,state); + CMinLM::MinLMSetAccType(state,1); + } + //--- check + if(rkind==5) + { + CMinLM::MinLMCreateVJ(n,n,x,state); + CMinLM::MinLMSetAccType(state,2); + } + //--- cycle + while(CMinLM::MinLMIteration(state)) + { + AXMB(state,a,b,n); + scerror=scerror || !RKindVSStateCheck(rkind,state); + } + //--- function call + CMinLM::MinLMResults(state,x,rep); + //--- search errors + eqerror=eqerror || rep.m_terminationtype<=0; + for(i=0;i<=n-1;i++) + eqerror=eqerror || MathAbs(x[i]-xe[i])>0.001; + //--- Now we try to restart algorithm from new point + for(i=0;i<=n-1;i++) + x[i]=2*CMath::RandomReal()-1; + //--- function call + CMinLM::MinLMRestartFrom(state,x); + //--- cycle + while(CMinLM::MinLMIteration(state)) + { + AXMB(state,a,b,n); + scerror=scerror || !RKindVSStateCheck(rkind,state); + } + //--- function call + CMinLM::MinLMResults(state,x,rep); + //--- search errors + restartserror=restartserror || rep.m_terminationtype<=0; + for(i=0;i<=n-1;i++) + restartserror=restartserror || MathAbs(x[i]-xe[i])>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=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=0; + epsf=0; + epsx=0; + maxits=0; + //--- check + if(ckind==0) + epsf=0.000001; + //--- check + if(ckind==1) + epsx=0.000001; + //--- check + if(ckind==2) + maxits=2; + //--- check + if(ckind==3) + epsg=0.0001; + //--- allocation + ArrayResize(x,3); + //--- change values + n=3; + m=3; + for(i=0;i<=2;i++) + x[i]=6; + //--- check + if(rkind==0) + CMinLM::MinLMCreateFJ(n,m,x,state); + //--- check + if(rkind==1) + CMinLM::MinLMCreateFGJ(n,m,x,state); + //--- check + if(!CAp::Assert(rkind!=2)) + return(false); + //--- check + if(rkind==3) + { + CMinLM::MinLMCreateVJ(n,m,x,state); + CMinLM::MinLMSetAccType(state,0); + } + //--- check + if(rkind==4) + { + CMinLM::MinLMCreateVJ(n,m,x,state); + CMinLM::MinLMSetAccType(state,1); + } + //--- check + if(rkind==5) + { + CMinLM::MinLMCreateVJ(n,m,x,state); + CMinLM::MinLMSetAccType(state,2); + } + //--- function call + CMinLM::MinLMSetCond(state,epsg,epsf,epsx,maxits); + //--- cycle + while(CMinLM::MinLMIteration(state)) + { + //--- check + if(state.m_needfi || state.m_needfij) + { + state.m_fi[0]=s*(MathExp(state.m_x[0])-2); + state.m_fi[1]=CMath::Sqr(state.m_x[1])+1; + state.m_fi[2]=state.m_x[2]-state.m_x[0]; + } + //--- check + if(state.m_needfij) + { + state.m_j[0].Set(0,s*MathExp(state.m_x[0])); + state.m_j[0].Set(1,0); + state.m_j[0].Set(2,0); + state.m_j[1].Set(0,0); + state.m_j[1].Set(1,2*state.m_x[1]); + state.m_j[1].Set(2,0); + state.m_j[2].Set(0,-1); + state.m_j[2].Set(1,0); + state.m_j[2].Set(2,1); + } + //--- check + if((state.m_needf || state.m_needfg) || state.m_needfgh) + state.m_f=s*CMath::Sqr(MathExp(state.m_x[0])-2)+CMath::Sqr(CMath::Sqr(state.m_x[1])+1)+CMath::Sqr(state.m_x[2]-state.m_x[0]); + //--- check + if(state.m_needfg || state.m_needfgh) + { + state.m_g[0]=s*2*(MathExp(state.m_x[0])-2)*MathExp(state.m_x[0])+2*(state.m_x[0]-state.m_x[2]); + state.m_g[1]=2*(CMath::Sqr(state.m_x[1])+1)*2*state.m_x[1]; + state.m_g[2]=2*(state.m_x[2]-state.m_x[0]); + } + //--- check + if(state.m_needfgh) + { + state.m_h[0].Set(0,s*(4*CMath::Sqr(MathExp(state.m_x[0]))-4*MathExp(state.m_x[0]))+2); + state.m_h[0].Set(1,0); + state.m_h[0].Set(2,-2); + state.m_h[1].Set(0,0); + state.m_h[1].Set(1,12*CMath::Sqr(state.m_x[1])+4); + state.m_h[1].Set(2,0); + state.m_h[2].Set(0,-2); + state.m_h[2].Set(1,0); + state.m_h[2].Set(2,2); + } + //--- search errors + scerror=scerror || !RKindVSStateCheck(rkind,state); + } + //--- function call + CMinLM::MinLMResults(state,x,rep); + //--- check + if(ckind==0) + { + //--- search errors + converror=converror || MathAbs(x[0]-MathLog(2))>0.05; + converror=converror || MathAbs(x[1])>0.05; + converror=converror || MathAbs(x[2]-MathLog(2))>0.05; + converror=converror || rep.m_terminationtype!=1; + } + //--- check + if(ckind==1) + { + //--- search errors + converror=converror || MathAbs(x[0]-MathLog(2))>0.05; + converror=converror || MathAbs(x[1])>0.05; + converror=converror || MathAbs(x[2]-MathLog(2))>0.05; + converror=converror || rep.m_terminationtype!=2; + } + //--- check + if(ckind==2) + { + //--- search errors + converror=(converror || rep.m_terminationtype!=5) || rep.m_iterationscount!=maxits; + } + //--- check + if(ckind==3) + { + //--- search errors + converror=converror || MathAbs(x[0]-MathLog(2))>0.05; + converror=converror || MathAbs(x[1])>0.05; + converror=converror || MathAbs(x[2]-MathLog(2))>0.05; + converror=converror || rep.m_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=100; + //--- allocation + ArrayResize(x,n); + ArrayResize(xlast,n); + for(i=0;i<=n-1;i++) + x[i]=6; + //--- check + if(rkind==0) + CMinLM::MinLMCreateFJ(n,m,x,state); + //--- check + if(rkind==1) + CMinLM::MinLMCreateFGJ(n,m,x,state); + //--- check + if(rkind==2) + CMinLM::MinLMCreateFGH(n,x,state); + //--- check + if(rkind==3) + { + CMinLM::MinLMCreateVJ(n,m,x,state); + CMinLM::MinLMSetAccType(state,0); + } + //--- check + if(rkind==4) + { + CMinLM::MinLMCreateVJ(n,m,x,state); + CMinLM::MinLMSetAccType(state,1); + } + //--- check + if(rkind==5) + { + CMinLM::MinLMCreateVJ(n,m,x,state); + CMinLM::MinLMSetAccType(state,2); + } + //--- function calls + CMinLM::MinLMSetCond(state,0,0,0,4); + CMinLM::MinLMSetXRep(state,true); + //--- change value + fprev=CMath::m_maxrealnumber; + //--- cycle + while(CMinLM::MinLMIteration(state)) + { + //--- check + if(state.m_needfi || state.m_needfij) + { + state.m_fi[0]=MathSqrt(s)*(MathExp(state.m_x[0])-2); + state.m_fi[1]=state.m_x[1]; + state.m_fi[2]=state.m_x[2]-state.m_x[0]; + } + //--- check + if(state.m_needfij) + { + state.m_j[0].Set(0,MathSqrt(s)*MathExp(state.m_x[0])); + state.m_j[0].Set(1,0); + state.m_j[0].Set(2,0); + state.m_j[1].Set(0,0); + state.m_j[1].Set(1,1); + state.m_j[1].Set(2,0); + state.m_j[2].Set(0,-1); + state.m_j[2].Set(1,0); + state.m_j[2].Set(2,1); + } + //--- check + if((state.m_needf || state.m_needfg) || state.m_needfgh) + state.m_f=s*CMath::Sqr(MathExp(state.m_x[0])-2)+CMath::Sqr(state.m_x[1])+CMath::Sqr(state.m_x[2]-state.m_x[0]); + //--- check + if(state.m_needfg || state.m_needfgh) + { + state.m_g[0]=s*2*(MathExp(state.m_x[0])-2)*MathExp(state.m_x[0])+2*(state.m_x[0]-state.m_x[2]); + state.m_g[1]=2*state.m_x[1]; + state.m_g[2]=2*(state.m_x[2]-state.m_x[0]); + } + //--- check + if(state.m_needfgh) + { + state.m_h[0].Set(0,s*(4*CMath::Sqr(MathExp(state.m_x[0]))-4*MathExp(state.m_x[0]))+2); + state.m_h[0].Set(1,0); + state.m_h[0].Set(2,-2); + state.m_h[1].Set(0,0); + state.m_h[1].Set(1,2); + state.m_h[1].Set(2,0); + state.m_h[2].Set(0,-2); + state.m_h[2].Set(1,0); + state.m_h[2].Set(2,2); + } + //--- search errors + scerror=scerror || !RKindVSStateCheck(rkind,state); + //--- check + if(state.m_xupdated) + { + othererrors=othererrors || state.m_f>fprev; + //--- check + if(fprev==CMath::m_maxrealnumber) + { + for(i=0;i<=n-1;i++) + othererrors=othererrors || state.m_x[i]!=x[i]; + } + fprev=state.m_f; + for(i_=0;i_<=n-1;i_++) + xlast[i_]=state.m_x[i_]; + } + } + //--- function call + CMinLM::MinLMResults(state,x,rep); + //--- search errors + for(i=0;i<=n-1;i++) + othererrors=othererrors || x[i]!=xlast[i]; + } + n=1; +//--- allocation + ArrayResize(x,n); + x[0]=100; + stpmax=0.05+0.05*CMath::RandomReal(); +//--- function calls + CMinLM::MinLMCreateFGH(n,x,state); + CMinLM::MinLMSetCond(state,1.0E-9,0,0,0); + CMinLM::MinLMSetStpMax(state,stpmax); + CMinLM::MinLMSetXRep(state,true); + xprev=x[0]; +//--- cycle + while(CMinLM::MinLMIteration(state)) + { + //--- check + if((state.m_needf || state.m_needfg) || state.m_needfgh) + state.m_f=MathExp(state.m_x[0])+MathExp(-state.m_x[0]); + //--- check + if(state.m_needfg || state.m_needfgh) + state.m_g[0]=MathExp(state.m_x[0])-MathExp(-state.m_x[0]); + //--- check + if(state.m_needfgh) + state.m_h[0].Set(0,MathExp(state.m_x[0])+MathExp(-state.m_x[0])); + //--- search errors + othererrors=othererrors || MathAbs(state.m_x[0]-xprev)>(double)((1+MathSqrt(CMath::m_machineepsilon))*stpmax); + //--- check + if(state.m_xupdated) + xprev=state.m_x[0]; + } +//--- end + waserrors=((((((referror || lin1error) || lin2error) || eqerror) || converror) || scerror) || othererrors) || restartserror; +//--- check + if(!silent) + { + Print("TESTING LEVENBERG-MARQUARDT OPTIMIZATION"); + Print("REFERENCE PROBLEMS: "); + //--- check + if(referror) + Print("FAILED"); + else + Print("OK"); + Print("1-D PROBLEM #1: "); + //--- check + if(lin1error) + Print("FAILED"); + else + Print("OK"); + Print("1-D PROBLEM #2: "); + //--- check + if(lin2error) + Print("FAILED"); + else + Print("OK"); + Print("LINEAR EQUATIONS: "); + //--- check + if(eqerror) + Print("FAILED"); + else + Print("OK"); + Print("RESTARTS: "); + //--- check + if(restartserror) + Print("FAILED"); + else + Print("OK"); + Print("CONVERGENCE PROPERTIES: "); + //--- check + if(converror) + Print("FAILED"); + else + Print("OK"); + Print("STATE FIELDS CONSISTENCY: "); + //--- check + if(scerror) + Print("FAILED"); + else + Print("OK"); + Print("OTHER PROPERTIES: "); + //--- check + if(othererrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| 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 bool CTestMinLMUnit::RKindVSStateCheck(const int rkind,CMinLMState &state) + { +//--- create a variable + int nset=0; +//--- check + if(state.m_needfi) + nset=nset+1; +//--- check + if(state.m_needf) + nset=nset+1; +//--- check + if(state.m_needfg) + nset=nset+1; +//--- check + if(state.m_needfij) + nset=nset+1; +//--- check + if(state.m_needfgh) + nset=nset+1; +//--- check + if(state.m_xupdated) + nset=nset+1; +//--- check + if(nset!=1) + return(false); +//--- check + if(rkind==-2) + return(state.m_needfi || state.m_xupdated); +//--- check + if(rkind==-1) + return(state.m_needfi || state.m_xupdated); +//--- check + if(rkind==0) + return(state.m_needf || state.m_needfij || state.m_xupdated); +//--- check + if(rkind==1) + return(state.m_needf || state.m_needfij || state.m_needfg || state.m_xupdated); +//--- check + if(rkind==2) + return(state.m_needf || state.m_needfg || state.m_needfgh || state.m_xupdated); +//--- check + if(rkind==3) + return(state.m_needfi || state.m_needfij || state.m_xupdated); +//--- check + if(rkind==4) + return(state.m_needfi || state.m_needfij || state.m_xupdated); +//--- check + if(rkind==5) + return(state.m_needfi || state.m_needfij || state.m_xupdated); +//--- return result + return(false); + } +//+------------------------------------------------------------------+ +//| Calculates FI/F/G/H for problem min(||Ax-b||) | +//+------------------------------------------------------------------+ +static void CTestMinLMUnit::AXMB(CMinLMState &state,CMatrixDouble &a, + double &b[],const int n) + { +//--- create variables + int i=0; + int j=0; + int k=0; + double v=0; + int i_=0; +//--- check + if((state.m_needf || state.m_needfg) || state.m_needfgh) + state.m_f=0; +//--- check + if(state.m_needfg || state.m_needfgh) + { + for(i=0;i<=n-1;i++) + state.m_g[i]=0; + } +//--- check + if(state.m_needfgh) + { + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + state.m_h[i].Set(j,0); + } + } +//--- calculation + for(i=0;i<=n-1;i++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=a[i][i_]*state.m_x[i_]; + //--- check + if((state.m_needf || state.m_needfg) || state.m_needfgh) + state.m_f=state.m_f+CMath::Sqr(v-b[i]); + //--- check + if(state.m_needfg || state.m_needfgh) + { + for(j=0;j<=n-1;j++) + state.m_g[j]=state.m_g[j]+2*(v-b[i])*a[i][j]; + } + //--- check + if(state.m_needfgh) + { + for(j=0;j<=n-1;j++) + { + for(k=0;k<=n-1;k++) + state.m_h[j].Set(k,state.m_h[j][k]+2*a[i][j]*a[i][k]); + } + } + //--- check + if(state.m_needfi) + state.m_fi[i]=v-b[i]; + //--- check + if(state.m_needfij) + { + state.m_fi[i]=v-b[i]; + for(i_=0;i_<=n-1;i_++) + state.m_j[i].Set(i_,a[i][i_]); + } + } + } +//+------------------------------------------------------------------+ +//| Testing class CLSFit | +//+------------------------------------------------------------------+ +class CTestLSFitUnit + { +private: + //--- private methods + static void TestPolynomialFitting(bool &fiterrors); + static void TestRationalFitting(bool &fiterrors); + static void TestSplineFitting(bool &fiterrors); + static void TestGeneralFitting(bool &llserrors,bool &nlserrors); + static bool IsGLSSolution(const int n,const int m,const int k,double &y[],double &w[],CMatrixDouble &fmatrix,CMatrixDouble &cmatrix,double &cc[]); + static double GetGLSError(const int n,const int m,double &y[],double &w[],CMatrixDouble &fmatrix,double &c[]); + static void FitLinearNonlinear(const int m,const int deravailable,CMatrixDouble &xy,CLSFitState &state,bool &nlserrors); +public: + //--- constructor, destructor + CTestLSFitUnit(void); + ~CTestLSFitUnit(void); + //--- public method + static bool TestLSFit(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestLSFitUnit::CTestLSFitUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestLSFitUnit::~CTestLSFitUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CLSFit | +//+------------------------------------------------------------------+ +static bool CTestLSFitUnit::TestLSFit(const bool silent) + { +//--- create variables + bool waserrors; + bool llserrors; + bool nlserrors; + bool polfiterrors; + bool ratfiterrors; + bool splfiterrors; +//--- initialization + waserrors=false; +//--- function calls + TestPolynomialFitting(polfiterrors); + TestRationalFitting(ratfiterrors); + TestSplineFitting(splfiterrors); + TestGeneralFitting(llserrors,nlserrors); +//--- report + waserrors=(((llserrors || nlserrors) || polfiterrors) || ratfiterrors) || splfiterrors; +//--- check + if(!silent) + { + Print("TESTING LEAST SQUARES"); + Print("POLYNOMIAL LEAST SQUARES: "); + //--- check + if(polfiterrors) + Print("FAILED"); + else + Print("OK"); + Print("RATIONAL LEAST SQUARES: "); + //--- check + if(ratfiterrors) + Print("FAILED"); + else + Print("OK"); + Print("SPLINE LEAST SQUARES: "); + //--- check + if(splfiterrors) + Print("FAILED"); + else + Print("OK"); + Print("LINEAR LEAST SQUARES: "); + //--- check + if(llserrors) + Print("FAILED"); + else + Print("OK"); + Print("NON-LINEAR LEAST SQUARES: "); + //--- check + if(nlserrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- end + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Unit test | +//+------------------------------------------------------------------+ +static void CTestLSFitUnit::TestPolynomialFitting(bool &fiterrors) + { +//--- create variables + double threshold=0; + double t=0; + int i=0; + int k=0; + int info=0; + int info2=0; + double v=0; + double v0=0; + double v1=0; + double v2=0; + double s=0; + double xmin=0; + double xmax=0; + double refrms=0; + double refavg=0; + double refavgrel=0; + double refmax=0; + int n=0; + int m=0; + int maxn=0; + int pass=0; + int passcount=0; +//--- create arrays + double x[]; + double y[]; + double w[]; + double x2[]; + double y2[]; + double w2[]; + double xfull[]; + double yfull[]; + double xc[]; + double yc[]; + int dc[]; +//--- objects of classes êëàññîâ + CBarycentricInterpolant p; + CBarycentricInterpolant p1; + CBarycentricInterpolant p2; + CPolynomialFitReport rep; + CPolynomialFitReport rep2; +//--- initialization + fiterrors=false; + maxn=5; + passcount=20; + threshold=1.0E8*CMath::m_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++) + { + CApServ::TaskGenInt1D(-1,1,n,xfull,yfull); + //--- allocation + ArrayResize(x,n-k); + ArrayResize(y,n-k); + ArrayResize(w,n-k); + //--- check + if(k>0) + { + //--- allocation + ArrayResize(xc,k); + ArrayResize(yc,k); + ArrayResize(dc,k); + } + //--- change values + for(i=0;i<=n-k-1;i++) + { + x[i]=xfull[i]; + y[i]=yfull[i]; + w[i]=1+CMath::RandomReal(); + } + //--- change values + for(i=0;i<=k-1;i++) + { + xc[i]=xfull[n-k+i]; + yc[i]=yfull[n-k+i]; + dc[i]=0; + } + //--- function call + CLSFit::PolynomialFitWC(x,y,w,n-k,xc,yc,dc,k,n,info,p1,rep); + //--- check + if(info<=0) + fiterrors=true; + else + { + //--- search errors + for(i=0;i<=n-k-1;i++) + fiterrors=fiterrors || MathAbs(CRatInt::BarycentricCalc(p1,x[i])-y[i])>threshold; + for(i=0;i<=k-1;i++) + fiterrors=fiterrors || MathAbs(CRatInt::BarycentricCalc(p1,xc[i])-yc[i])>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++) + { + CApServ::TaskGenInt1D(-1,1,n,x,y); + //--- allocation + ArrayResize(w,n); + ArrayResize(xc,2); + ArrayResize(yc,2); + ArrayResize(dc,2); + //--- change values + for(i=0;i<=n-1;i++) + w[i]=1+CMath::RandomReal(); + xc[0]=0; + yc[0]=2*CMath::RandomReal()-1; + dc[0]=0; + xc[1]=0; + yc[1]=2*CMath::RandomReal()-1; + dc[1]=1; + //--- function call + CLSFit::PolynomialFitWC(x,y,w,n,xc,yc,dc,k,m,info,p1,rep); + //--- check + if(info<=0) + fiterrors=true; + else + { + //--- function call + CRatInt::BarycentricDiff1(p1,0.0,v0,v1); + fiterrors=fiterrors || MathAbs(v0-yc[0])>threshold; + //--- check + if(k==2) + fiterrors=fiterrors || MathAbs(v1-yc[1])>threshold; + } + } + } + } + } + } +//--- calculation + 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; + ArrayResize(x2,n); + ArrayResize(y2,n); + ArrayResize(w2,n); + xmin=0; + xmax=2*M_PI; + //--- change values + for(i=0;i<=n-1;i++) + { + x2[i]=2*M_PI*CMath::RandomReal(); + y2[i]=MathSin(x2[i]); + w2[i]=1; + } + //--- allocation + ArrayResize(x,m); + ArrayResize(y,m); + for(i=0;i<=m-1;i++) + { + x[i]=xmin+(xmax-xmin)*i/(m-1); + y[i]=MathSin(x[i]); + } + //--- function calls + CPolInt::PolynomialBuild(x,y,m,p1); + CLSFit::PolynomialFitWC(x2,y2,w2,n,xc,yc,dc,0,m,info,p2,rep); + //--- check + if(info<=0) + fiterrors=true; + else + { + //--- calculate P1 (interpolant) RMS error,compare with P2 error + v1=0; + v2=0; + for(i=0;i<=n-1;i++) + { + v1=v1+CMath::Sqr(CRatInt::BarycentricCalc(p1,x2[i])-y2[i]); + v2=v2+CMath::Sqr(CRatInt::BarycentricCalc(p2,x2[i])-y2[i]); + } + v1=MathSqrt(v1/n); + v2=MathSqrt(v2/n); + //--- search errors + fiterrors=fiterrors || v2>v1; + fiterrors=fiterrors || MathAbs(v2-rep.m_rmserror)>threshold; + } + //--- compare weighted and non-weighted + n=20; + ArrayResize(x,n); + ArrayResize(y,n); + ArrayResize(w,n); + for(i=0;i<=n-1;i++) + { + x[i]=2*CMath::RandomReal()-1; + y[i]=2*CMath::RandomReal()-1; + w[i]=1; + } + //--- function calls + CLSFit::PolynomialFitWC(x,y,w,n,xc,yc,dc,0,m,info,p1,rep); + CLSFit::PolynomialFit(x,y,n,m,info2,p2,rep2); + //--- check + if(info<=0 || info2<=0) + fiterrors=true; + else + { + //--- calculate P1 (interpolant),compare with P2 error + //--- compare RMS errors + t=2*CMath::RandomReal()-1; + v1=CRatInt::BarycentricCalc(p1,t); + v2=CRatInt::BarycentricCalc(p2,t); + //--- search errors + fiterrors=fiterrors || v2!=v1; + fiterrors=fiterrors || rep.m_rmserror!=rep2.m_rmserror; + fiterrors=fiterrors || rep.m_avgerror!=rep2.m_avgerror; + fiterrors=fiterrors || rep.m_avgrelerror!=rep2.m_avgrelerror; + fiterrors=fiterrors || rep.m_maxerror!=rep2.m_maxerror; + } + } + } +//--- calculation + for(m=1;m<=maxn;m++) + { + for(pass=1;pass<=passcount;pass++) + { + //--- check + if(!CAp::Assert(passcount>=2,"PassCount should be 2 or greater!")) + return; + //--- 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; + //--- check + if(pass==1) + { + v1=0; + v2=0; + v=0; + } + else + { + v1=CMath::RandomReal(); + v2=CMath::RandomReal(); + v=1+CMath::RandomReal(); + } + //--- allocation + ArrayResize(x,n); + ArrayResize(y,n); + ArrayResize(w,n); + //--- change values + for(i=0;i<=maxn-1;i++) + { + x[4*i+0]=i; + y[4*i+0]=v-v2; + w[4*i+0]=1; + x[4*i+1]=i; + y[4*i+1]=v-v1; + w[4*i+1]=1; + x[4*i+2]=i; + y[4*i+2]=v+v1; + w[4*i+2]=1; + x[4*i+3]=i; + y[4*i+3]=v+v2; + w[4*i+3]=1; + } + //--- change values + refrms=MathSqrt((CMath::Sqr(v1)+CMath::Sqr(v2))/2); + refavg=(MathAbs(v1)+MathAbs(v2))/2; + //--- check + if(pass==1) + refavgrel=0; + else + refavgrel=0.25*(MathAbs(v2)/MathAbs(v-v2)+MathAbs(v1)/MathAbs(v-v1)+MathAbs(v1)/MathAbs(v+v1)+MathAbs(v2)/MathAbs(v+v2)); + refmax=MathMax(v1,v2); + //--- Test errors correctness + CLSFit::PolynomialFit(x,y,n,m,info,p,rep); + //--- check + if(info<=0) + fiterrors=true; + else + { + s=CRatInt::BarycentricCalc(p,0); + //--- search errors + fiterrors=fiterrors || MathAbs(s-v)>threshold; + fiterrors=fiterrors || MathAbs(rep.m_rmserror-refrms)>threshold; + fiterrors=fiterrors || MathAbs(rep.m_avgerror-refavg)>threshold; + fiterrors=fiterrors || MathAbs(rep.m_avgrelerror-refavgrel)>threshold; + fiterrors=fiterrors || MathAbs(rep.m_maxerror-refmax)>threshold; + } + } + } + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestLSFitUnit::TestRationalFitting(bool &fiterrors) + { +//--- create variables + double threshold=0; + int maxn=0; + int passcount=0; + int n=0; + int m=0; + int i=0; + int k=0; + int pass=0; + double t=0; + double s=0; + double v=0; + double v0=0; + double v1=0; + double v2=0; + int info=0; + int info2=0; + double xmin=0; + double xmax=0; + double refrms=0; + double refavg=0; + double refavgrel=0; + double refmax=0; +//--- create arrays + double x[]; + double x2[]; + double y[]; + double y2[]; + double w[]; + double w2[]; + double xc[]; + double yc[]; + int dc[]; +//--- objects of classes + CBarycentricInterpolant b1; + CBarycentricInterpolant b2; + CBarycentricFitReport rep; + CBarycentricFitReport rep2; +//--- initialization + fiterrors=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*CMath::m_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++) + { + //--- allocation + ArrayResize(x,n-k); + ArrayResize(y,n-k); + ArrayResize(w,n-k); + //--- check + if(k>0) + { + //--- allocation + ArrayResize(xc,k); + ArrayResize(yc,k); + ArrayResize(dc,k); + } + //--- change values + for(i=0;i<=n-k-1;i++) + { + x[i]=(double)i/(double)(n-1); + y[i]=2*CMath::RandomReal()-1; + w[i]=1+CMath::RandomReal(); + } + for(i=0;i<=k-1;i++) + { + xc[i]=(double)(n-k+i)/(double)(n-1); + yc[i]=2*CMath::RandomReal()-1; + dc[i]=0; + } + //--- function call + CLSFit::BarycentricFitFloaterHormannWC(x,y,w,n-k,xc,yc,dc,k,n,info,b1,rep); + //--- check + if(info<=0) + fiterrors=true; + else + { + //--- search errors + for(i=0;i<=n-k-1;i++) + fiterrors=fiterrors || MathAbs(CRatInt::BarycentricCalc(b1,x[i])-y[i])>threshold; + for(i=0;i<=k-1;i++) + fiterrors=fiterrors || MathAbs(CRatInt::BarycentricCalc(b1,xc[i])-yc[i])>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++) + { + //--- allocation + ArrayResize(x,n); + ArrayResize(y,n); + ArrayResize(w,n); + ArrayResize(xc,2); + ArrayResize(yc,2); + ArrayResize(dc,2); + for(i=0;i<=n-1;i++) + { + x[i]=2*CMath::RandomReal()-1; + y[i]=2*CMath::RandomReal()-1; + w[i]=1+CMath::RandomReal(); + } + //--- change values + xc[0]=-1; + yc[0]=2*CMath::RandomReal()-1; + dc[0]=0; + xc[1]=1; + yc[1]=2*CMath::RandomReal()-1; + dc[1]=0; + //--- function call + CLSFit::BarycentricFitFloaterHormannWC(x,y,w,n,xc,yc,dc,k,m,info,b1,rep); + //--- check + if(info<=0) + fiterrors=true; + else + { + for(i=0;i<=k-1;i++) + { + CRatInt::BarycentricDiff1(b1,xc[i],v0,v1); + //--- search errors + fiterrors=fiterrors || MathAbs(v0-yc[i])>threshold; + } + } + } + } + } + } +//--- calculation + 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; + ArrayResize(x2,n); + ArrayResize(y2,n); + ArrayResize(w2,n); + //--- change values + xmin=CMath::m_maxrealnumber; + xmax=-CMath::m_maxrealnumber; + for(i=0;i<=n-1;i++) + { + x2[i]=2*M_PI*CMath::RandomReal(); + y2[i]=MathSin(x2[i]); + w2[i]=1; + xmin=MathMin(xmin,x2[i]); + xmax=MathMax(xmax,x2[i]); + } + //--- allocation + ArrayResize(x,m); + ArrayResize(y,m); + for(i=0;i<=m-1;i++) + { + x[i]=xmin+(xmax-xmin)*i/(m-1); + y[i]=MathSin(x[i]); + } + //--- function call + CRatInt::BarycentricBuildFloaterHormann(x,y,m,3,b1); + CLSFit::BarycentricFitFloaterHormannWC(x2,y2,w2,n,xc,yc,dc,0,m,info,b2,rep); + //--- check + if(info<=0) + fiterrors=true; + else + { + //--- calculate B1 (interpolant) RMS error,compare with B2 error + v1=0; + v2=0; + for(i=0;i<=n-1;i++) + { + v1=v1+CMath::Sqr(CRatInt::BarycentricCalc(b1,x2[i])-y2[i]); + v2=v2+CMath::Sqr(CRatInt::BarycentricCalc(b2,x2[i])-y2[i]); + } + v1=MathSqrt(v1/n); + v2=MathSqrt(v2/n); + //--- search errors + fiterrors=fiterrors || v2>v1; + fiterrors=fiterrors || MathAbs(v2-rep.m_rmserror)>threshold; + } + //--- compare weighted and non-weighted + n=20; + ArrayResize(x,n); + ArrayResize(y,n); + ArrayResize(w,n); + //--- change values + for(i=0;i<=n-1;i++) + { + x[i]=2*CMath::RandomReal()-1; + y[i]=2*CMath::RandomReal()-1; + w[i]=1; + } + //--- function calls + CLSFit::BarycentricFitFloaterHormannWC(x,y,w,n,xc,yc,dc,0,m,info,b1,rep); + CLSFit::BarycentricFitFloaterHormann(x,y,n,m,info2,b2,rep2); + //--- check + if(info<=0 || info2<=0) + fiterrors=true; + else + { + //--- calculate B1 (interpolant),compare with B2 + //--- compare RMS errors + t=2*CMath::RandomReal()-1; + v1=CRatInt::BarycentricCalc(b1,t); + v2=CRatInt::BarycentricCalc(b2,t); + //--- search errors + fiterrors=fiterrors || v2!=v1; + fiterrors=fiterrors || rep.m_rmserror!=rep2.m_rmserror; + fiterrors=fiterrors || rep.m_avgerror!=rep2.m_avgerror; + fiterrors=fiterrors || rep.m_avgrelerror!=rep2.m_avgrelerror; + fiterrors=fiterrors || rep.m_maxerror!=rep2.m_maxerror; + } + } + } +//--- calculation + for(pass=1;pass<=passcount;pass++) + { + //--- check + if(!CAp::Assert(passcount>=2,"PassCount should be 2 or greater!")) + return; + //--- 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=0; + v2=0; + v=0; + } + else + { + v1=CMath::RandomReal(); + v2=CMath::RandomReal(); + v=1+CMath::RandomReal(); + } + //--- allocation + ArrayResize(x,4); + ArrayResize(y,4); + ArrayResize(w,4); + //--- change values + x[0]=0; + y[0]=v-v2; + w[0]=1; + x[1]=0; + y[1]=v-v1; + w[1]=1; + x[2]=0; + y[2]=v+v1; + w[2]=1; + x[3]=0; + y[3]=v+v2; + w[3]=1; + refrms=MathSqrt((CMath::Sqr(v1)+CMath::Sqr(v2))/2); + refavg=(MathAbs(v1)+MathAbs(v2))/2; + //--- check + if(pass==1) + refavgrel=0; + else + refavgrel=0.25*(MathAbs(v2)/MathAbs(v-v2)+MathAbs(v1)/MathAbs(v-v1)+MathAbs(v1)/MathAbs(v+v1)+MathAbs(v2)/MathAbs(v+v2)); + refmax=MathMax(v1,v2); + //--- Test errors correctness + CLSFit::BarycentricFitFloaterHormann(x,y,4,2,info,b1,rep); + //--- check + if(info<=0) + fiterrors=true; + else + { + s=CRatInt::BarycentricCalc(b1,0); + //--- search errors + fiterrors=fiterrors || MathAbs(s-v)>threshold; + fiterrors=fiterrors || MathAbs(rep.m_rmserror-refrms)>threshold; + fiterrors=fiterrors || MathAbs(rep.m_avgerror-refavg)>threshold; + fiterrors=fiterrors || MathAbs(rep.m_avgrelerror-refavgrel)>threshold; + fiterrors=fiterrors || MathAbs(rep.m_maxerror-refmax)>threshold; + } + } + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestLSFitUnit::TestSplineFitting(bool &fiterrors) + { +//--- create variables + double threshold=0; + double nonstrictthreshold=0; + int passcount=0; + int n=0; + int m=0; + int i=0; + int k=0; + int pass=0; + double sa=0; + double sb=0; + int info=0; + int info1=0; + int info2=0; + double s=0; + double ds=0; + double d2s=0; + int stype=0; + double t=0; + double v=0; + double v1=0; + double v2=0; + double refrms=0; + double refavg=0; + double refavgrel=0; + double refmax=0; + double rho=0; +//--- create arrays + double x[]; + double y[]; + double w[]; + double w2[]; + double xc[]; + double yc[]; + double d[]; + int dc[]; +//--- objects of classes êëàññîâ + CSpline1DInterpolant c; + CSpline1DInterpolant c2; + CSpline1DFitReport rep; + CSpline1DFitReport rep2; +//--- Valyes: +//--- * pass count +//--- * threshold - for tests which must be satisfied exactly +//--- * nonstrictthreshold - for approximate tests + passcount=20; + threshold=10000*CMath::m_machineepsilon; + nonstrictthreshold=1.0E-4; + fiterrors=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++) + { + //--- check + if(k>=m) + continue; + n=100; + //--- allocation + ArrayResize(x,n); + ArrayResize(y,n); + ArrayResize(w,n); + ArrayResize(xc,4); + ArrayResize(yc,4); + ArrayResize(dc,4); + //--- change values + sa=1+CMath::RandomReal(); + sb=2*CMath::RandomReal()-1; + for(i=0;i<=n-1;i++) + { + x[i]=sa*CMath::RandomReal()+sb; + y[i]=2*CMath::RandomReal()-1; + w[i]=1+CMath::RandomReal(); + } + xc[0]=sb; + yc[0]=2*CMath::RandomReal()-1; + dc[0]=0; + xc[1]=sb; + yc[1]=2*CMath::RandomReal()-1; + dc[1]=1; + xc[2]=sa+sb; + yc[2]=2*CMath::RandomReal()-1; + dc[2]=0; + xc[3]=sa+sb; + yc[3]=2*CMath::RandomReal()-1; + dc[3]=1; + //--- function call + CLSFit::Spline1DFitCubicWC(x,y,w,n,xc,yc,dc,k,m,info,c,rep); + //--- check + if(info<=0) + fiterrors=true; + else + { + //--- Check that constraints are satisfied + for(i=0;i<=k-1;i++) + { + CSpline1D::Spline1DDiff(c,xc[i],s,ds,d2s); + //--- check + if(dc[i]==0) + fiterrors=fiterrors || MathAbs(s-yc[i])>threshold; + //--- check + if(dc[i]==1) + fiterrors=fiterrors || MathAbs(ds-yc[i])>threshold; + //--- check + if(dc[i]==2) + fiterrors=fiterrors || MathAbs(d2s-yc[i])>threshold; + } + } + } + } + //--- Cubic splines + //--- Ability to handle one internal constraint + for(m=4;m<=8;m++) + { + n=100; + ArrayResize(x,n); + ArrayResize(y,n); + ArrayResize(w,n); + ArrayResize(xc,1); + ArrayResize(yc,1); + ArrayResize(dc,1); + //--- change values + sa=1+CMath::RandomReal(); + sb=2*CMath::RandomReal()-1; + for(i=0;i<=n-1;i++) + { + x[i]=sa*CMath::RandomReal()+sb; + y[i]=2*CMath::RandomReal()-1; + w[i]=1+CMath::RandomReal(); + } + xc[0]=sa*CMath::RandomReal()+sb; + yc[0]=2*CMath::RandomReal()-1; + dc[0]=CMath::RandomInteger(2); + //--- function call + CLSFit::Spline1DFitCubicWC(x,y,w,n,xc,yc,dc,1,m,info,c,rep); + //--- check + if(info<=0) + fiterrors=true; + else + { + //--- Check that constraints are satisfied + CSpline1D::Spline1DDiff(c,xc[0],s,ds,d2s); + //--- check + if(dc[0]==0) + fiterrors=fiterrors || MathAbs(s-yc[0])>threshold; + //--- check + if(dc[0]==1) + fiterrors=fiterrors || MathAbs(ds-yc[0])>threshold; + //--- check + if(dc[0]==2) + fiterrors=fiterrors || MathAbs(d2s-yc[0])>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++) + { + //--- check + if(k>=m) + continue; + //--- check + if(m%2!=0) + continue; + n=100; + //--- allocation + ArrayResize(x,n); + ArrayResize(y,n); + ArrayResize(w,n); + ArrayResize(xc,4); + ArrayResize(yc,4); + ArrayResize(dc,4); + //--- change values + sa=1+CMath::RandomReal(); + sb=2*CMath::RandomReal()-1; + for(i=0;i<=n-1;i++) + { + x[i]=sa*CMath::RandomReal()+sb; + y[i]=2*CMath::RandomReal()-1; + w[i]=1+CMath::RandomReal(); + } + xc[0]=sb; + yc[0]=2*CMath::RandomReal()-1; + dc[0]=0; + xc[1]=sb; + yc[1]=2*CMath::RandomReal()-1; + dc[1]=1; + xc[2]=sa+sb; + yc[2]=2*CMath::RandomReal()-1; + dc[2]=0; + xc[3]=sa+sb; + yc[3]=2*CMath::RandomReal()-1; + dc[3]=1; + //--- function call + CLSFit::Spline1DFitHermiteWC(x,y,w,n,xc,yc,dc,k,m,info,c,rep); + //--- check + if(info<=0) + fiterrors=true; + else + { + //--- Check that constraints are satisfied + for(i=0;i<=k-1;i++) + { + CSpline1D::Spline1DDiff(c,xc[i],s,ds,d2s); + //--- check + if(dc[i]==0) + fiterrors=fiterrors || MathAbs(s-yc[i])>threshold; + //--- check + if(dc[i]==1) + fiterrors=fiterrors || MathAbs(ds-yc[i])>threshold; + //--- check + if(dc[i]==2) + fiterrors=fiterrors || MathAbs(d2s-yc[i])>threshold; + } + } + } + } + //--- Hermite splines + //--- Ability to handle one internal constraint + for(m=4;m<=8;m++) + { + //--- check + if(m%2!=0) + continue; + n=100; + //--- allocation + ArrayResize(x,n); + ArrayResize(y,n); + ArrayResize(w,n); + ArrayResize(xc,1); + ArrayResize(yc,1); + ArrayResize(dc,1); + //--- change values + sa=1+CMath::RandomReal(); + sb=2*CMath::RandomReal()-1; + for(i=0;i<=n-1;i++) + { + x[i]=sa*CMath::RandomReal()+sb; + y[i]=2*CMath::RandomReal()-1; + w[i]=1+CMath::RandomReal(); + } + xc[0]=sa*CMath::RandomReal()+sb; + yc[0]=2*CMath::RandomReal()-1; + dc[0]=CMath::RandomInteger(2); + //--- function call + CLSFit::Spline1DFitHermiteWC(x,y,w,n,xc,yc,dc,1,m,info,c,rep); + //--- check + if(info<=0) + fiterrors=true; + else + { + //--- Check that constraints are satisfied + CSpline1D::Spline1DDiff(c,xc[0],s,ds,d2s); + //--- check + if(dc[0]==0) + fiterrors=fiterrors || MathAbs(s-yc[0])>threshold; + //--- check + if(dc[0]==1) + fiterrors=fiterrors || MathAbs(ds-yc[0])>threshold; + //--- check + if(dc[0]==2) + fiterrors=fiterrors || MathAbs(d2s-yc[0])>threshold; + } + } + } +//--- calculation + for(m=4;m<=8;m++) + { + for(stype=0;stype<=1;stype++) + { + for(pass=1;pass<=passcount;pass++) + { + //--- check + 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+CMath::RandomReal(); + sb=2*CMath::RandomReal()-1; + //--- check + if(stype==0) + { + //--- allocation + ArrayResize(x,m-2); + ArrayResize(y,m-2); + //--- change values + for(i=0;i<=m-2-1;i++) + { + x[i]=sa*i/(m-2-1)+sb; + y[i]=2*CMath::RandomReal()-1; + } + //--- function call + CSpline1D::Spline1DBuildCubic(x,y,m-2,1,2*CMath::RandomReal()-1,1,2*CMath::RandomReal()-1,c2); + } + //--- check + if(stype==1) + { + //--- allocation + ArrayResize(x,m/2); + ArrayResize(y,m/2); + ArrayResize(d,m/2); + //--- change values + for(i=0;i<=m/2-1;i++) + { + x[i]=sa*i/(m/2-1)+sb; + y[i]=2*CMath::RandomReal()-1; + d[i]=2*CMath::RandomReal()-1; + } + //--- function call + CSpline1D::Spline1DBuildHermite(x,y,d,m/2,c2); + } + n=50; + //--- allocation + ArrayResize(x,2*n); + ArrayResize(y,2*n); + ArrayResize(w,2*n); + //--- calculation + 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=CMath::RandomReal(); + x[i]=sa*CMath::RandomReal()+sb; + //--- check + if(i==0) + x[i]=sb; + //--- check + if(i==1) + x[i]=sa+sb; + //--- change values + v=CSpline1D::Spline1DCalc(c2,x[i]); + y[i]=v+t; + w[i]=1+CMath::RandomReal(); + x[n+i]=x[i]; + y[n+i]=v-t; + w[n+i]=w[i]; + } + //--- check + if(stype==0) + CLSFit::Spline1DFitCubicWC(x,y,w,2*n,xc,yc,dc,0,m,info,c,rep); + //--- check + if(stype==1) + CLSFit::Spline1DFitHermiteWC(x,y,w,2*n,xc,yc,dc,0,m,info,c,rep); + //--- check + if(info<=0) + fiterrors=true; + else + { + for(i=0;i<=n-1;i++) + { + v=sa*CMath::RandomReal()+sb; + //--- search errors + fiterrors=fiterrors || MathAbs(CSpline1D::Spline1DCalc(c,v)-CSpline1D::Spline1DCalc(c2,v))>threshold; + } + } + } + } + } +//--- calculation + for(m=4;m<=8;m++) + { + for(pass=1;pass<=passcount;pass++) + { + //--- prepare points/weights + sa=1+CMath::RandomReal(); + sb=2*CMath::RandomReal()-1; + n=10+CMath::RandomInteger(10); + //--- allocation + ArrayResize(x,n); + ArrayResize(y,n); + ArrayResize(w,n); + for(i=0;i<=n-1;i++) + { + x[i]=sa*CMath::RandomReal()+sb; + y[i]=2*CMath::RandomReal()-1; + w[i]=1; + } + //--- Fit cubic with unity weights,without weights,then compare + if(m>=4) + { + //--- function calls + CLSFit::Spline1DFitCubicWC(x,y,w,n,xc,yc,dc,0,m,info1,c,rep); + CLSFit::Spline1DFitCubic(x,y,n,m,info2,c2,rep2); + //--- check + if(info1<=0 || info2<=0) + fiterrors=true; + else + { + for(i=0;i<=n-1;i++) + { + v=sa*CMath::RandomReal()+sb; + //--- search errors + fiterrors=fiterrors || CSpline1D::Spline1DCalc(c,v)!=CSpline1D::Spline1DCalc(c2,v); + fiterrors=fiterrors || rep.m_taskrcond!=rep2.m_taskrcond; + fiterrors=fiterrors || rep.m_rmserror!=rep2.m_rmserror; + fiterrors=fiterrors || rep.m_avgerror!=rep2.m_avgerror; + fiterrors=fiterrors || rep.m_avgrelerror!=rep2.m_avgrelerror; + fiterrors=fiterrors || rep.m_maxerror!=rep2.m_maxerror; + } + } + } + //--- Fit Hermite with unity weights,without weights,then compare + if(m>=4 && m%2==0) + { + CLSFit::Spline1DFitHermiteWC(x,y,w,n,xc,yc,dc,0,m,info1,c,rep); + CLSFit::Spline1DFitHermite(x,y,n,m,info2,c2,rep2); + //--- check + if(info1<=0 || info2<=0) + fiterrors=true; + else + { + for(i=0;i<=n-1;i++) + { + v=sa*CMath::RandomReal()+sb; + //--- search errors + fiterrors=fiterrors || CSpline1D::Spline1DCalc(c,v)!=CSpline1D::Spline1DCalc(c2,v); + fiterrors=fiterrors || rep.m_taskrcond!=rep2.m_taskrcond; + fiterrors=fiterrors || rep.m_rmserror!=rep2.m_rmserror; + fiterrors=fiterrors || rep.m_avgerror!=rep2.m_avgerror; + fiterrors=fiterrors || rep.m_avgrelerror!=rep2.m_avgrelerror; + fiterrors=fiterrors || rep.m_maxerror!=rep2.m_maxerror; + } + } + } + } + } +//--- 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=k; + //--- when we have two points (even with different weights), + //--- resulting spline must be equal to the straight line + ArrayResize(x,2); + ArrayResize(y,2); + ArrayResize(w,2); + x[0]=-0.5-CMath::RandomReal(); + y[0]=0.5+CMath::RandomReal(); + w[0]=1+CMath::RandomReal(); + x[1]=0.5+CMath::RandomReal(); + y[1]=0.5+CMath::RandomReal(); + w[1]=1+CMath::RandomReal(); + //--- function call + CLSFit::Spline1DFitPenalized(x,y,2,m,rho,info,c,rep); + //--- check + if(info>0) + { + v=2*CMath::RandomReal()-1; + v1=(v-x[0])/(x[1]-x[0])*y[1]+(v-x[1])/(x[0]-x[1])*y[0]; + //--- search errors + fiterrors=fiterrors || MathAbs(v1-CSpline1D::Spline1DCalc(c,v))>nonstrictthreshold; + } + else + fiterrors=true; + //--- function call + CLSFit::Spline1DFitPenalizedW(x,y,w,2,m,rho,info,c,rep); + //--- check + if(info>0) + { + v=2*CMath::RandomReal()-1; + v1=(v-x[0])/(x[1]-x[0])*y[1]+(v-x[1])/(x[0]-x[1])*y[0]; + //--- search errors + fiterrors=fiterrors || MathAbs(v1-CSpline1D::Spline1DCalc(c,v))>nonstrictthreshold; + } + else + fiterrors=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++) + { + //--- allocation + ArrayResize(x,n); + ArrayResize(y,n); + ArrayResize(w,n); + ArrayResize(w2,n); + //--- change values + s=1+MathExp(10*CMath::RandomReal()); + for(i=0;i<=n-1;i++) + { + x[i]=(double)i/(double)(n-1); + y[i]=CMath::RandomReal(); + w[i]=0.1+CMath::RandomReal(); + w2[i]=w[i]*s; + } + //--- function calls + CLSFit::Spline1DFitPenalizedW(x,y,w,n,m,rho,info,c,rep); + CLSFit::Spline1DFitPenalizedW(x,y,w2,n,m,rho,info2,c2,rep2); + //--- check + if(info>0 && info2>0) + { + v=CMath::RandomReal(); + v1=CSpline1D::Spline1DCalc(c,v); + v2=CSpline1D::Spline1DCalc(c2,v); + //--- search errors + fiterrors=fiterrors || MathAbs(v1-v2)>nonstrictthreshold; + } + else + fiterrors=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=-5; + //--- allocation + ArrayResize(x,n); + ArrayResize(y,n); + ArrayResize(w,n); + for(i=0;i<=n-1;i++) + { + x[i]=(double)i/(double)(n-1); + y[i]=CMath::RandomReal(); + w[i]=0.1+CMath::RandomReal(); + } + //--- function call + CLSFit::Spline1DFitPenalized(x,y,n,m,rho,info,c,rep); + //--- check + if(info>0) + { + //--- search errors + for(i=0;i<=n-1;i++) + fiterrors=fiterrors || MathAbs(y[i]-CSpline1D::Spline1DCalc(c,x[i]))>nonstrictthreshold; + } + else + fiterrors=true; + //--- function call + CLSFit::Spline1DFitPenalizedW(x,y,w,n,m,rho,info,c,rep); + //--- check + if(info>0) + { + //--- search errors + for(i=0;i<=n-1;i++) + fiterrors=fiterrors || MathAbs(y[i]-CSpline1D::Spline1DCalc(c,x[i]))>nonstrictthreshold; + } + else + fiterrors=true; + } +//--- Check correctness of error reports + for(pass=1;pass<=passcount;pass++) + { + //--- check + if(!CAp::Assert(passcount>=2,"PassCount should be 2 or greater!")) + return; + //--- 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=0; + v2=0; + v=0; + } + else + { + v1=CMath::RandomReal(); + v2=CMath::RandomReal(); + v=1+CMath::RandomReal(); + } + //--- allocation + ArrayResize(x,4); + ArrayResize(y,4); + ArrayResize(w,4); + //--- change values + x[0]=0; + y[0]=v-v2; + w[0]=1; + x[1]=0; + y[1]=v-v1; + w[1]=1; + x[2]=0; + y[2]=v+v1; + w[2]=1; + x[3]=0; + y[3]=v+v2; + w[3]=1; + refrms=MathSqrt((CMath::Sqr(v1)+CMath::Sqr(v2))/2); + refavg=(MathAbs(v1)+MathAbs(v2))/2; + //--- check + if(pass==1) + refavgrel=0; + else + refavgrel=0.25*(MathAbs(v2)/MathAbs(v-v2)+MathAbs(v1)/MathAbs(v-v1)+MathAbs(v1)/MathAbs(v+v1)+MathAbs(v2)/MathAbs(v+v2)); + refmax=MathMax(v1,v2); + //--- Test penalized spline + CLSFit::Spline1DFitPenalizedW(x,y,w,4,4,0.0,info,c,rep); + //--- check + if(info<=0) + fiterrors=true; + else + { + s=CSpline1D::Spline1DCalc(c,0); + //--- search errors + fiterrors=fiterrors || MathAbs(s-v)>threshold; + fiterrors=fiterrors || MathAbs(rep.m_rmserror-refrms)>threshold; + fiterrors=fiterrors || MathAbs(rep.m_avgerror-refavg)>threshold; + fiterrors=fiterrors || MathAbs(rep.m_avgrelerror-refavgrel)>threshold; + fiterrors=fiterrors || MathAbs(rep.m_maxerror-refmax)>threshold; + } + //--- Test cubic fitting + CLSFit::Spline1DFitCubic(x,y,4,4,info,c,rep); + //--- check + if(info<=0) + fiterrors=true; + else + { + s=CSpline1D::Spline1DCalc(c,0); + //--- search errors + fiterrors=fiterrors || MathAbs(s-v)>threshold; + fiterrors=fiterrors || MathAbs(rep.m_rmserror-refrms)>threshold; + fiterrors=fiterrors || MathAbs(rep.m_avgerror-refavg)>threshold; + fiterrors=fiterrors || MathAbs(rep.m_avgrelerror-refavgrel)>threshold; + fiterrors=fiterrors || MathAbs(rep.m_maxerror-refmax)>threshold; + } + //--- Test Hermite fitting + CLSFit::Spline1DFitHermite(x,y,4,4,info,c,rep); + //--- check + if(info<=0) + fiterrors=true; + else + { + s=CSpline1D::Spline1DCalc(c,0); + //--- search errors + fiterrors=fiterrors || MathAbs(s-v)>threshold; + fiterrors=fiterrors || MathAbs(rep.m_rmserror-refrms)>threshold; + fiterrors=fiterrors || MathAbs(rep.m_avgerror-refavg)>threshold; + fiterrors=fiterrors || MathAbs(rep.m_avgrelerror-refavgrel)>threshold; + fiterrors=fiterrors || MathAbs(rep.m_maxerror-refmax)>threshold; + } + } + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestLSFitUnit::TestGeneralFitting(bool &llserrors,bool &nlserrors) + { +//--- create variables + double threshold=0; + double nlthreshold=0; + int maxn=0; + int maxm=0; + int passcount=0; + int n=0; + int m=0; + int i=0; + int j=0; + int k=0; + int pass=0; + double xscale=0; + double diffstep=0; + double v=0; + double v1=0; + double v2=0; + int info=0; + int info2=0; + double refrms=0; + double refavg=0; + double refavgrel=0; + double refmax=0; +//--- create arrays + double x[]; + double y[]; + double w[]; + double w2[]; + double c[]; + double c2[]; +//--- create matrix + CMatrixDouble a; + CMatrixDouble a2; + CMatrixDouble cm; +//--- objects of classes + CLSFitReport rep; + CLSFitReport rep2; + CLSFitState state; +//--- initialization + llserrors=false; + nlserrors=false; + threshold=10000*CMath::m_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. + a.Resize(n,m); + ArrayResize(x,n); + ArrayResize(y,n); + ArrayResize(w,n); + xscale=0.9+0.1*CMath::RandomReal(); + for(i=0;i<=n-1;i++) + { + //--- check + if(n==1) + x[i]=2*CMath::RandomReal()-1; + else + x[i]=xscale*((double)(2*i)/(double)(n-1)-1); + //--- change values + y[i]=3*x[i]+MathExp(x[i]); + w[i]=1+CMath::RandomReal(); + a[i].Set(0,1); + //--- check + if(m>1) + a[i].Set(1,x[i]); + for(j=2;j<=m-1;j++) + a[i].Set(j,2*x[i]*a[i][j-1]-a[i][j-2]); + } + //--- 1. test weighted fitting (optimality) + //--- 2. Solve degenerate least squares task built on the basis + //--- of previous task + CLSFit::LSFitLinearW(y,w,a,n,m,info,c,rep); + //--- check + if(info<=0) + llserrors=true; + else + llserrors=llserrors || !IsGLSSolution(n,m,0,y,w,a,cm,c); + //--- allocation + a2.Resize(n,2*m); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=m-1;j++) + { + a2[i].Set(2*j+0,a[i][j]); + a2[i].Set(2*j+1,a[i][j]); + } + } + //--- function call + CLSFit::LSFitLinearW(y,w,a2,n,2*m,info,c2,rep); + //--- check + if(info<=0) + llserrors=true; + else + { + //--- test answer correctness using design matrix properties + //--- and previous task solution + for(j=0;j<=m-1;j++) + llserrors=llserrors || MathAbs(c2[2*j+0]+c2[2*j+1]-c[j])>threshold; + } + //--- test non-weighted fitting + ArrayResize(w2,n); + for(i=0;i<=n-1;i++) + w2[i]=1; + //--- function calls + CLSFit::LSFitLinearW(y,w2,a,n,m,info,c,rep); + CLSFit::LSFitLinear(y,a,n,m,info2,c2,rep2); + //--- check + if(info<=0 || info2<=0) + llserrors=true; + else + { + //--- test answer correctness + for(j=0;j<=m-1;j++) + llserrors=llserrors || MathAbs(c[j]-c2[j])>threshold; + //--- search errors + llserrors=llserrors || MathAbs(rep.m_taskrcond-rep2.m_taskrcond)>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) + { + //--- allocation + ArrayResize(c2,m); + //--- test function/gradient/Hessian-based weighted fitting + CLSFit::LSFitLinearW(y,w,a,n,m,info,c,rep); + for(i=0;i<=m-1;i++) + c2[i]=2*CMath::RandomReal()-1; + //--- function calls + CLSFit::LSFitCreateWF(a,y,w,c2,n,m,m,diffstep,state); + CLSFit::LSFitSetCond(state,0.0,nlthreshold,0); + FitLinearNonlinear(m,0,a,state,nlserrors); + CLSFit::LSFitResults(state,info,c2,rep2); + //--- check + if(info<=0) + nlserrors=true; + else + { + //--- search errors + for(i=0;i<=m-1;i++) + nlserrors=nlserrors || MathAbs(c[i]-c2[i])>100*nlthreshold; + } + //--- change values + for(i=0;i<=m-1;i++) + c2[i]=2*CMath::RandomReal()-1; + //--- function calls + CLSFit::LSFitCreateWFG(a,y,w,c2,n,m,m,CMath::RandomReal()>0.5,state); + CLSFit::LSFitSetCond(state,0.0,nlthreshold,0); + FitLinearNonlinear(m,1,a,state,nlserrors); + CLSFit::LSFitResults(state,info,c2,rep2); + //--- check + if(info<=0) + nlserrors=true; + else + { + //--- search errors + for(i=0;i<=m-1;i++) + nlserrors=nlserrors || MathAbs(c[i]-c2[i])>100*nlthreshold; + } + //--- change values + for(i=0;i<=m-1;i++) + c2[i]=2*CMath::RandomReal()-1; + //--- function calls + CLSFit::LSFitCreateWFGH(a,y,w,c2,n,m,m,state); + CLSFit::LSFitSetCond(state,0.0,nlthreshold,0); + FitLinearNonlinear(m,2,a,state,nlserrors); + CLSFit::LSFitResults(state,info,c2,rep2); + //--- check + if(info<=0) + nlserrors=true; + else + { + //--- search errors + for(i=0;i<=m-1;i++) + nlserrors=nlserrors || MathAbs(c[i]-c2[i])>100*nlthreshold; + } + //--- test gradient-only or Hessian-based fitting without weights + CLSFit::LSFitLinear(y,a,n,m,info,c,rep); + for(i=0;i<=m-1;i++) + c2[i]=2*CMath::RandomReal()-1; + //--- function calls + CLSFit::LSFitCreateF(a,y,c2,n,m,m,diffstep,state); + CLSFit::LSFitSetCond(state,0.0,nlthreshold,0); + FitLinearNonlinear(m,0,a,state,nlserrors); + CLSFit::LSFitResults(state,info,c2,rep2); + //--- check + if(info<=0) + nlserrors=true; + else + { + //--- search errors + for(i=0;i<=m-1;i++) + nlserrors=nlserrors || MathAbs(c[i]-c2[i])>100*nlthreshold; + } + //--- change values + for(i=0;i<=m-1;i++) + c2[i]=2*CMath::RandomReal()-1; + //--- function calls + CLSFit::LSFitCreateFG(a,y,c2,n,m,m,CMath::RandomReal()>0.5,state); + CLSFit::LSFitSetCond(state,0.0,nlthreshold,0); + FitLinearNonlinear(m,1,a,state,nlserrors); + CLSFit::LSFitResults(state,info,c2,rep2); + //--- check + if(info<=0) + nlserrors=true; + else + { + //--- search errors + for(i=0;i<=m-1;i++) + nlserrors=nlserrors || MathAbs(c[i]-c2[i])>100*nlthreshold; + } + //--- change values + for(i=0;i<=m-1;i++) + c2[i]=2*CMath::RandomReal()-1; + //--- function calls + CLSFit::LSFitCreateFGH(a,y,c2,n,m,m,state); + CLSFit::LSFitSetCond(state,0.0,nlthreshold,0); + FitLinearNonlinear(m,2,a,state,nlserrors); + CLSFit::LSFitResults(state,info,c2,rep2); + //--- check + if(info<=0) + nlserrors=true; + else + { + //--- search errors + for(i=0;i<=m-1;i++) + nlserrors=nlserrors || MathAbs(c[i]-c2[i])>100*nlthreshold; + } + } + } + } + //--- test correctness of the RCond field + a.Resize(n,n); + ArrayResize(x,n); + ArrayResize(y,n); + ArrayResize(w,n); + //--- change values + v1=CMath::m_maxrealnumber; + v2=CMath::m_minrealnumber; + //--- calculation + for(i=0;i<=n-1;i++) + { + x[i]=0.1+0.9*CMath::RandomReal(); + y[i]=0.1+0.9*CMath::RandomReal(); + w[i]=1; + for(j=0;j<=n-1;j++) + { + //--- check + if(i==j) + { + a[i].Set(i,0.1+0.9*CMath::RandomReal()); + v1=MathMin(v1,a[i][i]); + v2=MathMax(v2,a[i][i]); + } + else + a[i].Set(j,0); + } + } + //--- function call + CLSFit::LSFitLinearW(y,w,a,n,n,info,c,rep); + //--- check + if(info<=0) + llserrors=true; + else + llserrors=llserrors || MathAbs(rep.m_taskrcond-v1/v2)>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) + a.Resize(n,m); + ArrayResize(x,n); + ArrayResize(y,n); + ArrayResize(w,n); + xscale=0.9+0.1*CMath::RandomReal(); + //--- calculation + for(i=0;i<=n-1;i++) + { + //--- check + if(n==1) + x[i]=2*CMath::RandomReal()-1; + else + x[i]=xscale*((double)(2*i)/(double)(n-1)-1); + //--- change values + y[i]=3*x[i]+MathExp(x[i]); + w[i]=1+CMath::RandomReal(); + a[i].Set(0,1); + //--- check + if(m>1) + a[i].Set(1,x[i]); + for(j=2;j<=m-1;j++) + a[i].Set(j,2*x[i]*a[i][j-1]-a[i][j-2]); + } + //--- allocation + cm.Resize(k,m+1); + for(i=0;i<=k-1;i++) + { + for(j=0;j<=m;j++) + cm[i].Set(j,2*CMath::RandomReal()-1); + } + //--- Solve constrained task + CLSFit::LSFitLinearWC(y,w,a,cm,n,m,k,info,c,rep); + //--- check + if(info<=0) + llserrors=true; + else + llserrors=llserrors || !IsGLSSolution(n,m,k,y,w,a,cm,c); + //--- test non-weighted fitting + ArrayResize(w2,n); + for(i=0;i<=n-1;i++) + w2[i]=1; + //--- function calls + CLSFit::LSFitLinearWC(y,w2,a,cm,n,m,k,info,c,rep); + CLSFit::LSFitLinearC(y,a,cm,n,m,k,info2,c2,rep2); + //--- check + if(info<=0 || info2<=0) + llserrors=true; + else + { + //--- test answer correctness + for(j=0;j<=m-1;j++) + llserrors=llserrors || MathAbs(c[j]-c2[j])>threshold; + llserrors=llserrors || MathAbs(rep.m_taskrcond-rep2.m_taskrcond)>threshold; + } + } + } + } + } +//--- nonlinear task for nonlinear fitting: +//--- f(X,C)=1/(1+C*X^2), +//--- C(true)=2. + n=100; + ArrayResize(c,1); + c[0]=1+2*CMath::RandomReal(); +//--- allocation + a.Resize(n,1); + ArrayResize(y,n); + for(i=0;i<=n-1;i++) + { + a[i].Set(0,4*CMath::RandomReal()-2); + y[i]=1/(1+2*CMath::Sqr(a[i][0])); + } +//--- function call + CLSFit::LSFitCreateFG(a,y,c,n,1,1,true,state); + CLSFit::LSFitSetCond(state,0.0,nlthreshold,0); +//--- cycle + while(CLSFit::LSFitIteration(state)) + { + //--- check + if(state.m_needf) + state.m_f=1/(1+state.m_c[0]*CMath::Sqr(state.m_x[0])); + //--- check + if(state.m_needfg) + { + state.m_f=1/(1+state.m_c[0]*CMath::Sqr(state.m_x[0])); + state.m_g[0]=-(CMath::Sqr(state.m_x[0])/CMath::Sqr(1+state.m_c[0]*CMath::Sqr(state.m_x[0]))); + } + } +//--- function call + CLSFit::LSFitResults(state,info,c,rep); +//--- check + if(info<=0) + nlserrors=true; + else + nlserrors=nlserrors || MathAbs(c[0]-2)>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=CMath::RandomReal(); + v2=CMath::RandomReal(); + v=1+CMath::RandomReal(); + //--- allocation + ArrayResize(c,1); + c[0]=1+2*CMath::RandomReal(); + //--- allocation + a.Resize(4,1); + ArrayResize(y,4); + //--- change values + a[0].Set(0,1); + y[0]=v-v2; + a[1].Set(0,1); + y[1]=v-v1; + a[2].Set(0,1); + y[2]=v+v1; + a[3].Set(0,1); + y[3]=v+v2; + refrms=MathSqrt((CMath::Sqr(v1)+CMath::Sqr(v2))/2); + refavg=(MathAbs(v1)+MathAbs(v2))/2; + refavgrel=0.25*(MathAbs(v2)/MathAbs(v-v2)+MathAbs(v1)/MathAbs(v-v1)+MathAbs(v1)/MathAbs(v+v1)+MathAbs(v2)/MathAbs(v+v2)); + refmax=MathMax(v1,v2); + //--- Test LLS + CLSFit::LSFitLinear(y,a,4,1,info,c,rep); + //--- check + if(info<=0) + llserrors=true; + else + { + //--- search errors + llserrors=llserrors || MathAbs(c[0]-v)>threshold; + llserrors=llserrors || MathAbs(rep.m_rmserror-refrms)>threshold; + llserrors=llserrors || MathAbs(rep.m_avgerror-refavg)>threshold; + llserrors=llserrors || MathAbs(rep.m_avgrelerror-refavgrel)>threshold; + llserrors=llserrors || MathAbs(rep.m_maxerror-refmax)>threshold; + } + //--- Test NLS + CLSFit::LSFitCreateFG(a,y,c,4,1,1,true,state); + CLSFit::LSFitSetCond(state,0.0,nlthreshold,0); + //--- cycle + while(CLSFit::LSFitIteration(state)) + { + //--- check + if(state.m_needf) + state.m_f=state.m_c[0]; + //--- check + if(state.m_needfg) + { + state.m_f=state.m_c[0]; + state.m_g[0]=1; + } + } + //--- function call + CLSFit::LSFitResults(state,info,c,rep); + //--- check + if(info<=0) + nlserrors=true; + else + { + //--- search errors + nlserrors=nlserrors || MathAbs(c[0]-v)>threshold; + nlserrors=nlserrors || MathAbs(rep.m_rmserror-refrms)>threshold; + nlserrors=nlserrors || MathAbs(rep.m_avgerror-refavg)>threshold; + nlserrors=nlserrors || MathAbs(rep.m_avgrelerror-refavgrel)>threshold; + nlserrors=nlserrors || MathAbs(rep.m_maxerror-refmax)>threshold; + } + } + } +//+------------------------------------------------------------------+ +//| Tests whether C is solution of (possibly) constrained LLS problem| +//+------------------------------------------------------------------+ +static bool CTestLSFitUnit::IsGLSSolution(const int n,const int m,const int k, + double &y[],double &w[],CMatrixDouble &fmatrix, + CMatrixDouble &cmatrix,double &cc[]) + { +//--- create variables + bool result; + int i=0; + int j=0; + double v=0; + double s1=0; + double s2=0; + double s3=0; + double delta=0; + double threshold=0; + int i_=0; +//--- create arrays + double c[]; + double c2[]; + double sv[]; + double deltac[]; + double deltaproj[]; +//--- create matrix + CMatrixDouble u; + CMatrixDouble vt; +//--- copy array + ArrayCopy(c,cc); +//--- Setup. +//--- Threshold is small because CMatrix may be ill-conditioned + delta=0.001; + threshold=MathSqrt(CMath::m_machineepsilon); +//--- allocation + ArrayResize(c2,m); + ArrayResize(deltac,m); + ArrayResize(deltaproj,m); +//--- test whether C is feasible point or not (projC must be close to C) + for(i=0;i<=k-1;i++) + { + //--- change value + v=0.0; + for(i_=0;i_<=m-1;i_++) + v+=cmatrix[i][i_]*c[i_]; + //--- check + if(MathAbs(v-cmatrix[i][m])>threshold) + { + //--- return result + return(false); + } + } +//--- find orthogonal basis of Null(CMatrix) (stored in rows from K to M-1) + if(k>0) + CSingValueDecompose::RMatrixSVD(cmatrix,k,m,0,2,2,sv,u,vt); +//--- Test result + result=true; + s1=GetGLSError(n,m,y,w,fmatrix,c); +//--- calculation + 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 + for(i_=0;i_<=m-1;i_++) + c2[i_]=c[i_]; + for(i=0;i<=m-1;i++) + { + //--- check + if(i==j) + deltac[i]=delta; + else + deltac[i]=0; + } + //--- check + if(k==0) + { + for(i_=0;i_<=m-1;i_++) + deltaproj[i_]=deltac[i_]; + } + else + { + for(i=0;i<=m-1;i++) + deltaproj[i]=0; + for(i=k;i<=m-1;i++) + { + //--- change value + v=0.0; + for(i_=0;i_<=m-1;i_++) + v+=vt[i][i_]*deltac[i_]; + for(i_=0;i_<=m-1;i_++) + deltaproj[i_]=deltaproj[i_]+v*vt[i][i_]; + } + } + //--- now we have DeltaProj such that if C is feasible, + //--- then C+DeltaProj is feasible too + for(i_=0;i_<=m-1;i_++) + c2[i_]=c[i_]; + for(i_=0;i_<=m-1;i_++) + c2[i_]=c2[i_]+deltaproj[i_]; + s2=GetGLSError(n,m,y,w,fmatrix,c2); + for(i_=0;i_<=m-1;i_++) + c2[i_]=c[i_]; + for(i_=0;i_<=m-1;i_++) + c2[i_]=c2[i_]-deltaproj[i_]; + s3=GetGLSError(n,m,y,w,fmatrix,c2); + result=(result && s2>=(double)(s1/(1+threshold))) && s3>=(double)(s1/(1+threshold)); + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Tests whether C is solution of LLS problem | +//+------------------------------------------------------------------+ +static double CTestLSFitUnit::GetGLSError(const int n,const int m,double &y[], + double &w[],CMatrixDouble &fmatrix,double &c[]) + { +//--- create variables + double result=0; + int i=0; + double v=0; + int i_=0; +//--- calculation + for(i=0;i<=n-1;i++) + { + //--- change value + v=0.0; + for(i_=0;i_<=m-1;i_++) + v+=fmatrix[i][i_]*c[i_]; + result=result+CMath::Sqr(w[i]*(v-y[i])); + } +//--- return result + 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 CTestLSFitUnit::FitLinearNonlinear(const int m,const int deravailable, + CMatrixDouble &xy,CLSFitState &state, + bool &nlserrors) + { +//--- create variables + int i=0; + int j=0; + double v=0; + int i_=0; +//--- cycle + while(CLSFit::LSFitIteration(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.m_needfg) + nlserrors=true; + //--- check + if(deravailable<2 && state.m_needfgh) + nlserrors=true; + i=0; + //--- check + if(state.m_needf) + i=i+1; + //--- check + if(state.m_needfg) + i=i+1; + //--- check + if(state.m_needfgh) + i=i+1; + //--- check + if(i!=1) + nlserrors=true; + //--- test that PointIndex is consistent with actual point passed + for(i=0;i<=m-1;i++) + nlserrors=nlserrors || xy[state.m_pointindex][i]!=state.m_x[i]; + //--- calculate + if(state.m_needf) + { + //--- change value + v=0.0; + for(i_=0;i_<=m-1;i_++) + v+=state.m_x[i_]*state.m_c[i_]; + state.m_f=v; + continue; + } + //--- check + if(state.m_needfg) + { + //--- change value + v=0.0; + for(i_=0;i_<=m-1;i_++) + v+=state.m_x[i_]*state.m_c[i_]; + state.m_f=v; + //--- copy + for(i_=0;i_<=m-1;i_++) + state.m_g[i_]=state.m_x[i_]; + continue; + } + //--- check + if(state.m_needfgh) + { + //--- change value + v=0.0; + for(i_=0;i_<=m-1;i_++) + v+=state.m_x[i_]*state.m_c[i_]; + state.m_f=v; + //--- copy + for(i_=0;i_<=m-1;i_++) + state.m_g[i_]=state.m_x[i_]; + for(i=0;i<=m-1;i++) + { + for(j=0;j<=m-1;j++) + state.m_h[i].Set(j,0); + } + continue; + } + } + } +//+------------------------------------------------------------------+ +//| Testing class CPSpline | +//+------------------------------------------------------------------+ +class CTestPSplineUnit + { +private: + //--- private methods + static void UnsetP2(CPSpline2Interpolant &p); + static void UnsetP3(CPSpline3Interpolant &p); + static void Unset1D(double &x[]); +public: + //--- constructor, destructor + CTestPSplineUnit(void); + ~CTestPSplineUnit(void); + //--- public method + static bool TestPSpline(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestPSplineUnit::CTestPSplineUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestPSplineUnit::~CTestPSplineUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CPSpline | +//+------------------------------------------------------------------+ +static bool CTestPSplineUnit::TestPSpline(const bool silent) + { +//--- create variables + bool waserrors; + bool p2errors; + bool p3errors; + double nonstrictthreshold=0; + double threshold=0; + int passcount=0; + double lstep=0; + double h=0; + int maxn=0; + int periodicity=0; + int skind=0; + int pkind=0; + bool periodic; + double a=0; + double b=0; + int n=0; + int tmpn=0; + int i=0; + double vx=0; + double vy=0; + double vz=0; + double vx2=0; + double vy2=0; + double vz2=0; + double vdx=0; + double vdy=0; + double vdz=0; + double vdx2=0; + double vdy2=0; + double vdz2=0; + double vd2x=0; + double vd2y=0; + double vd2z=0; + double vd2x2=0; + double vd2y2=0; + double vd2z2=0; + double v0=0; + double v1=0; + int i_=0; +//--- create arrays + double x[]; + double y[]; + double z[]; + double t[]; + double t2[]; + double t3[]; +//--- create matrix + CMatrixDouble xy; + CMatrixDouble xyz; +//--- objects of classes + CPSpline2Interpolant p2; + CPSpline3Interpolant p3; + CSpline1DInterpolant s; +//--- initialization + waserrors=false; + passcount=20; + lstep=0.005; + h=0.00001; + maxn=10; + threshold=10000*CMath::m_machineepsilon; + nonstrictthreshold=0.00001; + p2errors=false; + p3errors=false; +//--- 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; + //--- check + if(periodic && skind==0) + continue; + //--- check + if(n<5 && skind==0) + continue; + //--- init + xy.Resize(n,2); + xyz.Resize(n,3); + //--- function call + CApServ::TaskGenInt1DEquidist(-1,1,n,t2,x); + //--- change values + for(i_=0;i_<=n-1;i_++) + xy[i_].Set(0,x[i_]); + for(i_=0;i_<=n-1;i_++) + xyz[i_].Set(0,x[i_]); + //--- function call + CApServ::TaskGenInt1DEquidist(-1,1,n,t2,y); + //--- change values + for(i_=0;i_<=n-1;i_++) + xy[i_].Set(1,y[i_]); + for(i_=0;i_<=n-1;i_++) + xyz[i_].Set(1,y[i_]); + //--- function call + CApServ::TaskGenInt1DEquidist(-1,1,n,t2,z); + //--- change values + for(i_=0;i_<=n-1;i_++) + xyz[i_].Set(2,z[i_]); + //--- function calls + UnsetP2(p2); + UnsetP3(p3); + //--- check + if(periodic) + { + CPSpline::PSpline2BuildPeriodic(xy,n,skind,pkind,p2); + CPSpline::PSpline3BuildPeriodic(xyz,n,skind,pkind,p3); + } + else + { + CPSpline::PSpline2Build(xy,n,skind,pkind,p2); + CPSpline::PSpline3Build(xyz,n,skind,pkind,p3); + } + //--- PSpline2ParameterValues() properties + CPSpline::PSpline2ParameterValues(p2,tmpn,t2); + //--- check + if(tmpn!=n) + { + p2errors=true; + continue; + } + //--- function call + CPSpline::PSpline3ParameterValues(p3,tmpn,t3); + //--- check + if(tmpn!=n) + { + p3errors=true; + continue; + } + //--- search errors + p2errors=p2errors || t2[0]!=0.0; + p3errors=p3errors || t3[0]!=0.0; + for(i=1;i<=n-1;i++) + { + p2errors=p2errors || t2[i]<=t2[i-1]; + p3errors=p3errors || t3[i]<=t3[i-1]; + } + //--- check + if(periodic) + { + p2errors=p2errors || t2[n-1]>=1.0; + p3errors=p3errors || t3[n-1]>=1.0; + } + else + { + p2errors=p2errors || t2[n-1]!=1.0; + p3errors=p3errors || t3[n-1]!=1.0; + } + //--- 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 + CPSpline::PSpline2Calc(p2,t2[i],vx,vy); + p2errors=p2errors || MathAbs(vx-x[i])>threshold; + p2errors=p2errors || MathAbs(vy-y[i])>threshold; + //--- 3-dimensional test + CPSpline::PSpline3Calc(p3,t3[i],vx,vy,vz); + p3errors=p3errors || MathAbs(vx-x[i])>threshold; + p3errors=p3errors || MathAbs(vy-y[i])>threshold; + p3errors=p3errors || MathAbs(vz-z[i])>threshold; + } + //--- Test periodicity (if needed) + if(periodic) + { + //--- periodicity at nodes + for(i=0;i<=n-1;i++) + { + //--- 2-dimensional test + CPSpline::PSpline2Calc(p2,t2[i]+CMath::RandomInteger(10)-5,vx,vy); + //--- search errors + p2errors=p2errors || MathAbs(vx-x[i])>threshold; + p2errors=p2errors || MathAbs(vy-y[i])>threshold; + //--- function call + CPSpline::PSpline2Diff(p2,t2[i]+CMath::RandomInteger(10)-5,vx,vdx,vy,vdy); + //--- search errors + p2errors=p2errors || MathAbs(vx-x[i])>threshold; + p2errors=p2errors || MathAbs(vy-y[i])>threshold; + //--- function call + CPSpline::PSpline2Diff2(p2,t2[i]+CMath::RandomInteger(10)-5,vx,vdx,vd2x,vy,vdy,vd2y); + //--- search errors + p2errors=p2errors || MathAbs(vx-x[i])>threshold; + p2errors=p2errors || MathAbs(vy-y[i])>threshold; + //--- 3-dimensional test + CPSpline::PSpline3Calc(p3,t3[i]+CMath::RandomInteger(10)-5,vx,vy,vz); + //--- search errors + p3errors=p3errors || MathAbs(vx-x[i])>threshold; + p3errors=p3errors || MathAbs(vy-y[i])>threshold; + p3errors=p3errors || MathAbs(vz-z[i])>threshold; + //--- function call + CPSpline::PSpline3Diff(p3,t3[i]+CMath::RandomInteger(10)-5,vx,vdx,vy,vdy,vz,vdz); + //--- search errors + p3errors=p3errors || MathAbs(vx-x[i])>threshold; + p3errors=p3errors || MathAbs(vy-y[i])>threshold; + p3errors=p3errors || MathAbs(vz-z[i])>threshold; + //--- function call + CPSpline::PSpline3Diff2(p3,t3[i]+CMath::RandomInteger(10)-5,vx,vdx,vd2x,vy,vdy,vd2y,vz,vdz,vd2z); + //--- search errors + p3errors=p3errors || MathAbs(vx-x[i])>threshold; + p3errors=p3errors || MathAbs(vy-y[i])>threshold; + p3errors=p3errors || MathAbs(vz-z[i])>threshold; + } + //--- periodicity between nodes + v0=CMath::RandomReal(); + CPSpline::PSpline2Calc(p2,v0,vx,vy); + CPSpline::PSpline2Calc(p2,v0+CMath::RandomInteger(10)-5,vx2,vy2); + //--- search errors + p2errors=p2errors || MathAbs(vx-vx2)>threshold; + p2errors=p2errors || MathAbs(vy-vy2)>threshold; + //--- function calls + CPSpline::PSpline3Calc(p3,v0,vx,vy,vz); + CPSpline::PSpline3Calc(p3,v0+CMath::RandomInteger(10)-5,vx2,vy2,vz2); + //--- search errors + p3errors=p3errors || MathAbs(vx-vx2)>threshold; + p3errors=p3errors || MathAbs(vy-vy2)>threshold; + p3errors=p3errors || MathAbs(vz-vz2)>threshold; + //--- near-boundary test for continuity of function values and derivatives: + //--- 2-dimensional curve + if(!CAp::Assert(skind==1 || skind==2,"TEST: unexpected spline type!")) + return(false); + //--- change values + v0=100*CMath::m_machineepsilon; + v1=1-v0; + //--- function calls + CPSpline::PSpline2Calc(p2,v0,vx,vy); + CPSpline::PSpline2Calc(p2,v1,vx2,vy2); + //--- search errors + p2errors=p2errors || MathAbs(vx-vx2)>threshold; + p2errors=p2errors || MathAbs(vy-vy2)>threshold; + //--- function calls + CPSpline::PSpline2Diff(p2,v0,vx,vdx,vy,vdy); + CPSpline::PSpline2Diff(p2,v1,vx2,vdx2,vy2,vdy2); + //--- search errors + p2errors=p2errors || MathAbs(vx-vx2)>threshold; + p2errors=p2errors || MathAbs(vy-vy2)>threshold; + p2errors=p2errors || MathAbs(vdx-vdx2)>nonstrictthreshold; + p2errors=p2errors || MathAbs(vdy-vdy2)>nonstrictthreshold; + //--- function calls + CPSpline::PSpline2Diff2(p2,v0,vx,vdx,vd2x,vy,vdy,vd2y); + CPSpline::PSpline2Diff2(p2,v1,vx2,vdx2,vd2x2,vy2,vdy2,vd2y2); + //--- search errors + p2errors=p2errors || MathAbs(vx-vx2)>threshold; + p2errors=p2errors || MathAbs(vy-vy2)>threshold; + p2errors=p2errors || MathAbs(vdx-vdx2)>nonstrictthreshold; + p2errors=p2errors || MathAbs(vdy-vdy2)>nonstrictthreshold; + //--- check + if(skind==2) + { + //--- second derivative test only for cubic splines + p2errors=p2errors || MathAbs(vd2x-vd2x2)>nonstrictthreshold; + p2errors=p2errors || MathAbs(vd2y-vd2y2)>nonstrictthreshold; + } + //--- near-boundary test for continuity of function values and derivatives: + //--- 3-dimensional curve + if(!CAp::Assert(skind==1 || skind==2,"TEST: unexpected spline type!")) + return(false); + //--- change values + v0=100*CMath::m_machineepsilon; + v1=1-v0; + //--- function calls + CPSpline::PSpline3Calc(p3,v0,vx,vy,vz); + CPSpline::PSpline3Calc(p3,v1,vx2,vy2,vz2); + //--- search errors + p3errors=p3errors || MathAbs(vx-vx2)>threshold; + p3errors=p3errors || MathAbs(vy-vy2)>threshold; + p3errors=p3errors || MathAbs(vz-vz2)>threshold; + //--- function calls + CPSpline::PSpline3Diff(p3,v0,vx,vdx,vy,vdy,vz,vdz); + CPSpline::PSpline3Diff(p3,v1,vx2,vdx2,vy2,vdy2,vz2,vdz2); + //--- search errors + p3errors=p3errors || MathAbs(vx-vx2)>threshold; + p3errors=p3errors || MathAbs(vy-vy2)>threshold; + p3errors=p3errors || MathAbs(vz-vz2)>threshold; + p3errors=p3errors || MathAbs(vdx-vdx2)>nonstrictthreshold; + p3errors=p3errors || MathAbs(vdy-vdy2)>nonstrictthreshold; + p3errors=p3errors || MathAbs(vdz-vdz2)>nonstrictthreshold; + //--- function calls + CPSpline::PSpline3Diff2(p3,v0,vx,vdx,vd2x,vy,vdy,vd2y,vz,vdz,vd2z); + CPSpline::PSpline3Diff2(p3,v1,vx2,vdx2,vd2x2,vy2,vdy2,vd2y2,vz2,vdz2,vd2z2); + //--- search errors + p3errors=p3errors || MathAbs(vx-vx2)>threshold; + p3errors=p3errors || MathAbs(vy-vy2)>threshold; + p3errors=p3errors || MathAbs(vz-vz2)>threshold; + p3errors=p3errors || MathAbs(vdx-vdx2)>nonstrictthreshold; + p3errors=p3errors || MathAbs(vdy-vdy2)>nonstrictthreshold; + p3errors=p3errors || MathAbs(vdz-vdz2)>nonstrictthreshold; + //--- check + if(skind==2) + { + //--- second derivative test only for cubic splines + p3errors=p3errors || MathAbs(vd2x-vd2x2)>nonstrictthreshold; + p3errors=p3errors || MathAbs(vd2y-vd2y2)>nonstrictthreshold; + p3errors=p3errors || MathAbs(vd2z-vd2z2)>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 + xy.Resize(n,2); + xyz.Resize(n,3); + //--- function call + CApServ::TaskGenInt1DEquidist(0,1,n,t,x); + //--- change values + for(i_=0;i_<=n-1;i_++) + xy[i_].Set(0,x[i_]); + for(i_=0;i_<=n-1;i_++) + xyz[i_].Set(0,x[i_]); + //--- function call + CApServ::TaskGenInt1DEquidist(0,1,n,t,y); + //--- change values + for(i_=0;i_<=n-1;i_++) + xy[i_].Set(1,y[i_]); + for(i_=0;i_<=n-1;i_++) + xyz[i_].Set(1,y[i_]); + //--- function call + CApServ::TaskGenInt1DEquidist(0,1,n,t,z); + //--- change values + for(i_=0;i_<=n-1;i_++) + xyz[i_].Set(2,z[i_]); + //--- function call + UnsetP2(p2); + UnsetP3(p3); + CPSpline::PSpline2Build(xy,n,2,0,p2); + CPSpline::PSpline3Build(xyz,n,2,0,p3); + //--- 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=CMath::RandomReal(); + CSpline1D::Spline1DBuildCubic(t,x,n,0,0.0,0,0.0,s); + CSpline1D::Spline1DDiff(s,v0,vx2,vdx2,vd2x2); + CSpline1D::Spline1DBuildCubic(t,y,n,0,0.0,0,0.0,s); + CSpline1D::Spline1DDiff(s,v0,vy2,vdy2,vd2y2); + CSpline1D::Spline1DBuildCubic(t,z,n,0,0.0,0,0.0,s); + CSpline1D::Spline1DDiff(s,v0,vz2,vdz2,vd2z2); + //--- 2D test + CPSpline::PSpline2Calc(p2,v0,vx,vy); + //--- search errors + p2errors=p2errors || MathAbs(vx-vx2)>threshold; + p2errors=p2errors || MathAbs(vy-vy2)>threshold; + //--- function call + CPSpline::PSpline2Diff(p2,v0,vx,vdx,vy,vdy); + //--- search errors + p2errors=p2errors || MathAbs(vx-vx2)>threshold; + p2errors=p2errors || MathAbs(vy-vy2)>threshold; + p2errors=p2errors || MathAbs(vdx-vdx2)>threshold; + p2errors=p2errors || MathAbs(vdy-vdy2)>threshold; + //--- function call + CPSpline::PSpline2Diff2(p2,v0,vx,vdx,vd2x,vy,vdy,vd2y); + //--- search errors + p2errors=p2errors || MathAbs(vx-vx2)>threshold; + p2errors=p2errors || MathAbs(vy-vy2)>threshold; + p2errors=p2errors || MathAbs(vdx-vdx2)>threshold; + p2errors=p2errors || MathAbs(vdy-vdy2)>threshold; + p2errors=p2errors || MathAbs(vd2x-vd2x2)>threshold; + p2errors=p2errors || MathAbs(vd2y-vd2y2)>threshold; + //--- 3D test + CPSpline::PSpline3Calc(p3,v0,vx,vy,vz); + //--- search errors + p3errors=p3errors || MathAbs(vx-vx2)>threshold; + p3errors=p3errors || MathAbs(vy-vy2)>threshold; + p3errors=p3errors || MathAbs(vz-vz2)>threshold; + //--- function call + CPSpline::PSpline3Diff(p3,v0,vx,vdx,vy,vdy,vz,vdz); + //--- search errors + p3errors=p3errors || MathAbs(vx-vx2)>threshold; + p3errors=p3errors || MathAbs(vy-vy2)>threshold; + p3errors=p3errors || MathAbs(vz-vz2)>threshold; + p3errors=p3errors || MathAbs(vdx-vdx2)>threshold; + p3errors=p3errors || MathAbs(vdy-vdy2)>threshold; + p3errors=p3errors || MathAbs(vdz-vdz2)>threshold; + //--- function call + CPSpline::PSpline3Diff2(p3,v0,vx,vdx,vd2x,vy,vdy,vd2y,vz,vdz,vd2z); + //--- search errors + p3errors=p3errors || MathAbs(vx-vx2)>threshold; + p3errors=p3errors || MathAbs(vy-vy2)>threshold; + p3errors=p3errors || MathAbs(vz-vz2)>threshold; + p3errors=p3errors || MathAbs(vdx-vdx2)>threshold; + p3errors=p3errors || MathAbs(vdy-vdy2)>threshold; + p3errors=p3errors || MathAbs(vdz-vdz2)>threshold; + p3errors=p3errors || MathAbs(vd2x-vd2x2)>threshold; + p3errors=p3errors || MathAbs(vd2y-vd2y2)>threshold; + p3errors=p3errors || MathAbs(vd2z-vd2z2)>threshold; + //--- Test tangents for 2D/3D + CPSpline::PSpline2Tangent(p2,v0,vx,vy); + //--- search errors + p2errors=p2errors || MathAbs(vx-vdx2/CApServ::SafePythag2(vdx2,vdy2))>threshold; + p2errors=p2errors || MathAbs(vy-vdy2/CApServ::SafePythag2(vdx2,vdy2))>threshold; + //--- function call + CPSpline::PSpline3Tangent(p3,v0,vx,vy,vz); + //--- search errors + p3errors=p3errors || MathAbs(vx-vdx2/CApServ::SafePythag3(vdx2,vdy2,vdz2))>threshold; + p3errors=p3errors || MathAbs(vy-vdy2/CApServ::SafePythag3(vdx2,vdy2,vdz2))>threshold; + p3errors=p3errors || MathAbs(vz-vdz2/CApServ::SafePythag3(vdx2,vdy2,vdz2))>threshold; + } +//--- Arc length test. +//--- Simple problem with easy solution (points on a straight line with +//--- uniform parameterization). + for(n=2;n<=maxn;n++) + { + //--- allocation + xy.Resize(n,2); + xyz.Resize(n,3); + for(i=0;i<=n-1;i++) + { + xy[i].Set(0,i); + xy[i].Set(1,i); + xyz[i].Set(0,i); + xyz[i].Set(1,i); + xyz[i].Set(2,i); + } + //--- function calls + CPSpline::PSpline2Build(xy,n,1,0,p2); + CPSpline::PSpline3Build(xyz,n,1,0,p3); + a=CMath::RandomReal(); + b=CMath::RandomReal(); + //--- search errors + p2errors=p2errors || MathAbs(CPSpline::PSpline2ArcLength(p2,a,b)-(b-a)*MathSqrt(2)*(n-1))>nonstrictthreshold; + p3errors=p3errors || MathAbs(CPSpline::PSpline3ArcLength(p3,a,b)-(b-a)*MathSqrt(3)*(n-1))>nonstrictthreshold; + } +//--- report + waserrors=p2errors || p3errors; +//--- check + if(!silent) + { + Print("TESTING SPLINE INTERPOLATION"); + //--- Normal tests + Print("2D TEST: "); + //--- check + if(p2errors) + Print("FAILED"); + else + Print("OK"); + Print("3D TEST: "); + //--- check + if(p3errors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- end + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Unset spline, i.e. initialize it with random garbage | +//+------------------------------------------------------------------+ +static void CTestPSplineUnit::UnsetP2(CPSpline2Interpolant &p) + { +//--- create matrix + CMatrixDouble xy; +//--- allocation + xy.Resize(2,2); +//--- initialization + xy[0].Set(0,-1); + xy[0].Set(1,-1); + xy[1].Set(0,1); + xy[1].Set(1,1); +//--- function call + CPSpline::PSpline2Build(xy,2,1,0,p); + } +//+------------------------------------------------------------------+ +//| Unset spline, i.e. initialize it with random garbage | +//+------------------------------------------------------------------+ +static void CTestPSplineUnit::UnsetP3(CPSpline3Interpolant &p) + { +//--- create matrix + CMatrixDouble xy; +//--- allocation + xy.Resize(2,3); +//--- initialization + xy[0].Set(0,-1); + xy[0].Set(1,-1); + xy[0].Set(2,-1); + xy[1].Set(0,1); + xy[1].Set(1,1); + xy[1].Set(2,1); +//--- function call + CPSpline::PSpline3Build(xy,2,1,0,p); + } +//+------------------------------------------------------------------+ +//| Unsets real vector | +//+------------------------------------------------------------------+ +static void CTestPSplineUnit::Unset1D(double &x[]) + { +//--- allocation + ArrayResize(x,1); +//--- change value + x[0]=2*CMath::RandomReal()-1; + } +//+------------------------------------------------------------------+ +//| Testing class CSpline2D | +//+------------------------------------------------------------------+ +class CTestSpline2DUnit + { +public: + //--- constructor, destructor + CTestSpline2DUnit(void); + ~CTestSpline2DUnit(void); + //--- public methods + static bool TestSpline2D(const bool silent); + static void LConst(CSpline2DInterpolant &c,double &lx[],double &ly[],const int m,const int n,const double lstep,double &lc,double &lcx,double &lcy,double &lcxy); + static void TwodNumder(CSpline2DInterpolant &c,const double x,const double y,const double h,double &f,double &fx,double &fy,double &fxy); + static bool TestUnpack(CSpline2DInterpolant &c,double &lx[],double &ly[]); + static bool TestLinTrans(CSpline2DInterpolant &c,const double ax,const double bx,const double ay,const double by); + static void UnsetSpline2D(CSpline2DInterpolant &c); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestSpline2DUnit::CTestSpline2DUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestSpline2DUnit::~CTestSpline2DUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CSpline2D | +//+------------------------------------------------------------------+ +static bool CTestSpline2DUnit::TestSpline2D(const bool silent) + { +//--- create variables + bool waserrors; + bool blerrors; + bool bcerrors; + bool dserrors; + bool cperrors; + bool uperrors; + bool lterrors; + bool syerrors; + bool rlerrors; + bool rcerrors; + int pass=0; + int passcount=0; + int jobtype=0; + double lstep=0; + double h=0; + double ax=0; + double ay=0; + double bx=0; + double by=0; + int i=0; + int j=0; + int k=0; + int n=0; + int m=0; + int n2=0; + int m2=0; + double err=0; + double t=0; + double t1=0; + double t2=0; + double l1=0; + double l1x=0; + double l1y=0; + double l1xy=0; + double l2=0; + double l2x=0; + double l2y=0; + double l2xy=0; + double fm=0; + double f1=0; + double f2=0; + double f3=0; + double f4=0; + double v1=0; + double v1x=0; + double v1y=0; + double v1xy=0; + double v2=0; + double v2x=0; + double v2y=0; + double v2xy=0; + double mf=0; +//--- create arrays + double x[]; + double y[]; + double lx[]; + double ly[]; +//--- create matrix + CMatrixDouble f; + CMatrixDouble fr; + CMatrixDouble ft; +//--- objects of classes + CSpline2DInterpolant c; + CSpline2DInterpolant c2; +//--- initialization + waserrors=false; + passcount=10; + h=0.00001; + lstep=0.001; + blerrors=false; + bcerrors=false; + dserrors=false; + cperrors=false; + uperrors=false; + lterrors=false; + syerrors=false; + rlerrors=false; + rcerrors=false; +//--- Test: bilinear,bicubic + for(n=2;n<=7;n++) + { + for(m=2;m<=7;m++) + { + //--- allocation + ArrayResize(x,n); + ArrayResize(y,m); + ArrayResize(lx,2*n-2+1); + ArrayResize(ly,2*m-2+1); + f.Resize(m,n); + //--- calculation + ft.Resize(n,m); + 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-CMath::RandomReal(); + bx=1+CMath::RandomReal(); + ay=-1-CMath::RandomReal(); + by=1+CMath::RandomReal(); + for(j=0;j<=n-1;j++) + { + x[j]=0.5*(bx+ax)-0.5*(bx-ax)*MathCos(M_PI*(2*j+1)/(2*n)); + //--- check + if(j==0) + x[j]=ax; + //--- check + if(j==n-1) + x[j]=bx; + lx[2*j]=x[j]; + //--- check + if(j>0) + lx[2*j-1]=0.5*(x[j]+x[j-1]); + } + //--- swap + for(j=0;j<=n-1;j++) + { + k=CMath::RandomInteger(n); + //--- check + if(k!=j) + { + t=x[j]; + x[j]=x[k]; + x[k]=t; + } + } + //--- calculation + for(i=0;i<=m-1;i++) + { + y[i]=0.5*(by+ay)-0.5*(by-ay)*MathCos(M_PI*(2*i+1)/(2*m)); + //--- check + if(i==0) + y[i]=ay; + //--- check + if(i==m-1) + y[i]=by; + ly[2*i]=y[i]; + //--- check + if(i>0) + ly[2*i-1]=0.5*(y[i]+y[i-1]); + } + //--- swap + for(i=0;i<=m-1;i++) + { + k=CMath::RandomInteger(m); + //--- check + if(k!=i) + { + t=y[i]; + y[i]=y[k]; + y[k]=t; + } + } + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + f[i].Set(j,MathExp(0.6*x[j])-MathExp(-(0.3*y[i])+0.08*x[j])+2*MathCos(M_PI*(x[j]+1.2*y[i]))+0.1*MathCos(20*x[j]+15*y[i])); + } + //--- Test bilinear interpolation: + //--- * interpolation at the nodes + //--- * linearity + //--- * continuity + //--- * differentiation in the inner points + CSpline2D::Spline2DBuildBilinear(x,y,f,m,n,c); + //--- search errors + err=0; + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + err=MathMax(err,MathAbs(f[i][j]-CSpline2D::Spline2DCalc(c,x[j],y[i]))); + } + //--- search errors + blerrors=blerrors || err>10000*CMath::m_machineepsilon; + err=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=CSpline2D::Spline2DCalc(c,lx[2*j+1],ly[2*i+1]); + f1=CSpline2D::Spline2DCalc(c,lx[2*j],ly[2*i]); + f2=CSpline2D::Spline2DCalc(c,lx[2*j+2],ly[2*i]); + f3=CSpline2D::Spline2DCalc(c,lx[2*j+2],ly[2*i+2]); + f4=CSpline2D::Spline2DCalc(c,lx[2*j],ly[2*i+2]); + //--- search errors + err=MathMax(err,MathAbs(0.25*(f1+f2+f3+f4)-fm)); + } + } + //--- search errors + blerrors=blerrors || err>10000*CMath::m_machineepsilon; + //--- function calls + LConst(c,lx,ly,m,n,lstep,l1,l1x,l1y,l1xy); + LConst(c,lx,ly,m,n,lstep/3,l2,l2x,l2y,l2xy); + //--- search errors + blerrors=blerrors || l2/l1>1.2; + err=0; + for(i=0;i<=m-2;i++) + { + for(j=0;j<=n-2;j++) + { + CSpline2D::Spline2DDiff(c,lx[2*j+1],ly[2*i+1],v1,v1x,v1y,v1xy); + TwodNumder(c,lx[2*j+1],ly[2*i+1],h,v2,v2x,v2y,v2xy); + //--- search errors + err=MathMax(err,MathAbs(v1-v2)); + err=MathMax(err,MathAbs(v1x-v2x)); + err=MathMax(err,MathAbs(v1y-v2y)); + err=MathMax(err,MathAbs(v1xy-v2xy)); + } + } + //--- search errors + dserrors=dserrors || err>1.0E-3; + uperrors=uperrors || !TestUnpack(c,lx,ly); + lterrors=lterrors || !TestLinTrans(c,ax,bx,ay,by); + //--- Test bicubic interpolation. + //--- * interpolation at the nodes + //--- * smoothness + //--- * differentiation + CSpline2D::Spline2DBuildBicubic(x,y,f,m,n,c); + //--- search errors + err=0; + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + err=MathMax(err,MathAbs(f[i][j]-CSpline2D::Spline2DCalc(c,x[j],y[i]))); + } + //--- search errors + bcerrors=bcerrors || err>10000*CMath::m_machineepsilon; + LConst(c,lx,ly,m,n,lstep,l1,l1x,l1y,l1xy); + LConst(c,lx,ly,m,n,lstep/3,l2,l2x,l2y,l2xy); + //--- search errors + bcerrors=bcerrors || l2/l1>1.2; + bcerrors=bcerrors || l2x/l1x>1.2; + bcerrors=bcerrors || l2y/l1y>1.2; + //--- check + if(l2xy>0.01 && 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 || l2xy/l1xy>1.2; + } + err=0; + for(i=0;i<=2*m-2;i++) + { + for(j=0;j<=2*n-2;j++) + { + CSpline2D::Spline2DDiff(c,lx[j],ly[i],v1,v1x,v1y,v1xy); + TwodNumder(c,lx[j],ly[i],h,v2,v2x,v2y,v2xy); + //--- search errors + err=MathMax(err,MathAbs(v1-v2)); + err=MathMax(err,MathAbs(v1x-v2x)); + err=MathMax(err,MathAbs(v1y-v2y)); + err=MathMax(err,MathAbs(v1xy-v2xy)); + } + } + //--- search errors + dserrors=dserrors || err>1.0E-3; + uperrors=uperrors || !TestUnpack(c,lx,ly); + lterrors=lterrors || !TestLinTrans(c,ax,bx,ay,by); + //--- Copy/Serialise test + if(CMath::RandomReal()>0.5) + CSpline2D::Spline2DBuildBicubic(x,y,f,m,n,c); + else + CSpline2D::Spline2DBuildBilinear(x,y,f,m,n,c); + //--- function calls + UnsetSpline2D(c2); + CSpline2D::Spline2DCopy(c,c2); + //--- calculation + err=0; + for(i=1;i<=5;i++) + { + t1=ax+(bx-ax)*CMath::RandomReal(); + t2=ay+(by-ay)*CMath::RandomReal(); + //--- search errors + err=MathMax(err,MathAbs(CSpline2D::Spline2DCalc(c,t1,t2)-CSpline2D::Spline2DCalc(c2,t1,t2))); + } + //--- search errors + cperrors=cperrors || err>10000*CMath::m_machineepsilon; + //--- Special symmetry test + err=0; + for(jobtype=0;jobtype<=1;jobtype++) + { + //--- Prepare + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + ft[j].Set(i,f[i][j]); + } + //--- check + if(jobtype==0) + { + CSpline2D::Spline2DBuildBilinear(x,y,f,m,n,c); + CSpline2D::Spline2DBuildBilinear(y,x,ft,n,m,c2); + } + else + { + CSpline2D::Spline2DBuildBicubic(x,y,f,m,n,c); + CSpline2D::Spline2DBuildBicubic(y,x,ft,n,m,c2); + } + //--- Test + for(i=1;i<=10;i++) + { + t1=ax+(bx-ax)*CMath::RandomReal(); + t2=ay+(by-ay)*CMath::RandomReal(); + //--- search errors + err=MathMax(err,MathAbs(CSpline2D::Spline2DCalc(c,t1,t2)-CSpline2D::Spline2DCalc(c2,t2,t1))); + } + } + //--- search errors + syerrors=syerrors || err>10000*CMath::m_machineepsilon; + } + } + } +//--- Test resample + for(m=2;m<=6;m++) + { + for(n=2;n<=6;n++) + { + //--- allocation + f.Resize(m,n); + ArrayResize(x,n); + ArrayResize(y,m); + //--- change values + for(j=0;j<=n-1;j++) + x[j]=(double)j/(double)(n-1); + for(i=0;i<=m-1;i++) + y[i]=(double)i/(double)(m-1); + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + f[i].Set(j,MathExp(0.6*x[j])-MathExp(-(0.3*y[i])+0.08*x[j])+2*MathCos(M_PI*(x[j]+1.2*y[i]))+0.1*MathCos(20*x[j]+15*y[i])); + } + //--- calculation + for(m2=2;m2<=6;m2++) + { + for(n2=2;n2<=6;n2++) + { + for(pass=1;pass<=passcount;pass++) + { + for(jobtype=0;jobtype<=1;jobtype++) + { + //--- check + if(jobtype==0) + { + CSpline2D::Spline2DResampleBilinear(f,m,n,fr,m2,n2); + CSpline2D::Spline2DBuildBilinear(x,y,f,m,n,c); + } + //--- check + if(jobtype==1) + { + CSpline2D::Spline2DResampleBicubic(f,m,n,fr,m2,n2); + CSpline2D::Spline2DBuildBicubic(x,y,f,m,n,c); + } + //--- change values + err=0; + mf=0; + //--- calculation + for(i=0;i<=m2-1;i++) + { + for(j=0;j<=n2-1;j++) + { + v1=CSpline2D::Spline2DCalc(c,(double)j/(double)(n2-1),(double)i/(double)(m2-1)); + v2=fr[i][j]; + //--- search errors + err=MathMax(err,MathAbs(v1-v2)); + mf=MathMax(mf,MathAbs(v1)); + } + } + //--- check + if(jobtype==0) + rlerrors=rlerrors || err/mf>10000*CMath::m_machineepsilon; + //--- check + if(jobtype==1) + rcerrors=rcerrors || err/mf>10000*CMath::m_machineepsilon; + } + } + } + } + } + } +//--- report + waserrors=(((((((blerrors || bcerrors) || dserrors) || cperrors) || uperrors) || lterrors) || syerrors) || rlerrors) || rcerrors; +//--- check + if(!silent) + { + Print("TESTING 2D INTERPOLATION"); + //--- Normal tests + Print("BILINEAR TEST: "); + //--- check + if(blerrors) + Print("FAILED"); + else + Print("OK"); + Print("BICUBIC TEST: "); + //--- check + if(bcerrors) + Print("FAILED"); + else + Print("OK"); + Print("DIFFERENTIATION TEST: "); + //--- check + if(dserrors) + Print("FAILED"); + else + Print("OK"); + Print("COPY/SERIALIZE TEST: "); + //--- check + if(cperrors) + Print("FAILED"); + else + Print("OK"); + Print("UNPACK TEST: "); + //--- check + if(uperrors) + Print("FAILED"); + else + Print("OK"); + Print("LIN.TRANS. TEST: "); + //--- check + if(lterrors) + Print("FAILED"); + else + Print("OK"); + Print("SPECIAL SYMMETRY TEST: "); + //--- check + if(syerrors) + Print("FAILED"); + else + Print("OK"); + Print("BILINEAR RESAMPLING TEST: "); + //--- check + if(rlerrors) + Print("FAILED"); + else + Print("OK"); + Print("BICUBIC RESAMPLING TEST: "); + //--- check + if(rcerrors) + Print("FAILED"); + else + Print("OK"); + //--- Summary + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- end + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Lipschitz constants for spline inself,first and second | +//| derivatives. | +//+------------------------------------------------------------------+ +static void CTestSpline2DUnit::LConst(CSpline2DInterpolant &c,double &lx[], + double &ly[],const int m,const int n, + const double lstep,double &lc, + double &lcx,double &lcy,double &lcxy) + { +//--- create variables + int i=0; + int j=0; + double f1=0; + double f2=0; + double f3=0; + double f4=0; + double fx1=0; + double fx2=0; + double fx3=0; + double fx4=0; + double fy1=0; + double fy2=0; + double fy3=0; + double fy4=0; + double fxy1=0; + double fxy2=0; + double fxy3=0; + double fxy4=0; + double s2lstep=0; +//--- initialization + lc=0; + lcx=0; + lcy=0; + lcxy=0; + s2lstep=MathSqrt(2)*lstep; +//--- calculation + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- Calculate + TwodNumder(c,lx[j]-lstep/2,ly[i]-lstep/2,lstep/4,f1,fx1,fy1,fxy1); + TwodNumder(c,lx[j]+lstep/2,ly[i]-lstep/2,lstep/4,f2,fx2,fy2,fxy2); + TwodNumder(c,lx[j]+lstep/2,ly[i]+lstep/2,lstep/4,f3,fx3,fy3,fxy3); + TwodNumder(c,lx[j]-lstep/2,ly[i]+lstep/2,lstep/4,f4,fx4,fy4,fxy4); + //--- Lipschitz constant for the function itself + lc=MathMax(lc,MathAbs((f1-f2)/lstep)); + lc=MathMax(lc,MathAbs((f2-f3)/lstep)); + lc=MathMax(lc,MathAbs((f3-f4)/lstep)); + lc=MathMax(lc,MathAbs((f4-f1)/lstep)); + lc=MathMax(lc,MathAbs((f1-f3)/s2lstep)); + lc=MathMax(lc,MathAbs((f2-f4)/s2lstep)); + //--- Lipschitz constant for the first derivative + lcx=MathMax(lcx,MathAbs((fx1-fx2)/lstep)); + lcx=MathMax(lcx,MathAbs((fx2-fx3)/lstep)); + lcx=MathMax(lcx,MathAbs((fx3-fx4)/lstep)); + lcx=MathMax(lcx,MathAbs((fx4-fx1)/lstep)); + lcx=MathMax(lcx,MathAbs((fx1-fx3)/s2lstep)); + lcx=MathMax(lcx,MathAbs((fx2-fx4)/s2lstep)); + //--- Lipschitz constant for the first derivative + lcy=MathMax(lcy,MathAbs((fy1-fy2)/lstep)); + lcy=MathMax(lcy,MathAbs((fy2-fy3)/lstep)); + lcy=MathMax(lcy,MathAbs((fy3-fy4)/lstep)); + lcy=MathMax(lcy,MathAbs((fy4-fy1)/lstep)); + lcy=MathMax(lcy,MathAbs((fy1-fy3)/s2lstep)); + lcy=MathMax(lcy,MathAbs((fy2-fy4)/s2lstep)); + //--- Lipschitz constant for the cross-derivative + lcxy=MathMax(lcxy,MathAbs((fxy1-fxy2)/lstep)); + lcxy=MathMax(lcxy,MathAbs((fxy2-fxy3)/lstep)); + lcxy=MathMax(lcxy,MathAbs((fxy3-fxy4)/lstep)); + lcxy=MathMax(lcxy,MathAbs((fxy4-fxy1)/lstep)); + lcxy=MathMax(lcxy,MathAbs((fxy1-fxy3)/s2lstep)); + lcxy=MathMax(lcxy,MathAbs((fxy2-fxy4)/s2lstep)); + } + } + } +//+------------------------------------------------------------------+ +//| Numerical differentiation. | +//+------------------------------------------------------------------+ +static void CTestSpline2DUnit::TwodNumder(CSpline2DInterpolant &c,const double x, + const double y,const double h, + double &f,double &fx,double &fy, + double &fxy) + { +//--- calculation + f=CSpline2D::Spline2DCalc(c,x,y); + fx=(CSpline2D::Spline2DCalc(c,x+h,y)-CSpline2D::Spline2DCalc(c,x-h,y))/(2*h); + fy=(CSpline2D::Spline2DCalc(c,x,y+h)-CSpline2D::Spline2DCalc(c,x,y-h))/(2*h); + fxy=(CSpline2D::Spline2DCalc(c,x+h,y+h)-CSpline2D::Spline2DCalc(c,x-h,y+h)-CSpline2D::Spline2DCalc(c,x+h,y-h)+CSpline2D::Spline2DCalc(c,x-h,y-h))/CMath::Sqr(2*h); + } +//+------------------------------------------------------------------+ +//| Unpack test | +//+------------------------------------------------------------------+ +static bool CTestSpline2DUnit::TestUnpack(CSpline2DInterpolant &c,double &lx[], + double &ly[]) + { +//--- create variables + bool result; + int i=0; + int j=0; + int n=0; + int m=0; + int ci=0; + int cj=0; + int p=0; + double err=0; + double tx=0; + double ty=0; + double v1=0; + double v2=0; + int pass=0; + int passcount=0; +//--- create matrix + CMatrixDouble tbl; +//--- initialization + passcount=20; + err=0; +//--- function call + CSpline2D::Spline2DUnpack(c,m,n,tbl); +//--- calculation + 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*CMath::RandomReal())*(tbl[p][1]-tbl[p][0]); + ty=(0.001+0.999*CMath::RandomReal())*(tbl[p][3]-tbl[p][2]); + //--- Interpolation properties + v1=0; + for(ci=0;ci<=3;ci++) + { + for(cj=0;cj<=3;cj++) + v1=v1+tbl[p][4+ci*4+cj]*MathPow(tx,ci)*MathPow(ty,cj); + } + v2=CSpline2D::Spline2DCalc(c,tbl[p][0]+tx,tbl[p][2]+ty); + //--- search errors + err=MathMax(err,MathAbs(v1-v2)); + //--- Grid correctness + err=MathMax(err,MathAbs(lx[2*j]-tbl[p][0])); + err=MathMax(err,MathAbs(lx[2*(j+1)]-tbl[p][1])); + err=MathMax(err,MathAbs(ly[2*i]-tbl[p][2])); + err=MathMax(err,MathAbs(ly[2*(i+1)]-tbl[p][3])); + } + } + } +//--- get result + result=err<10000*CMath::m_machineepsilon; +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| LinTrans test | +//+------------------------------------------------------------------+ +static bool CTestSpline2DUnit::TestLinTrans(CSpline2DInterpolant &c, + const double ax,const double bx, + const double ay,const double by) + { +//--- create variables + bool result; + double err=0; + double a1=0; + double a2=0; + double b1=0; + double b2=0; + double tx=0; + double ty=0; + double vx=0; + double vy=0; + double v1=0; + double v2=0; + int pass=0; + int passcount=0; + int xjob=0; + int yjob=0; +//--- object of class + CSpline2DInterpolant c2; +//--- initialization + passcount=5; + err=0; +//--- calculation + for(xjob=0;xjob<=1;xjob++) + { + for(yjob=0;yjob<=1;yjob++) + { + for(pass=1;pass<=passcount;pass++) + { + //--- Prepare + do + { + a1=2*CMath::RandomReal()-1; + } + while(a1==0.0); + //--- change values + a1=a1*xjob; + b1=2*CMath::RandomReal()-1; + do + { + a2=2*CMath::RandomReal()-1; + } + while(a2==0.0); + //--- change values + a2=a2*yjob; + b2=2*CMath::RandomReal()-1; + //--- Test XY + CSpline2D::Spline2DCopy(c,c2); + CSpline2D::Spline2DLinTransXY(c2,a1,b1,a2,b2); + tx=ax+CMath::RandomReal()*(bx-ax); + ty=ay+CMath::RandomReal()*(by-ay); + //--- check + if(xjob==0) + { + tx=b1; + vx=ax+CMath::RandomReal()*(bx-ax); + } + else + vx=(tx-b1)/a1; + //--- check + if(yjob==0) + { + ty=b2; + vy=ay+CMath::RandomReal()*(by-ay); + } + else + vy=(ty-b2)/a2; + v1=CSpline2D::Spline2DCalc(c,tx,ty); + v2=CSpline2D::Spline2DCalc(c2,vx,vy); + //--- search errors + err=MathMax(err,MathAbs(v1-v2)); + //--- Test F + CSpline2D::Spline2DCopy(c,c2); + CSpline2D::Spline2DLinTransF(c2,a1,b1); + //--- change values + tx=ax+CMath::RandomReal()*(bx-ax); + ty=ay+CMath::RandomReal()*(by-ay); + v1=CSpline2D::Spline2DCalc(c,tx,ty); + v2=CSpline2D::Spline2DCalc(c2,tx,ty); + //--- search errors + err=MathMax(err,MathAbs(a1*v1+b1-v2)); + } + } + } +//--- get result + result=err<10000*CMath::m_machineepsilon; +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Unset spline,i.e. initialize it with random garbage | +//+------------------------------------------------------------------+ +static void CTestSpline2DUnit::UnsetSpline2D(CSpline2DInterpolant &c) + { +//--- create arrays + double x[]; + double y[]; +//--- create matrix + CMatrixDouble f; +//--- allocation + ArrayResize(x,2); + ArrayResize(y,2); + f.Resize(2,2); +//--- initialization + x[0]=-1; + x[1]=1; + y[0]=-1; + y[1]=1; + f[0].Set(0,0); + f[0].Set(1,0); + f[1].Set(0,0); + f[1].Set(1,0); +//--- function call + CSpline2D::Spline2DBuildBilinear(x,y,f,2,2,c); + } +//+------------------------------------------------------------------+ +//| Testing class CSpdGEVD | +//+------------------------------------------------------------------+ +class CTestSpdGEVDUnit + { +public: + //--- constructor, destructor + CTestSpdGEVDUnit(void); + ~CTestSpdGEVDUnit(void); + //--- public method + static bool TestSpdGEVD(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestSpdGEVDUnit::CTestSpdGEVDUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestSpdGEVDUnit::~CTestSpdGEVDUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CSpdGEVD | +//+------------------------------------------------------------------+ +static bool CTestSpdGEVDUnit::TestSpdGEVD(const bool silent) + { +//--- create variables + int pass=0; + int n=0; + int passcount=0; + int maxn=0; + int atask=0; + int btask=0; + bool isuppera; + bool isupperb; + int i=0; + int j=0; + int minij=0; + double v=0; + double v1=0; + double v2=0; + double err=0; + double valerr=0; + double threshold=0; + bool waserrors; + bool wfailed; + bool wnsorted; + int i_=0; +//--- create arrays + double d[]; + double t1[]; +//--- create matrix + CMatrixDouble a; + CMatrixDouble b; + CMatrixDouble afull; + CMatrixDouble bfull; + CMatrixDouble l; + CMatrixDouble z; +//--- initialization + threshold=10000*CMath::m_machineepsilon; + valerr=0; + wfailed=false; + wnsorted=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 + ArrayResize(t1,n); + a.Resize(n,n); + b.Resize(n,n); + afull.Resize(n,n); + bfull.Resize(n,n); + l.Resize(n,n); + //--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + a[i].Set(j,2*CMath::RandomReal()-1); + a[j].Set(i,a[i][j]); + afull[i].Set(j,a[i][j]); + afull[j].Set(i,a[i][j]); + } + } + //--- change values + for(i=0;i<=n-1;i++) + { + for(j=i+1;j<=n-1;j++) + { + l[i].Set(j,CMath::RandomReal()); + l[j].Set(i,l[i][j]); + } + l[i].Set(i,1.5+CMath::RandomReal()); + } + //--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + minij=MathMin(i,j); + //--- change value + v=0.0; + for(i_=0;i_<=minij;i_++) + { + v+=l[i][i_]*l[i_][j]; + } + b[i].Set(j,v); + b[j].Set(i,v); + bfull[i].Set(j,v); + bfull[j].Set(i,v); + } + } + //--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(isuppera) + { + //--- check + if(jthreshold || wfailed) || wnsorted; +//--- check + if(!silent) + { + Print("TESTING SYMMETRIC GEVD"); + Print("Av-lambdav error (generalized): "); + Print("{0,5:E3}",valerr); + Print("Eigen values order: "); + //--- check + if(!wnsorted) + Print("OK"); + else + Print("FAILED"); + Print("Always converged: "); + //--- check + if(!wfailed) + Print("YES"); + else + Print("NO"); + Print("Threshold: "); + Print("{0,5:E3}",threshold); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Testing class CInverseUpdate | +//+------------------------------------------------------------------+ +class CTestInverseUpdateUnit + { +private: + //--- private methods + static void MakeACopy(CMatrixDouble &a,const int m,const int n,CMatrixDouble &b); + static void MatLU(CMatrixDouble &a,const int m,const int n,int &pivots[]); + static void GenerateRandomOrthogonalMatrix(CMatrixDouble &a0,const int n); + static void GenerateRandomMatrixCond(CMatrixDouble &a0,const int n,const double c); + static bool InvMatTr(CMatrixDouble &a,const int n,const bool isupper,const bool isunittriangular); + static bool InvMatLU(CMatrixDouble &a,int &pivots[],const int n); + static bool InvMat(CMatrixDouble &a,const int n); + static double MatrixDiff(CMatrixDouble &a,CMatrixDouble &b,const int m,const int n); + static bool UpdAndInv(CMatrixDouble &a,double &u[],double &v[],const int n); +public: + //--- constructor, destructor + CTestInverseUpdateUnit(void); + ~CTestInverseUpdateUnit(void); + //--- public method + static bool TestInverseUpdate(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestInverseUpdateUnit::CTestInverseUpdateUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestInverseUpdateUnit::~CTestInverseUpdateUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CInverseUpdate | +//+------------------------------------------------------------------+ +static bool CTestInverseUpdateUnit::TestInverseUpdate(const bool silent) + { +//--- create variables + int n=0; + int maxn=0; + int i=0; + int updrow=0; + int updcol=0; + double val=0; + int pass=0; + int passcount=0; + bool waserrors; + double threshold=0; + double c=0; +//--- create arrays + double u[]; + double v[]; +//--- create matrix + CMatrixDouble a; + CMatrixDouble inva; + CMatrixDouble b1; + CMatrixDouble b2; +//--- initialization + waserrors=false; + maxn=10; + passcount=100; + threshold=1.0E-6; +//--- process + for(n=1;n<=maxn;n++) + { + //--- allocation + a.Resize(n,n); + b1.Resize(n,n); + b2.Resize(n,n); + ArrayResize(u,n); + ArrayResize(v,n); + //--- calculation + for(pass=1;pass<=passcount;pass++) + { + c=MathExp(CMath::RandomReal()*MathLog(10)); + GenerateRandomMatrixCond(a,n,c); + MakeACopy(a,n,n,inva); + //--- check + if(!InvMat(inva,n)) + { + waserrors=true; + break; + } + //--- Test simple update + updrow=CMath::RandomInteger(n); + updcol=CMath::RandomInteger(n); + val=0.1*(2*CMath::RandomReal()-1); + //--- change values + for(i=0;i<=n-1;i++) + { + //--- check + if(i==updrow) + u[i]=val; + else + u[i]=0; + //--- check + if(i==updcol) + v[i]=1; + else + v[i]=0; + } + //--- function call + MakeACopy(a,n,n,b1); + //--- check + if(!UpdAndInv(b1,u,v,n)) + { + waserrors=true; + break; + } + //--- function calls + MakeACopy(inva,n,n,b2); + CInverseUpdate::RMatrixInvUpdateSimple(b2,n,updrow,updcol,val); + //--- search errors + waserrors=waserrors || MatrixDiff(b1,b2,n,n)>threshold; + //--- Test row update + updrow=CMath::RandomInteger(n); + for(i=0;i<=n-1;i++) + { + //--- check + if(i==updrow) + u[i]=1; + else + u[i]=0; + v[i]=0.1*(2*CMath::RandomReal()-1); + } + //--- function call + MakeACopy(a,n,n,b1); + //--- check + if(!UpdAndInv(b1,u,v,n)) + { + waserrors=true; + break; + } + //--- function calls + MakeACopy(inva,n,n,b2); + CInverseUpdate::RMatrixInvUpdateRow(b2,n,updrow,v); + //--- search errors + waserrors=waserrors || MatrixDiff(b1,b2,n,n)>threshold; + //--- Test column update + updcol=CMath::RandomInteger(n); + for(i=0;i<=n-1;i++) + { + //--- check + if(i==updcol) + v[i]=1; + else + v[i]=0; + u[i]=0.1*(2*CMath::RandomReal()-1); + } + //--- function call + MakeACopy(a,n,n,b1); + //--- check + if(!UpdAndInv(b1,u,v,n)) + { + waserrors=true; + break; + } + //--- function calls + MakeACopy(inva,n,n,b2); + CInverseUpdate::RMatrixInvUpdateColumn(b2,n,updcol,u); + //--- search errors + waserrors=waserrors || MatrixDiff(b1,b2,n,n)>threshold; + //--- Test full update + for(i=0;i<=n-1;i++) + { + v[i]=0.1*(2*CMath::RandomReal()-1); + u[i]=0.1*(2*CMath::RandomReal()-1); + } + //--- function call + MakeACopy(a,n,n,b1); + //--- check + if(!UpdAndInv(b1,u,v,n)) + { + waserrors=true; + break; + } + //--- function calls + MakeACopy(inva,n,n,b2); + CInverseUpdate::RMatrixInvUpdateUV(b2,n,u,v); + //--- search errors + waserrors=waserrors || MatrixDiff(b1,b2,n,n)>threshold; + } + } +//--- report + if(!silent) + { + Print("TESTING INVERSE UPDATE (REAL)"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Copy | +//+------------------------------------------------------------------+ +static void CTestInverseUpdateUnit::MakeACopy(CMatrixDouble &a,const int m, + const int n,CMatrixDouble &b) + { +//--- create variables + int i=0; + int j=0; +//--- allocation + b.Resize(m,n); +//--- copy + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + b[i].Set(j,a[i][j]); + } + } +//+------------------------------------------------------------------+ +//| LU decomposition | +//+------------------------------------------------------------------+ +static void CTestInverseUpdateUnit::MatLU(CMatrixDouble &a,const int m, + const int n,int &pivots[]) + { +//--- create variables + int i=0; + int j=0; + int jp=0; + double s=0; + int i_=0; +//--- create array + double t1[]; +//--- allocation + ArrayResize(pivots,MathMin(m-1,n-1)+1); + ArrayResize(t1,MathMax(m-1,n-1)+1); +//--- check + if(!CAp::Assert(m>=0 && n>=0,"Error in LUDecomposition: incorrect function arguments")) + return; +//--- Quick return if possible + if(m==0 || n==0) + return; +//--- calculation + for(j=0;j<=MathMin(m-1,n-1);j++) + { + //--- Find pivot and test for singularity. + jp=j; + for(i=j+1;i<=m-1;i++) + { + //--- check + if(MathAbs(a[i][j])>MathAbs(a[jp][j])) + jp=i; + } + pivots[j]=jp; + //--- check + if(a[jp][j]!=0.0) + { + //--- Apply the interchange to rows + if(jp!=j) + { + for(i_=0;i_<=n-1;i_++) + t1[i_]=a[j][i_]; + for(i_=0;i_<=n-1;i_++) + a[j].Set(i_,a[jp][i_]); + for(i_=0;i_<=n-1;i_++) + a[jp].Set(i_,t1[i_]); + } + //--- Compute elements J+1:M of J-th column. + if(j1.0) + continue; + sm=MathSqrt(-(2*MathLog(sm)/sm)); + v[i]=u1*sm; + //--- check + if(i+1<=s) + v[i+1]=u2*sm; + i=i+2; + } + //--- change value + lambdav=0.0; + for(i_=1;i_<=s;i_++) + lambdav+=v[i_]*v[i_]; + } + while((double)(lambdav)==0.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=0.0; + for(i_=1;i_<=s;i_++) + t+=a[i][i_]*v[i_]; + w[i]=t; + } + //--- calculation + for(i=1;i<=s;i++) + { + t=w[i]*lambdav; + for(i_=1;i_<=s;i_++) + a[i].Set(i_,a[i][i_]-t*v[i_]); + } + } +//--- copy + for(i=1;i<=n;i++) + { + for(j=1;j<=n;j++) + a0[i-1].Set(j-1,a[i][j]); + } + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestInverseUpdateUnit::GenerateRandomMatrixCond(CMatrixDouble &a0, + const int n, + const double c) + { +//--- create variables + double l1=0; + double l2=0; + int i=0; + int j=0; + int k=0; +//--- create array + double cc[]; +//--- create matrix + CMatrixDouble q1; + CMatrixDouble q2; +//--- function calls + GenerateRandomOrthogonalMatrix(q1,n); + GenerateRandomOrthogonalMatrix(q2,n); +//--- allocation + ArrayResize(cc,n); +//--- change values + l1=0; + l2=MathLog(1/c); + cc[0]=MathExp(l1); + for(i=1;i<=n-2;i++) + cc[i]=MathExp(CMath::RandomReal()*(l2-l1)+l1); + cc[n-1]=MathExp(l2); +//--- allocation + a0.Resize(n,n); +//--- calculation + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + a0[i].Set(j,0); + for(k=0;k<=n-1;k++) + a0[i].Set(j,a0[i][j]+q1[i][k]*cc[k]*q2[j][k]); + } + } + } +//+------------------------------------------------------------------+ +//| triangular inverse | +//+------------------------------------------------------------------+ +static bool CTestInverseUpdateUnit::InvMatTr(CMatrixDouble &a,const int n, + const bool isupper, + const bool isunittriangular) + { +//--- create variables + bool result; + bool nounit; + int i=0; + int j=0; + double v=0; + double ajj=0; + int i_=0; +//--- create array + double t[]; +//--- initialization + result=true; +//--- allocation + ArrayResize(t,n); +//--- Test the input parameters. + nounit=!isunittriangular; +//--- check + if(isupper) + { + //--- Compute inverse of upper triangular matrix. + for(j=0;j<=n-1;j++) + { + //--- check + if(nounit) + { + //--- check + if(a[j][j]==0.0) + { + //--- return result + return(false); + } + a[j].Set(j,1/a[j][j]); + ajj=-a[j][j]; + } + else + ajj=-1; + //--- Compute elements 1:j-1 of j-th column. + if(j>0) + { + for(i_=0;i_<=j-1;i_++) + t[i_]=a[i_][j]; + for(i=0;i<=j-1;i++) + { + //--- check + if(i=0;j--) + { + //--- check + if(nounit) + { + //--- check + if(a[j][j]==0.0) + { + //--- return result + return(false); + } + //--- change values + a[j].Set(j,1/a[j][j]); + ajj=-a[j][j]; + } + else + ajj=-1; + //--- check + if(jj+1) + { + //--- change value + v=0.0; + for(i_=j+1;i_<=i-1;i_++) + v+=a[i][i_]*t[i_]; + } + else + v=0; + //--- check + if(nounit) + a[i].Set(j,v+a[i][i]*t[i]); + else + a[i].Set(j,v+t[i]); + } + //--- change values + for(i_=j+1;i_<=n-1;i_++) + a[i_].Set(j,ajj*a[i_][j]); + } + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| LU inverse | +//+------------------------------------------------------------------+ +static bool CTestInverseUpdateUnit::InvMatLU(CMatrixDouble &a,int &pivots[], + const int n) + { +//--- create variables + bool result; + int i=0; + int j=0; + int jp=0; + double v=0; + int i_=0; +//--- create array + double work[]; +//--- initialization + result=true; +//--- Quick return if possible + if(n==0) + { + //--- return result + return(result); + } +//--- allocation + ArrayResize(work,n); +//--- Form inv(U) + if(!InvMatTr(a,n,true,false)) + { + //--- return result + return(false); + } +//--- 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[i]=a[i][j]; + a[i].Set(j,0); + } + //--- Compute current column of inv(A). + if(j=0;j--) + { + jp=pivots[j]; + //--- check + if(jp!=j) + { + //--- copy + for(i_=0;i_<=n-1;i_++) + work[i_]=a[i_][j]; + for(i_=0;i_<=n-1;i_++) + a[i_].Set(j,a[i_][jp]); + for(i_=0;i_<=n-1;i_++) + a[i_].Set(jp,work[i_]); + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Matrix inverse | +//+------------------------------------------------------------------+ +static bool CTestInverseUpdateUnit::InvMat(CMatrixDouble &a,const int n) + { +//--- create array + int pivots[]; +//--- function call + MatLU(a,n,n,pivots); +//--- return result + return(InvMatLU(a,pivots,n)); + } +//+------------------------------------------------------------------+ +//| Diff | +//+------------------------------------------------------------------+ +static double CTestInverseUpdateUnit::MatrixDiff(CMatrixDouble &a, + CMatrixDouble &b, + const int m,const int n) + { +//--- create variables + double result=0; + int i=0; + int j=0; +//--- calculation + for(i=0;i<=m-1;i++) + { + for(j=0;j<=n-1;j++) + result=MathMax(result,MathAbs(b[i][j]-a[i][j])); + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Update and inverse | +//+------------------------------------------------------------------+ +static bool CTestInverseUpdateUnit::UpdAndInv(CMatrixDouble &a,double &u[], + double &v[],const int n) + { +//--- create variables + int i=0; + double r=0; + int i_=0; +//--- create array + int pivots[]; +//--- calculation + for(i=0;i<=n-1;i++) + { + r=u[i]; + for(i_=0;i_<=n-1;i_++) + a[i].Set(i_,a[i][i_]+r*v[i_]); + } +//--- function call + MatLU(a,n,n,pivots); +//--- return result + return(InvMatLU(a,pivots,n)); + } +//+------------------------------------------------------------------+ +//| Testing class CSchur | +//+------------------------------------------------------------------+ +class CTestSchurUnit + { +private: + //--- private methods + static void FillsParseA(CMatrixDouble &a,const int n,const double sparcity); + static void TestSchurProblem(CMatrixDouble &a,const int n,double &materr,double &orterr,bool &errstruct,bool &wfailed); +public: + //--- constructor, destructor + CTestSchurUnit(void); + ~CTestSchurUnit(void); + //--- public method + static bool TestSchur(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestSchurUnit::CTestSchurUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestSchurUnit::~CTestSchurUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing Schur decomposition subroutine | +//+------------------------------------------------------------------+ +static bool CTestSchurUnit::TestSchur(const bool silent) + { +//--- create variables + int n=0; + int maxn=0; + int i=0; + int j=0; + int pass=0; + int passcount=0; + bool waserrors; + bool errstruct; + bool wfailed; + double materr=0; + double orterr=0; + double threshold=0; +//--- create matrix + CMatrixDouble a; +//--- initialization + materr=0; + orterr=0; + errstruct=false; + wfailed=false; + waserrors=false; + maxn=70; + passcount=1; + threshold=5*100*CMath::m_machineepsilon; +//--- allocation + a.Resize(maxn,maxn); +//--- zero matrix,several cases + for(i=0;i<=maxn-1;i++) + { + for(j=0;j<=maxn-1;j++) + a[i].Set(j,0); + } + for(n=1;n<=maxn;n++) + { + //--- check + if(n>30 && n%2==0) + continue; + //--- function call + TestSchurProblem(a,n,materr,orterr,errstruct,wfailed); + } +//--- Dense matrix + for(pass=1;pass<=passcount;pass++) + { + for(n=1;n<=maxn;n++) + { + //--- check + if(n>30 && n%2==0) + continue; + //--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + a[i].Set(j,2*CMath::RandomReal()-1); + } + //--- function call + TestSchurProblem(a,n,materr,orterr,errstruct,wfailed); + } + } +//--- Sparse matrices,very sparse matrices,incredible sparse matrices + for(pass=1;pass<=1;pass++) + { + for(n=1;n<=maxn;n++) + { + //--- check + if(n>30 && n%3!=0) + continue; + //--- function calls + FillsParseA(a,n,0.8); + TestSchurProblem(a,n,materr,orterr,errstruct,wfailed); + FillsParseA(a,n,0.9); + TestSchurProblem(a,n,materr,orterr,errstruct,wfailed); + FillsParseA(a,n,0.95); + TestSchurProblem(a,n,materr,orterr,errstruct,wfailed); + FillsParseA(a,n,0.997); + TestSchurProblem(a,n,materr,orterr,errstruct,wfailed); + } + } +//--- report + waserrors=((materr>threshold || orterr>threshold) || errstruct) || wfailed; +//--- check + if(!silent) + { + Print("TESTING SCHUR DECOMPOSITION"); + Print("Schur decomposition error: "); + Print("{0,5:E3}",materr); + Print("Schur orthogonality error: "); + Print("{0,5:E3}",orterr); + Print("T matrix structure: "); + //--- check + if(!errstruct) + Print("OK"); + else + Print("FAILED"); + Print("Always converged: "); + //--- check + if(!wfailed) + Print("OK"); + else + Print("FAILED"); + Print("Threshold: "); + Print("{0,5:E3}",threshold); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestSchurUnit::FillsParseA(CMatrixDouble &a,const int n, + const double sparcity) + { +//--- create variables + int i=0; + int j=0; +//--- change values + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- check + if(CMath::RandomReal()>=sparcity) + a[i].Set(j,2*CMath::RandomReal()-1); + else + a[i].Set(j,0); + } + } + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestSchurUnit::TestSchurProblem(CMatrixDouble &a,const int n, + double &materr,double &orterr, + bool &errstruct,bool &wfailed) + { +//--- create variables + int i=0; + int j=0; + int k=0; + double v=0; + double locerr=0; + int i_=0; +//--- create arrays + double sr[]; + double astc[]; + double sastc[]; +//--- create matrix + CMatrixDouble s; + CMatrixDouble t; +//--- allocation + ArrayResize(sr,n); + ArrayResize(astc,n); + ArrayResize(sastc,n); +//--- Schur decomposition,convergence test + t.Resize(n,n); + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + t[i].Set(j,a[i][j]); + } +//--- check + if(!CSchur::RMatrixSchur(t,n,s)) + { + wfailed=true; + return; + } +//--- decomposition error + locerr=0; + for(j=0;j<=n-1;j++) + { + for(i_=0;i_<=n-1;i_++) + sr[i_]=s[j][i_]; + //--- calculation + for(k=0;k<=n-1;k++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=t[k][i_]*sr[i_]; + astc[k]=v; + } + //--- calculation + for(k=0;k<=n-1;k++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=s[k][i_]*astc[i_]; + sastc[k]=v; + } + //--- search errors + for(k=0;k<=n-1;k++) + locerr=MathMax(locerr,MathAbs(sastc[k]-a[k][j])); + } +//--- search errors + materr=MathMax(materr,locerr); +//--- orthogonality error + locerr=0; + for(i=0;i<=n-1;i++) + { + for(j=0;j<=n-1;j++) + { + //--- change value + v=0.0; + for(i_=0;i_<=n-1;i_++) + v+=s[i_][i]*s[i_][j]; + //--- check + if(i!=j) + locerr=MathMax(locerr,MathAbs(v)); + else + locerr=MathMax(locerr,MathAbs(v-1)); + } + } +//--- search errors + orterr=MathMax(orterr,locerr); +//--- T matrix structure + for(j=0;j<=n-1;j++) + { + for(i=j+2;i<=n-1;i++) + { + //--- check + if(t[i][j]!=0.0) + errstruct=true; + } + } + } +//+------------------------------------------------------------------+ +//| Testing class CNlEq | +//+------------------------------------------------------------------+ +class CTestNlEqUnit + { +private: + //--- private methods + static void TestFuncHBM(CNlEqState &state); + static void TestFuncHB1(CNlEqState &state); + static void TestFuncSHBM(CNlEqState &state); +public: + //--- constructor, destructor + CTestNlEqUnit(void); + ~CTestNlEqUnit(void); + //--- public method + static bool TestNlEq(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestNlEqUnit::CTestNlEqUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestNlEqUnit::~CTestNlEqUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CNlEq | +//+------------------------------------------------------------------+ +static bool CTestNlEqUnit::TestNlEq(const bool silent) + { +//--- create variables + bool waserrors; + bool basicserrors; + bool converror; + bool othererrors; + int n=0; + int i=0; + int k=0; + double v=0; + double flast=0; + bool firstrep; + int nfunc=0; + int njac=0; + int itcnt=0; + int pass=0; + int passcount=0; + double epsf=0; + double stpmax=0; + int i_=0; +//--- create arrays + double x[]; + double xlast[]; +//--- objects of classes + CNlEqState state; + CNlEqReport rep; +//--- initialization + waserrors=false; + basicserrors=false; + converror=false; + othererrors=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 + ArrayResize(x,2); + x[0]=20*CMath::RandomReal()-10; + x[1]=20*CMath::RandomReal()-10; + //--- function call + CNlEq::NlEqCreateLM(2,2,x,state); + epsf=1.0E-9; + //--- function call + CNlEq::NlEqSetCond(state,epsf,0); + //--- cycle + while(CNlEq::NlEqIteration(state)) + TestFuncHBM(state); + //--- function call + CNlEq::NlEqResults(state,x,rep); + //--- check + if(rep.m_terminationtype>0) + basicserrors=basicserrors || CMath::Sqr(x[0]*x[0]+x[1]-11)+CMath::Sqr(x[0]+x[1]*x[1]-7)>CMath::Sqr(epsf); + else + basicserrors=true; + //--- Ability to work after soft restart + ArrayResize(x,2); + x[0]=20*CMath::RandomReal()-10; + x[1]=20*CMath::RandomReal()-10; + //--- function call + CNlEq::NlEqCreateLM(2,2,x,state); + epsf=1.0E-9; + //--- function call + CNlEq::NlEqSetCond(state,epsf,0); + //--- cycle + while(CNlEq::NlEqIteration(state)) + TestFuncHBM(state); + //--- function call + CNlEq::NlEqResults(state,x,rep); + //--- allocation + ArrayResize(x,2); + //--- change values + x[0]=20*CMath::RandomReal()-10; + x[1]=20*CMath::RandomReal()-10; + //--- function call + CNlEq::NlEqRestartFrom(state,x); + //--- cycle + while(CNlEq::NlEqIteration(state)) + TestFuncHBM(state); + //--- function call + CNlEq::NlEqResults(state,x,rep); + //--- check + if(rep.m_terminationtype>0) + basicserrors=basicserrors || CMath::Sqr(x[0]*x[0]+x[1]-11)+CMath::Sqr(x[0]+x[1]*x[1]-7)>CMath::Sqr(epsf); + else + basicserrors=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 + ArrayResize(x,2); + x[0]=100; + x[1]=100; + //--- function call + CNlEq::NlEqCreateLM(2,2,x,state); + epsf=1.0E-9; + //--- function calls + CNlEq::NlEqSetCond(state,epsf,0); + CNlEq::NlEqSetStpMax(state,0.01); + k=1+CMath::RandomInteger(100); + //--- calculation + for(i=0;i<=k-1;i++) + { + //--- check + if(!CNlEq::NlEqIteration(state)) + break; + TestFuncHBM(state); + } + //--- allocation + ArrayResize(x,2); + //--- change values + x[0]=20*CMath::RandomReal()-10; + x[1]=20*CMath::RandomReal()-10; + //--- function call + CNlEq::NlEqRestartFrom(state,x); + //--- cycle + while(CNlEq::NlEqIteration(state)) + TestFuncHBM(state); + //--- function call + CNlEq::NlEqResults(state,x,rep); + //--- check + if(rep.m_terminationtype>0) + basicserrors=basicserrors || CMath::Sqr(x[0]*x[0]+x[1]-11)+CMath::Sqr(x[0]+x[1]*x[1]-7)>CMath::Sqr(epsf); + else + basicserrors=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 + ArrayResize(x,2); + x[0]=20*CMath::RandomReal()-10; + x[1]=20*CMath::RandomReal()-10; + //--- function call + CNlEq::NlEqCreateLM(2,1,x,state); + epsf=1.0E-9; + //--- function call + CNlEq::NlEqSetCond(state,epsf,0); + //--- cycle + while(CNlEq::NlEqIteration(state)) + TestFuncHB1(state); + //--- function call + CNlEq::NlEqResults(state,x,rep); + //--- check + if(rep.m_terminationtype>0) + basicserrors=basicserrors || CMath::Sqr(x[0]*x[0]+x[1]-11)+CMath::Sqr(x[0]+x[1]*x[1]-7)>(double)(epsf); + else + basicserrors=true; + } +//--- Basic tests +//--- Ability to detect situation when we can't find minimum + passcount=100; + for(pass=0;pass<=passcount-1;pass++) + { + //--- allocation + ArrayResize(x,2); + x[0]=20*CMath::RandomReal()-10; + x[1]=20*CMath::RandomReal()-10; + //--- function call + CNlEq::NlEqCreateLM(2,3,x,state); + epsf=1.0E-9; + //--- function call + CNlEq::NlEqSetCond(state,epsf,0); + //--- cycle + while(CNlEq::NlEqIteration(state)) + TestFuncSHBM(state); + //--- function call + CNlEq::NlEqResults(state,x,rep); + //--- search errors + basicserrors=basicserrors || rep.m_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; + ArrayResize(x,n); + ArrayResize(xlast,n); +//--- change values + x[0]=20*CMath::RandomReal()-10; + x[1]=20*CMath::RandomReal()-10; + xlast[0]=CMath::m_maxrealnumber; + xlast[1]=CMath::m_maxrealnumber; +//--- function calls + CNlEq::NlEqCreateLM(n,2,x,state); + CNlEq::NlEqSetCond(state,1.0E-6,0); + CNlEq::NlEqSetXRep(state,true); +//--- change values + firstrep=true; + flast=CMath::m_maxrealnumber; + nfunc=0; + njac=0; + itcnt=0; +//--- cycle + while(CNlEq::NlEqIteration(state)) + { + //--- check + if(state.m_xupdated) + { + //--- first report must be starting point + if(firstrep) + { + for(i=0;i<=n-1;i++) + othererrors=othererrors || state.m_x[i]!=x[i]; + firstrep=false; + } + //--- function value must decrease + othererrors=othererrors || state.m_f>flast; + //--- check correctness of function value + v=CMath::Sqr(state.m_x[0]*state.m_x[0]+state.m_x[1]-11)+CMath::Sqr(state.m_x[0]+state.m_x[1]*state.m_x[1]-7); + othererrors=othererrors || MathAbs(v-state.m_f)/MathMax(v,1)>100*CMath::m_machineepsilon; + //--- update info and continue + for(i_=0;i_<=n-1;i_++) + xlast[i_]=state.m_x[i_]; + flast=state.m_f; + itcnt=itcnt+1; + continue; + } + //--- check + if(state.m_needf) + nfunc=nfunc+1; + //--- check + if(state.m_needfij) + { + nfunc=nfunc+1; + njac=njac+1; + } + //--- function call + TestFuncHBM(state); + } +//--- function call + CNlEq::NlEqResults(state,x,rep); +//--- check + if(rep.m_terminationtype>0) + { + othererrors=(othererrors || xlast[0]!=x[0]) || xlast[1]!=x[1]; + v=CMath::Sqr(x[0]*x[0]+x[1]-11)+CMath::Sqr(x[0]+x[1]*x[1]-7); + othererrors=othererrors || MathAbs(flast-v)/MathMax(v,1)>100*CMath::m_machineepsilon; + } + else + converror=true; +//--- search errors + othererrors=othererrors || rep.m_nfunc!=nfunc; + othererrors=othererrors || rep.m_njac!=njac; + othererrors=othererrors || rep.m_iterationscount!=itcnt-1; +//--- Test ability to set limit on algorithm steps + ArrayResize(x,2); + ArrayResize(xlast,2); +//--- change values + x[0]=20*CMath::RandomReal()+20; + x[1]=20*CMath::RandomReal()+20; + xlast[0]=x[0]; + xlast[1]=x[1]; + stpmax=0.1+0.1*CMath::RandomReal(); + epsf=1.0E-9; +//--- function calls + CNlEq::NlEqCreateLM(2,3,x,state); + CNlEq::NlEqSetStpMax(state,stpmax); + CNlEq::NlEqSetCond(state,epsf,0); + CNlEq::NlEqSetXRep(state,true); +//--- cycle + while(CNlEq::NlEqIteration(state)) + { + //--- check + if(state.m_needf || state.m_needfij) + TestFuncHBM(state); + //--- check + if((state.m_needf || state.m_needfij) || state.m_xupdated) + othererrors=othererrors || MathSqrt(CMath::Sqr(state.m_x[0]-xlast[0])+CMath::Sqr(state.m_x[1]-xlast[1]))>1.00001*stpmax; + //--- check + if(state.m_xupdated) + { + xlast[0]=state.m_x[0]; + xlast[1]=state.m_x[1]; + } + } +//--- end + waserrors=(basicserrors || converror) || othererrors; +//--- check + if(!silent) + { + Print("TESTING NLEQ SOLVER"); + Print("BASIC FUNCTIONALITY: "); + //--- check + if(basicserrors) + Print("FAILED"); + else + Print("OK"); + Print("CONVERGENCE: "); + //--- check + if(converror) + Print("FAILED"); + else + Print("OK"); + Print("OTHER PROPERTIES: "); + //--- check + if(othererrors) + Print("FAILED"); + else + Print("OK"); + //--- check + if(waserrors) + Print("TEST FAILED"); + else + Print("TEST PASSED"); + Print(""); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| 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 CTestNlEqUnit::TestFuncHBM(CNlEqState &state) + { +//--- create variables + double x=0; + double y=0; +//--- check + if(!CAp::Assert(state.m_needf || state.m_needfij,"TestNLEQUnit: internal error!")) + return; +//--- change values + x=state.m_x[0]; + y=state.m_x[1]; +//--- check + if(state.m_needf) + { + state.m_f=CMath::Sqr(x*x+y-11)+CMath::Sqr(x+y*y-7); + return; + } +//--- check + if(state.m_needfij) + { + state.m_fi[0]=x*x+y-11; + state.m_fi[1]=x+y*y-7; + state.m_j[0].Set(0,2*x); + state.m_j[0].Set(1,1); + state.m_j[1].Set(0,1); + state.m_j[1].Set(1,2*y); + //--- exit the function + return; + } + } +//+------------------------------------------------------------------+ +//| Himmelblau's function | +//| F=(x^2+y-11)^2 + (x+y^2-7)^2 | +//| posed as system of 1 function | +//+------------------------------------------------------------------+ +static void CTestNlEqUnit::TestFuncHB1(CNlEqState &state) + { +//--- create variables + double x=0; + double y=0; +//--- check + if(!CAp::Assert(state.m_needf || state.m_needfij,"TestNLEQUnit: internal error!")) + return; +//--- change values + x=state.m_x[0]; + y=state.m_x[1]; +//--- check + if(state.m_needf) + { + state.m_f=CMath::Sqr(CMath::Sqr(x*x+y-11)+CMath::Sqr(x+y*y-7)); + return; + } +//--- check + if(state.m_needfij) + { + state.m_fi[0]=CMath::Sqr(x*x+y-11)+CMath::Sqr(x+y*y-7); + state.m_j[0].Set(0,2*(x*x+y-11)*2*x+2*(x+y*y-7)); + state.m_j[0].Set(1,2*(x*x+y-11)+2*(x+y*y-7)*2*y); + //--- exit the function + 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 CTestNlEqUnit::TestFuncSHBM(CNlEqState &state) + { +//--- create variables + double x=0; + double y=0; +//--- check + if(!CAp::Assert(state.m_needf || state.m_needfij,"TestNLEQUnit: internal error!")) + return; +//--- change values + x=state.m_x[0]; + y=state.m_x[1]; +//--- check + if(state.m_needf) + { + state.m_f=CMath::Sqr(x*x+y-11)+CMath::Sqr(x+y*y-7)+1; + return; + } +//--- check + if(state.m_needfij) + { + state.m_fi[0]=x*x+y-11; + state.m_fi[1]=x+y*y-7; + state.m_fi[2]=1; + state.m_j[0].Set(0,2*x); + state.m_j[0].Set(1,1); + state.m_j[1].Set(0,1); + state.m_j[1].Set(1,2*y); + state.m_j[2].Set(0,0); + state.m_j[2].Set(1,0); + //--- exit the function + return; + } + } +//+------------------------------------------------------------------+ +//| Testing class CChebyshev | +//+------------------------------------------------------------------+ +class CTestChebyshevUnit + { +public: + //--- constructor, destructor + CTestChebyshevUnit(void); + ~CTestChebyshevUnit(void); + //--- public method + static bool TestChebyshev(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestChebyshevUnit::CTestChebyshevUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestChebyshevUnit::~CTestChebyshevUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CChebyshev | +//+------------------------------------------------------------------+ +static bool CTestChebyshevUnit::TestChebyshev(const bool silent) + { +//--- create variables + double err=0; + double sumerr=0; + double cerr=0; + double ferr=0; + double threshold=0; + double x=0; + double v=0; + int pass=0; + int i=0; + int j=0; + int k=0; + int n=0; + int maxn=0; + bool waserrors; + int i_=0; +//--- create arrays + double c[]; + double p1[]; + double p2[]; +//--- create matrix + CMatrixDouble a; +//--- initialization + err=0; + sumerr=0; + cerr=0; + ferr=0; + threshold=1.0E-9; + waserrors=false; +//--- Testing Chebyshev polynomials of the first kind + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(1,0,0.00)-1)); + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(1,0,0.33)-1)); + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(1,0,-0.42)-1)); + x=0.2; + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(1,1,x)-0.2)); + x=0.4; + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(1,1,x)-0.4)); + x=0.6; + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(1,1,x)-0.6)); + x=0.8; + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(1,1,x)-0.8)); + x=1.0; + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(1,1,x)-1.0)); + x=0.2; + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(1,2,x)+0.92)); + x=0.4; + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(1,2,x)+0.68)); + x=0.6; + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(1,2,x)+0.28)); + x=0.8; + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(1,2,x)-0.28)); + x=1.0; + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(1,2,x)-1.00)); + n=10; + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(1,n,0.2)-0.4284556288)); + n=11; + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(1,n,0.2)+0.7996160205)); + n=12; + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(1,n,0.2)+0.7483020370)); +//--- Testing Chebyshev polynomials of the second kind + n=0; + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(2,n,0.2)-1.0000000000)); + n=1; + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(2,n,0.2)-0.4000000000)); + n=2; + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(2,n,0.2)+0.8400000000)); + n=3; + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(2,n,0.2)+0.7360000000)); + n=4; + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(2,n,0.2)-0.5456000000)); + n=10; + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(2,n,0.2)-0.6128946176)); + n=11; + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(2,n,0.2)+0.6770370970)); + n=12; + err=MathMax(err,MathAbs(CChebyshev::ChebyshevCalculate(2,n,0.2)+0.8837094564)); +//--- Testing Clenshaw summation + maxn=20; + ArrayResize(c,maxn+1); + for(k=1;k<=2;k++) + { + for(pass=1;pass<=10;pass++) + { + x=2*CMath::RandomReal()-1; + v=0; + //--- calculation + for(n=0;n<=maxn;n++) + { + c[n]=2*CMath::RandomReal()-1; + v=v+CChebyshev::ChebyshevCalculate(k,n,x)*c[n]; + //--- search errors + sumerr=MathMax(sumerr,MathAbs(v-CChebyshev::ChebyshevSum(c,k,n,x))); + } + } + } +//--- Testing coefficients + CChebyshev::ChebyshevCoefficients(0,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-1)); +//--- function call + CChebyshev::ChebyshevCoefficients(1,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-0)); + cerr=MathMax(cerr,MathAbs(c[1]-1)); +//--- function call + CChebyshev::ChebyshevCoefficients(2,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]+1)); + cerr=MathMax(cerr,MathAbs(c[1]-0)); + cerr=MathMax(cerr,MathAbs(c[2]-2)); +//--- function call + CChebyshev::ChebyshevCoefficients(3,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-0)); + cerr=MathMax(cerr,MathAbs(c[1]+3)); + cerr=MathMax(cerr,MathAbs(c[2]-0)); + cerr=MathMax(cerr,MathAbs(c[3]-4)); +//--- function call + CChebyshev::ChebyshevCoefficients(4,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-1)); + cerr=MathMax(cerr,MathAbs(c[1]-0)); + cerr=MathMax(cerr,MathAbs(c[2]+8)); + cerr=MathMax(cerr,MathAbs(c[3]-0)); + cerr=MathMax(cerr,MathAbs(c[4]-8)); +//--- function call + CChebyshev::ChebyshevCoefficients(9,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-0)); + cerr=MathMax(cerr,MathAbs(c[1]-9)); + cerr=MathMax(cerr,MathAbs(c[2]-0)); + cerr=MathMax(cerr,MathAbs(c[3]+120)); + cerr=MathMax(cerr,MathAbs(c[4]-0)); + cerr=MathMax(cerr,MathAbs(c[5]-432)); + cerr=MathMax(cerr,MathAbs(c[6]-0)); + cerr=MathMax(cerr,MathAbs(c[7]+576)); + cerr=MathMax(cerr,MathAbs(c[8]-0)); + cerr=MathMax(cerr,MathAbs(c[9]-256)); +//--- Testing FromChebyshev + maxn=10; + a.Resize(maxn+1,maxn+1); + for(i=0;i<=maxn;i++) + { + for(j=0;j<=maxn;j++) + a[i].Set(j,0); + //--- function call + CChebyshev::ChebyshevCoefficients(i,c); + for(i_=0;i_<=i;i_++) + a[i].Set(i_,c[i_]); + } +//--- allocation + ArrayResize(c,maxn+1); + ArrayResize(p1,maxn+1); +//--- calculation + for(n=0;n<=maxn;n++) + { + for(pass=1;pass<=10;pass++) + { + for(i=0;i<=n;i++) + p1[i]=0; + for(i=0;i<=n;i++) + { + //--- change values + c[i]=2*CMath::RandomReal()-1; + v=c[i]; + for(i_=0;i_<=i;i_++) + p1[i_]=p1[i_]+v*a[i][i_]; + } + //--- function call + CChebyshev::FromChebyshev(c,n,p2); + for(i=0;i<=n;i++) + ferr=MathMax(ferr,MathAbs(p1[i]-p2[i])); + } + } +//--- Reporting + waserrors=((err>threshold || sumerr>threshold) || cerr>threshold) || ferr>threshold; +//--- check + if(!silent) + { + Print("TESTING CALCULATION OF THE CHEBYSHEV POLYNOMIALS"); + Print("Max error against table "); + Print("{0,5:E2}",err); + Print("Summation error "); + Print("{0,5:E2}",sumerr); + Print("Coefficients error "); + Print("{0,5:E2}",cerr); + Print("FrobChebyshev error "); + Print("{0,5:E2}",ferr); + Print("Threshold "); + Print("{0,5:E2}",threshold); + //--- check + if(!waserrors) + Print("TEST PASSED"); + else + Print("TEST FAILED"); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Testing class CHermite | +//+------------------------------------------------------------------+ +class CTestHermiteUnit + { +public: + //--- constructor, destructor + CTestHermiteUnit(void); + ~CTestHermiteUnit(void); + //--- method + static bool TestHermite(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestHermiteUnit::CTestHermiteUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestHermiteUnit::~CTestHermiteUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CHermite | +//+------------------------------------------------------------------+ +static bool CTestHermiteUnit::TestHermite(const bool silent) + { +//--- create variables + double err=0; + double sumerr=0; + double cerr=0; + double threshold=0; + int n=0; + int maxn=0; + int pass=0; + double x=0; + double v=0; + bool waserrors; +//--- create array + double c[]; +//--- initialization + err=0; + sumerr=0; + cerr=0; + threshold=1.0E-9; + waserrors=false; +//--- Testing Hermite polynomials + n=0; + err=MathMax(err,MathAbs(CHermite::HermiteCalculate(n,1)-1)); + n=1; + err=MathMax(err,MathAbs(CHermite::HermiteCalculate(n,1)-2)); + n=2; + err=MathMax(err,MathAbs(CHermite::HermiteCalculate(n,1)-2)); + n=3; + err=MathMax(err,MathAbs(CHermite::HermiteCalculate(n,1)+4)); + n=4; + err=MathMax(err,MathAbs(CHermite::HermiteCalculate(n,1)+20)); + n=5; + err=MathMax(err,MathAbs(CHermite::HermiteCalculate(n,1)+8)); + n=6; + err=MathMax(err,MathAbs(CHermite::HermiteCalculate(n,1)-184)); + n=7; + err=MathMax(err,MathAbs(CHermite::HermiteCalculate(n,1)-464)); + n=11; + err=MathMax(err,MathAbs(CHermite::HermiteCalculate(n,1)-230848)); + n=12; + err=MathMax(err,MathAbs(CHermite::HermiteCalculate(n,1)-280768)); +//--- Testing Clenshaw summation + maxn=10; + ArrayResize(c,maxn+1); + for(pass=1;pass<=10;pass++) + { + x=2*CMath::RandomReal()-1; + v=0; + //--- calculation + for(n=0;n<=maxn;n++) + { + c[n]=2*CMath::RandomReal()-1; + v=v+CHermite::HermiteCalculate(n,x)*c[n]; + //--- search errors + sumerr=MathMax(sumerr,MathAbs(v-CHermite::HermiteSum(c,n,x))); + } + } +//--- Testing coefficients + CHermite::HermiteCoefficients(0,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-1)); +//--- function call + CHermite::HermiteCoefficients(1,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-0)); + cerr=MathMax(cerr,MathAbs(c[1]-2)); +//--- function call + CHermite::HermiteCoefficients(2,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]+2)); + cerr=MathMax(cerr,MathAbs(c[1]-0)); + cerr=MathMax(cerr,MathAbs(c[2]-4)); +//--- function call + CHermite::HermiteCoefficients(3,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-0)); + cerr=MathMax(cerr,MathAbs(c[1]+12)); + cerr=MathMax(cerr,MathAbs(c[2]-0)); + cerr=MathMax(cerr,MathAbs(c[3]-8)); +//--- function call + CHermite::HermiteCoefficients(4,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-12)); + cerr=MathMax(cerr,MathAbs(c[1]-0)); + cerr=MathMax(cerr,MathAbs(c[2]+48)); + cerr=MathMax(cerr,MathAbs(c[3]-0)); + cerr=MathMax(cerr,MathAbs(c[4]-16)); +//--- function call + CHermite::HermiteCoefficients(5,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-0)); + cerr=MathMax(cerr,MathAbs(c[1]-120)); + cerr=MathMax(cerr,MathAbs(c[2]-0)); + cerr=MathMax(cerr,MathAbs(c[3]+160)); + cerr=MathMax(cerr,MathAbs(c[4]-0)); + cerr=MathMax(cerr,MathAbs(c[5]-32)); +//--- function call + CHermite::HermiteCoefficients(6,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]+120)); + cerr=MathMax(cerr,MathAbs(c[1]-0)); + cerr=MathMax(cerr,MathAbs(c[2]-720)); + cerr=MathMax(cerr,MathAbs(c[3]-0)); + cerr=MathMax(cerr,MathAbs(c[4]+480)); + cerr=MathMax(cerr,MathAbs(c[5]-0)); + cerr=MathMax(cerr,MathAbs(c[6]-64)); +//--- Reporting + waserrors=(err>threshold || sumerr>threshold) || cerr>threshold; +//--- check + if(!silent) + { + Print("TESTING CALCULATION OF THE HERMITE POLYNOMIALS"); + Print("Max error "); + Print("{0,5:E2}",err); + Print("Summation error "); + Print("{0,5:E2}",sumerr); + Print("Coefficients error "); + Print("{0,5:E2}",cerr); + Print("Threshold "); + Print("{0,5:E2}",threshold); + //--- check + if(!waserrors) + Print("TEST PASSED"); + else + Print("TEST FAILED"); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Testing class CLaguerre | +//+------------------------------------------------------------------+ +class CTestLaguerreUnit + { +public: + //--- constructor, destructor + CTestLaguerreUnit(void); + ~CTestLaguerreUnit(void); + //--- public method + static bool TestLaguerre(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestLaguerreUnit::CTestLaguerreUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestLaguerreUnit::~CTestLaguerreUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CLaguerre | +//+------------------------------------------------------------------+ +static bool CTestLaguerreUnit::TestLaguerre(const bool silent) + { +//--- create variables + double err=0; + double sumerr=0; + double cerr=0; + double threshold=0; + int n=0; + int maxn=0; + int pass=0; + double x=0; + double v=0; + bool waserrors; +//--- create array + double c[]; +//--- initialization + err=0; + sumerr=0; + cerr=0; + threshold=1.0E-9; + waserrors=false; +//--- Testing Laguerre polynomials + n=0; + err=MathMax(err,MathAbs(CLaguerre::LaguerreCalculate(n,0.5)-1.0000000000)); + n=1; + err=MathMax(err,MathAbs(CLaguerre::LaguerreCalculate(n,0.5)-0.5000000000)); + n=2; + err=MathMax(err,MathAbs(CLaguerre::LaguerreCalculate(n,0.5)-0.1250000000)); + n=3; + err=MathMax(err,MathAbs(CLaguerre::LaguerreCalculate(n,0.5)+0.1458333333)); + n=4; + err=MathMax(err,MathAbs(CLaguerre::LaguerreCalculate(n,0.5)+0.3307291667)); + n=5; + err=MathMax(err,MathAbs(CLaguerre::LaguerreCalculate(n,0.5)+0.4455729167)); + n=6; + err=MathMax(err,MathAbs(CLaguerre::LaguerreCalculate(n,0.5)+0.5041449653)); + n=7; + err=MathMax(err,MathAbs(CLaguerre::LaguerreCalculate(n,0.5)+0.5183392237)); + n=8; + err=MathMax(err,MathAbs(CLaguerre::LaguerreCalculate(n,0.5)+0.4983629984)); + n=9; + err=MathMax(err,MathAbs(CLaguerre::LaguerreCalculate(n,0.5)+0.4529195204)); + n=10; + err=MathMax(err,MathAbs(CLaguerre::LaguerreCalculate(n,0.5)+0.3893744141)); + n=11; + err=MathMax(err,MathAbs(CLaguerre::LaguerreCalculate(n,0.5)+0.3139072988)); + n=12; + err=MathMax(err,MathAbs(CLaguerre::LaguerreCalculate(n,0.5)+0.2316496389)); +//--- Testing Clenshaw summation + maxn=20; + ArrayResize(c,maxn+1); + for(pass=1;pass<=10;pass++) + { + x=2*CMath::RandomReal()-1; + v=0; + //--- calculation + for(n=0;n<=maxn;n++) + { + c[n]=2*CMath::RandomReal()-1; + v=v+CLaguerre::LaguerreCalculate(n,x)*c[n]; + //--- search errors + sumerr=MathMax(sumerr,MathAbs(v-CLaguerre::LaguerreSum(c,n,x))); + } + } +//--- Testing coefficients + CLaguerre::LaguerreCoefficients(0,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-1)); +//--- function call + CLaguerre::LaguerreCoefficients(1,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-1)); + cerr=MathMax(cerr,MathAbs(c[1]+1)); +//--- function call + CLaguerre::LaguerreCoefficients(2,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-2.0/2.0)); + cerr=MathMax(cerr,MathAbs(c[1]+4.0/2.0)); + cerr=MathMax(cerr,MathAbs(c[2]-1.0/2.0)); +//--- function call + CLaguerre::LaguerreCoefficients(3,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-6.0/6.0)); + cerr=MathMax(cerr,MathAbs(c[1]+18.0/6.0)); + cerr=MathMax(cerr,MathAbs(c[2]-9.0/6.0)); + cerr=MathMax(cerr,MathAbs(c[3]+1.0/6.0)); +//--- function call + CLaguerre::LaguerreCoefficients(4,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-24.0/24.0)); + cerr=MathMax(cerr,MathAbs(c[1]+96.0/24.0)); + cerr=MathMax(cerr,MathAbs(c[2]-72.0/24.0)); + cerr=MathMax(cerr,MathAbs(c[3]+16.0/24.0)); + cerr=MathMax(cerr,MathAbs(c[4]-1.0/24.0)); +//--- function call + CLaguerre::LaguerreCoefficients(5,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-120.0/120.0)); + cerr=MathMax(cerr,MathAbs(c[1]+600.0/120.0)); + cerr=MathMax(cerr,MathAbs(c[2]-600.0/120.0)); + cerr=MathMax(cerr,MathAbs(c[3]+200.0/120.0)); + cerr=MathMax(cerr,MathAbs(c[4]-25.0/120.0)); + cerr=MathMax(cerr,MathAbs(c[5]+1.0/120.0)); +//--- function call + CLaguerre::LaguerreCoefficients(6,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-720.0/720.0)); + cerr=MathMax(cerr,MathAbs(c[1]+4320.0/720.0)); + cerr=MathMax(cerr,MathAbs(c[2]-5400.0/720.0)); + cerr=MathMax(cerr,MathAbs(c[3]+2400.0/720.0)); + cerr=MathMax(cerr,MathAbs(c[4]-450.0/720.0)); + cerr=MathMax(cerr,MathAbs(c[5]+36.0/720.0)); + cerr=MathMax(cerr,MathAbs(c[6]-1.0/720.0)); +//--- Reporting + waserrors=(err>threshold || sumerr>threshold) || cerr>threshold; +//--- check + if(!silent) + { + Print("TESTING CALCULATION OF THE LAGUERRE POLYNOMIALS"); + Print("Max error "); + Print("{0,5:E2}",err); + Print("Summation error "); + Print("{0,5:E2}",sumerr); + Print("Coefficients error "); + Print("{0,5:E2}",cerr); + Print("Threshold "); + Print("{0,5:E2}",threshold); + //--- check + if(!waserrors) + Print("TEST PASSED"); + else + Print("TEST FAILED"); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| Testing class CLegendre | +//+------------------------------------------------------------------+ +class CTestLegendreUnit + { +public: + //--- constructor, destructor + CTestLegendreUnit(void); + ~CTestLegendreUnit(void); + //--- public method + static bool TestLegendre(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestLegendreUnit::CTestLegendreUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestLegendreUnit::~CTestLegendreUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing class CLegendre | +//+------------------------------------------------------------------+ +static bool CTestLegendreUnit::TestLegendre(const bool silent) + { +//--- create variables + double err=0; + double sumerr=0; + double cerr=0; + double threshold=0; + int n=0; + int maxn=0; + int i=0; + int pass=0; + double x=0; + double v=0; + double t=0; + bool waserrors; +//--- create array + double c[]; +//--- initialization + err=0; + sumerr=0; + cerr=0; + threshold=1.0E-9; + waserrors=false; +//--- Testing Legendre polynomials values + for(n=0;n<=10;n++) + { + //--- function call + CLegendre::LegendreCoefficients(n,c); + for(pass=1;pass<=10;pass++) + { + //--- calculation + x=2*CMath::RandomReal()-1; + v=CLegendre::LegendreCalculate(n,x); + t=1; + for(i=0;i<=n;i++) + { + v=v-c[i]*t; + t=t*x; + } + //--- search errors + err=MathMax(err,MathAbs(v)); + } + } +//--- Testing Clenshaw summation + maxn=20; + ArrayResize(c,maxn+1); + for(pass=1;pass<=10;pass++) + { + //--- change values + x=2*CMath::RandomReal()-1; + v=0; + for(n=0;n<=maxn;n++) + { + c[n]=2*CMath::RandomReal()-1; + v=v+CLegendre::LegendreCalculate(n,x)*c[n]; + //--- search errors + sumerr=MathMax(sumerr,MathAbs(v-CLegendre::LegendreSum(c,n,x))); + } + } +//--- Testing coefficients + CLegendre::LegendreCoefficients(0,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-1)); +//--- calculation + CLegendre::LegendreCoefficients(1,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-0)); + cerr=MathMax(cerr,MathAbs(c[1]-1)); +//--- calculation + CLegendre::LegendreCoefficients(2,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]+1.0/2.0)); + cerr=MathMax(cerr,MathAbs(c[1]-0)); + cerr=MathMax(cerr,MathAbs(c[2]-3.0/2.0)); +//--- calculation + CLegendre::LegendreCoefficients(3,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-0)); + cerr=MathMax(cerr,MathAbs(c[1]+3.0/2.0)); + cerr=MathMax(cerr,MathAbs(c[2]-0)); + cerr=MathMax(cerr,MathAbs(c[3]-5.0/2.0)); +//--- calculation + CLegendre::LegendreCoefficients(4,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-3.0/8.0)); + cerr=MathMax(cerr,MathAbs(c[1]-0)); + cerr=MathMax(cerr,MathAbs(c[2]+30.0/8.0)); + cerr=MathMax(cerr,MathAbs(c[3]-0)); + cerr=MathMax(cerr,MathAbs(c[4]-35.0/8.0)); +//--- calculation + CLegendre::LegendreCoefficients(9,c); +//--- search errors + cerr=MathMax(cerr,MathAbs(c[0]-0)); + cerr=MathMax(cerr,MathAbs(c[1]-315.0/128.0)); + cerr=MathMax(cerr,MathAbs(c[2]-0)); + cerr=MathMax(cerr,MathAbs(c[3]+4620.0/128.0)); + cerr=MathMax(cerr,MathAbs(c[4]-0)); + cerr=MathMax(cerr,MathAbs(c[5]-18018.0/128.0)); + cerr=MathMax(cerr,MathAbs(c[6]-0)); + cerr=MathMax(cerr,MathAbs(c[7]+25740.0/128.0)); + cerr=MathMax(cerr,MathAbs(c[8]-0)); + cerr=MathMax(cerr,MathAbs(c[9]-12155.0/128.0)); +//--- Reporting + waserrors=(err>threshold || sumerr>threshold) || cerr>threshold; +//--- check + if(!silent) + { + Print("TESTING CALCULATION OF THE LEGENDRE POLYNOMIALS"); + Print("Max error "); + Print("{0,5:E2}",err); + Print("Summation error "); + Print("{0,5:E2}",sumerr); + Print("Coefficients error "); + Print("{0,5:E2}",cerr); + Print("Threshold "); + Print("{0,5:E2}",threshold); + //--- check + if(!waserrors) + Print("TEST PASSED"); + else + Print("TEST FAILED"); + } +//--- return result + return(!waserrors); + } +//+------------------------------------------------------------------+ +//| The auxiliary class | +//+------------------------------------------------------------------+ +class CRec1 + { +public: + //--- class variables + bool m_bfield; + double m_rfield; + int m_ifield; + complex m_cfield; + //--- arrays + bool m_b1field[]; + double m_r1field[]; + int m_i1field[]; + complex m_c1field[]; + //--- matrix + CMatrixInt m_b2field; + CMatrixDouble m_r2field; + CMatrixInt m_i2field; + CMatrixComplex m_c2field; + //--- constructor, destructor + CRec1(void); + ~CRec1(void); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CRec1::CRec1(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CRec1::~CRec1(void) + { + + } +//+------------------------------------------------------------------+ +//| The auxiliary class | +//+------------------------------------------------------------------+ +class CRec4Serialization + { +public: + //--- arrays + bool m_b[]; + int m_i[]; + double m_r[]; + //--- constructor, destructor + CRec4Serialization(void); + ~CRec4Serialization(void); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CRec4Serialization::CRec4Serialization(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CRec4Serialization::~CRec4Serialization(void) + { + + } +//+------------------------------------------------------------------+ +//| Testing the basic functions | +//+------------------------------------------------------------------+ +class CTestAlglibBasicsUnit + { +private: + //--- private methods + static bool TestComplexArithmetics(const bool silent); + static bool TestIEEESpecial(const bool silent); + static bool TestSwapFunctions(const bool silent); + static bool TestSerializationFunctions(const bool silent); +public: + //--- constructor, destructor + CTestAlglibBasicsUnit(void); + ~CTestAlglibBasicsUnit(void); + //--- public methods + static void Rec4SerializationAlloc(CSerializer &s,CRec4Serialization &v); + static void Rec4SerializationSerialize(CSerializer &s,CRec4Serialization &v); + static void Rec4SerializationUnserialize(CSerializer &s,CRec4Serialization &v); + static bool TestAlglibBasics(const bool silent); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CTestAlglibBasicsUnit::CTestAlglibBasicsUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CTestAlglibBasicsUnit::~CTestAlglibBasicsUnit(void) + { + + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestAlglibBasicsUnit::Rec4SerializationAlloc(CSerializer &s, + CRec4Serialization &v) + { +//--- create a variable + int i=0; +//--- boolean fields + s.Alloc_Entry(); + for(i=0;i<=CAp::Len(v.m_b)-1;i++) + s.Alloc_Entry(); +//--- integer fields + s.Alloc_Entry(); + for(i=0;i<=CAp::Len(v.m_i)-1;i++) + s.Alloc_Entry(); +//--- real fields + s.Alloc_Entry(); + for(i=0;i<=CAp::Len(v.m_r)-1;i++) + s.Alloc_Entry(); + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestAlglibBasicsUnit::Rec4SerializationSerialize(CSerializer &s, + CRec4Serialization &v) + { +//--- create a variable + int i=0; +//--- boolean fields + s.Serialize_Int(CAp::Len(v.m_b)); + for(i=0;i<=CAp::Len(v.m_b)-1;i++) + s.Serialize_Bool(v.m_b[i]); +//--- integer fields + s.Serialize_Int(CAp::Len(v.m_i)); + for(i=0;i<=CAp::Len(v.m_i)-1;i++) + s.Serialize_Int(v.m_i[i]); +//--- real fields + s.Serialize_Int(CAp::Len(v.m_r)); + for(i=0;i<=CAp::Len(v.m_r)-1;i++) + s.Serialize_Double(v.m_r[i]); + } +//+------------------------------------------------------------------+ +//| The auxiliary function | +//+------------------------------------------------------------------+ +static void CTestAlglibBasicsUnit::Rec4SerializationUnserialize(CSerializer &s, + CRec4Serialization &v) + { +//--- create variables + int i=0; + int k=0; + bool bv; + int iv=0; + double rv=0; +//--- boolean fields + k=s.Unserialize_Int(); +//--- check + if(k>0) + { + //--- allocation + ArrayResize(v.m_b,k); + for(i=0;i<=k-1;i++) + { + bv=s.Unserialize_Bool(); + v.m_b[i]=bv; + } + } +//--- integer fields + k=s.Unserialize_Int(); +//--- check + if(k>0) + { + //--- allocation + ArrayResize(v.m_i,k); + for(i=0;i<=k-1;i++) + { + iv=s.Unserialize_Int(); + v.m_i[i]=iv; + } + } +//--- real fields + k=s.Unserialize_Int(); +//--- check + if(k>0) + { + //--- allocation + ArrayResize(v.m_r,k); + for(i=0;i<=k-1;i++) + { + rv=s.Unserialize_Double(); + v.m_r[i]=rv; + } + } + } +//+------------------------------------------------------------------+ +//| Testing the basic functions | +//+------------------------------------------------------------------+ +static bool CTestAlglibBasicsUnit::TestAlglibBasics(const bool silent) + { +//--- create a variable + bool result; +//--- function calls + result=true; + result=result && TestComplexArithmetics(silent); + result=result && TestIEEESpecial(silent); + result=result && TestSwapFunctions(silent); + result=result && TestSerializationFunctions(silent); +//--- check + if(!silent) + Print(""); +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Complex arithmetics test | +//+------------------------------------------------------------------+ +static bool CTestAlglibBasicsUnit::TestComplexArithmetics(const bool silent) + { +//--- create variables + bool result; + bool absc; + bool addcc; + bool addcr; + bool addrc; + bool subcc; + bool subcr; + bool subrc; + bool mulcc; + bool mulcr; + bool mulrc; + bool divcc; + bool divcr; + bool divrc; + complex ca=0; + complex cb=0; + complex res=0; + double ra=0; + double rb=0; + double threshold=0; + int pass=0; + int passcount=0; +//--- initialization + threshold=100*CMath::m_machineepsilon; + passcount=1000; + result=true; + absc=true; + addcc=true; + addcr=true; + addrc=true; + subcc=true; + subcr=true; + subrc=true; + mulcc=true; + mulcr=true; + mulrc=true; + divcc=true; + divcr=true; + divrc=true; +//--- calculation + for(pass=1;pass<=passcount;pass++) + { + //--- Test AbsC + ca.re=2*CMath::RandomReal()-1; + ca.im=2*CMath::RandomReal()-1; + ra=CMath::AbsComplex(ca); + absc=absc && MathAbs(ra-MathSqrt(CMath::Sqr(ca.re)+CMath::Sqr(ca.im)))CInfOrNaN::PositiveInfinity()); + okinf=okinf && !(CInfOrNaN::PositiveInfinity()>v1); + okinf=okinf && CInfOrNaN::PositiveInfinity()>CInfOrNaN::NegativeInfinity(); + okinf=okinf && CInfOrNaN::PositiveInfinity()>v2; + okinf=okinf && CInfOrNaN::PositiveInfinity()>0.0; + okinf=okinf && CInfOrNaN::PositiveInfinity()>1.2; + okinf=okinf && CInfOrNaN::PositiveInfinity()>-1.2; + okinf=okinf && !(v1>CInfOrNaN::PositiveInfinity()); + okinf=okinf && !(CInfOrNaN::NegativeInfinity()>CInfOrNaN::PositiveInfinity()); + okinf=okinf && !(v2>CInfOrNaN::PositiveInfinity()); + okinf=okinf && !(0.0>CInfOrNaN::PositiveInfinity()); + okinf=okinf && !(1.2>CInfOrNaN::PositiveInfinity()); + okinf=okinf && !(-1.2>CInfOrNaN::PositiveInfinity()); + okinf=okinf && CInfOrNaN::PositiveInfinity()>=CInfOrNaN::PositiveInfinity(); + okinf=okinf && CInfOrNaN::PositiveInfinity()>=v1; + okinf=okinf && CInfOrNaN::PositiveInfinity()>=CInfOrNaN::NegativeInfinity(); + okinf=okinf && CInfOrNaN::PositiveInfinity()>=v2; + okinf=okinf && CInfOrNaN::PositiveInfinity()>=0.0; + okinf=okinf && CInfOrNaN::PositiveInfinity()>=1.2; + okinf=okinf && CInfOrNaN::PositiveInfinity()>=-1.2; + okinf=okinf && v1>=CInfOrNaN::PositiveInfinity(); + okinf=okinf && !(CInfOrNaN::NegativeInfinity()>=CInfOrNaN::PositiveInfinity()); + okinf=okinf && !(v2>=CInfOrNaN::PositiveInfinity()); + okinf=okinf && !(0.0>=CInfOrNaN::PositiveInfinity()); + okinf=okinf && !(1.2>=CInfOrNaN::PositiveInfinity()); + okinf=okinf && !(-1.2>=CInfOrNaN::PositiveInfinity()); + okinf=okinf && !(CInfOrNaN::NegativeInfinity()==CInfOrNaN::PositiveInfinity()); + okinf=okinf && !(CInfOrNaN::NegativeInfinity()==v1); + okinf=okinf && CInfOrNaN::NegativeInfinity()==CInfOrNaN::NegativeInfinity(); + okinf=okinf && CInfOrNaN::NegativeInfinity()==v2; + okinf=okinf && !(CInfOrNaN::NegativeInfinity()==0.0); + okinf=okinf && !(CInfOrNaN::NegativeInfinity()==1.2); + okinf=okinf && !(CInfOrNaN::NegativeInfinity()==-1.2); + okinf=okinf && !(v1==CInfOrNaN::NegativeInfinity()); + okinf=okinf && CInfOrNaN::NegativeInfinity()==CInfOrNaN::NegativeInfinity(); + okinf=okinf && v2==CInfOrNaN::NegativeInfinity(); + okinf=okinf && !(0.0==CInfOrNaN::NegativeInfinity()); + okinf=okinf && !(1.2==CInfOrNaN::NegativeInfinity()); + okinf=okinf && !(-1.2==CInfOrNaN::NegativeInfinity()); + okinf=okinf && CInfOrNaN::NegativeInfinity()!=CInfOrNaN::PositiveInfinity(); + okinf=okinf && CInfOrNaN::NegativeInfinity()!=v1; + okinf=okinf && !(CInfOrNaN::NegativeInfinity()!=CInfOrNaN::NegativeInfinity()); + okinf=okinf && !(CInfOrNaN::NegativeInfinity()!=v2); + okinf=okinf && CInfOrNaN::NegativeInfinity()!=0.0; + okinf=okinf && CInfOrNaN::NegativeInfinity()!=1.2; + okinf=okinf && CInfOrNaN::NegativeInfinity()!=-1.2; + okinf=okinf && v1!=CInfOrNaN::NegativeInfinity(); + okinf=okinf && !(CInfOrNaN::NegativeInfinity()!=CInfOrNaN::NegativeInfinity()); + okinf=okinf && !(v2!=CInfOrNaN::NegativeInfinity()); + okinf=okinf && 0.0!=CInfOrNaN::NegativeInfinity(); + okinf=okinf && 1.2!=CInfOrNaN::NegativeInfinity(); + okinf=okinf && -1.2!=CInfOrNaN::NegativeInfinity(); + okinf=okinf && CInfOrNaN::NegativeInfinity()CInfOrNaN::PositiveInfinity()); + okinf=okinf && !(CInfOrNaN::NegativeInfinity()>v1); + okinf=okinf && !(CInfOrNaN::NegativeInfinity()>CInfOrNaN::NegativeInfinity()); + okinf=okinf && !(CInfOrNaN::NegativeInfinity()>v2); + okinf=okinf && !(CInfOrNaN::NegativeInfinity()>0.0); + okinf=okinf && !(CInfOrNaN::NegativeInfinity()>1.2); + okinf=okinf && !(CInfOrNaN::NegativeInfinity()>-1.2); + okinf=okinf && v1>CInfOrNaN::NegativeInfinity(); + okinf=okinf && !(CInfOrNaN::NegativeInfinity()>CInfOrNaN::NegativeInfinity()); + okinf=okinf && !(v2>CInfOrNaN::NegativeInfinity()); + okinf=okinf && 0.0>CInfOrNaN::NegativeInfinity(); + okinf=okinf && 1.2>CInfOrNaN::NegativeInfinity(); + okinf=okinf && -1.2>CInfOrNaN::NegativeInfinity(); + okinf=okinf && !(CInfOrNaN::NegativeInfinity()>=CInfOrNaN::PositiveInfinity()); + okinf=okinf && !(CInfOrNaN::NegativeInfinity()>=v1); + okinf=okinf && CInfOrNaN::NegativeInfinity()>=CInfOrNaN::NegativeInfinity(); + okinf=okinf && CInfOrNaN::NegativeInfinity()>=v2; + okinf=okinf && !(CInfOrNaN::NegativeInfinity()>=0.0); + okinf=okinf && !(CInfOrNaN::NegativeInfinity()>=1.2); + okinf=okinf && !(CInfOrNaN::NegativeInfinity()>=-1.2); + okinf=okinf && v1>=CInfOrNaN::NegativeInfinity(); + okinf=okinf && CInfOrNaN::NegativeInfinity()>=CInfOrNaN::NegativeInfinity(); + okinf=okinf && v2>=CInfOrNaN::NegativeInfinity(); + okinf=okinf && 0.0>=CInfOrNaN::NegativeInfinity(); + okinf=okinf && 1.2>=CInfOrNaN::NegativeInfinity(); + okinf=okinf && -1.2>=CInfOrNaN::NegativeInfinity(); +//--- summary + result=result && oknan; + result=result && okinf; + result=result && okother; +//--- check + if(!silent) + { + //--- check + if(result) + Print("IEEE SPECIAL VALUES: OK"); + else + { + Print("IEEE SPECIAL VALUES: FAILED"); + Print("* NAN "); + //--- check + if(oknan) + Print("OK"); + else + Print("FAILED"); + Print("* INF "); + //--- check + if(okinf) + Print("OK"); + else + Print("FAILED"); + Print("* FUNCTIONS "); + //--- check + if(okother) + Print("OK"); + else + Print("FAILED"); + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Tests for swapping functions | +//+------------------------------------------------------------------+ +static bool CTestAlglibBasicsUnit::TestSwapFunctions(const bool silent) + { +//--- create variables + bool result; + bool okb1; + bool okb2; + bool oki1; + bool oki2; + bool okr1; + bool okr2; + bool okc1; + bool okc2; +//--- create arrays + bool b11[]; + bool b12[]; + int i11[]; + int i12[]; + double r11[]; + double r12[]; + complex c11[]; + complex c12[]; +//--- create matrix + CMatrixInt b21; + CMatrixInt b22; + CMatrixInt i21; + CMatrixInt i22; + CMatrixDouble r21; + CMatrixDouble r22; + CMatrixComplex c21; + CMatrixComplex c22; +//--- initialization + result=true; + okb1=true; + okb2=true; + oki1=true; + oki2=true; + okr1=true; + okr2=true; + okc1=true; + okc2=true; +//--- Test B1 swaps + ArrayResize(b11,1); + ArrayResize(b12,2); +//--- change values + b11[0]=true; + b12[0]=false; + b12[1]=true; +//--- function call + CAp::Swap(b11,b12); +//--- check + if(CAp::Len(b11)==2 && CAp::Len(b12)==1) + { + okb1=okb1 && !b11[0]; + okb1=okb1 && b11[1]; + okb1=okb1 && b12[0]; + } + else + okb1=false; +//--- Test I1 swaps + ArrayResize(i11,1); + ArrayResize(i12,2); +//--- change values + i11[0]=1; + i12[0]=2; + i12[1]=3; +//--- function call + CAp::Swap(i11,i12); +//--- check + if(CAp::Len(i11)==2 && CAp::Len(i12)==1) + { + oki1=oki1 && i11[0]==2; + oki1=oki1 && i11[1]==3; + oki1=oki1 && i12[0]==1; + } + else + oki1=false; +//--- Test R1 swaps + ArrayResize(r11,1); + ArrayResize(r12,2); +//--- change values + r11[0]=1.5; + r12[0]=2.5; + r12[1]=3.5; +//--- function call + CAp::Swap(r11,r12); +//--- check + if(CAp::Len(r11)==2 && CAp::Len(r12)==1) + { + okr1=okr1 && r11[0]==2.5; + okr1=okr1 && r11[1]==3.5; + okr1=okr1 && r12[0]==1.5; + } + else + okr1=false; +//--- Test C1 swaps + ArrayResize(c11,1); + ArrayResize(c12,2); +//--- change values + c11[0]=1; + c12[0]=2; + c12[1]=3; +//--- function call + CAp::Swap(c11,c12); +//--- check + if(CAp::Len(c11)==2 && CAp::Len(c12)==1) + { + okc1=okc1 && c11[0]==2; + okc1=okc1 && c11[1]==3; + okc1=okc1 && c12[0]==1; + } + else + okc1=false; +//--- Test B2 swaps + b21.Resize(1,2); + b22.Resize(2,1); +//--- change values + b21[0].Set(0,true); + b21[0].Set(1,false); + b22[0].Set(0,false); + b22[1].Set(0,true); +//--- function call + CAp::Swap(b21,b22); +//--- check + if(((CAp::Rows(b21)==2 && CAp::Cols(b21)==1) && CAp::Rows(b22)==1) && CAp::Cols(b22)==2) + { + okb2=okb2 && !b21[0][0]; + okb2=okb2 && b21[1][0]; + okb2=okb2 && b22[0][0]; + okb2=okb2 && !b22[0][1]; + } + else + okb2=false; +//--- Test I2 swaps + i21.Resize(1,2); + i22.Resize(2,1); +//--- change values + i21[0].Set(0,1); + i21[0].Set(1,2); + i22[0].Set(0,3); + i22[1].Set(0,4); +//--- function call + CAp::Swap(i21,i22); +//--- check + if(((CAp::Rows(i21)==2 && CAp::Cols(i21)==1) && CAp::Rows(i22)==1) && CAp::Cols(i22)==2) + { + oki2=oki2 && i21[0][0]==3; + oki2=oki2 && i21[1][0]==4; + oki2=oki2 && i22[0][0]==1; + oki2=oki2 && i22[0][1]==2; + } + else + oki2=false; +//--- Test R2 swaps + r21.Resize(1,2); + r22.Resize(2,1); +//--- change values + r21[0].Set(0,1); + r21[0].Set(1,2); + r22[0].Set(0,3); + r22[1].Set(0,4); +//--- function call + CAp::Swap(r21,r22); +//--- check + if(((CAp::Rows(r21)==2 && CAp::Cols(r21)==1) && CAp::Rows(r22)==1) && CAp::Cols(r22)==2) + { + okr2=okr2 && r21[0][0]==3.0; + okr2=okr2 && r21[1][0]==4.0; + okr2=okr2 && r22[0][0]==1.0; + okr2=okr2 && r22[0][1]==2.0; + } + else + okr2=false; +//--- Test C2 swaps + c21.Resize(1,2); + c22.Resize(2,1); +//--- change values + c21[0].Set(0,1); + c21[0].Set(1,2); + c22[0].Set(0,3); + c22[1].Set(0,4); +//--- function call + CAp::Swap(c21,c22); +//--- check + if(((CAp::Rows(c21)==2 && CAp::Cols(c21)==1) && CAp::Rows(c22)==1) && CAp::Cols(c22)==2) + { + okc2=okc2 && c21[0][0]==3; + okc2=okc2 && c21[1][0]==4; + okc2=okc2 && c22[0][0]==1; + okc2=okc2 && c22[0][1]==2; + } + else + okc2=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; +//--- check + if(!silent) + { + //--- check + if(result) + Print("SWAPPING FUNCTIONS: OK"); + else + Print("SWAPPING FUNCTIONS: FAILED"); + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ +//| Tests for swapping functions | +//+------------------------------------------------------------------+ +static bool CTestAlglibBasicsUnit::TestSerializationFunctions(const bool silent) + { +//--- create variables + bool result; + bool okb; + bool oki; + bool okr; + int nb=0; + int ni=0; + int nr=0; + int i=0; +//--- objects of classes + CRec4Serialization r0; + CRec4Serialization r1; +//--- initialization + result=true; + okb=true; + oki=true; + okr=true; +//--- calculation + for(nb=1;nb<=4;nb++) + { + for(ni=1;ni<=4;ni++) + { + for(nr=1;nr<=4;nr++) + { + //--- allocation + ArrayResize(r0.m_b,nb); + for(i=0;i<=nb-1;i++) + r0.m_b[i]=CMath::RandomInteger(2)!=0; + //--- allocation + ArrayResize(r0.m_i,ni); + for(i=0;i<=ni-1;i++) + r0.m_i[i]=CMath::RandomInteger(10)-5; + //--- allocation + ArrayResize(r0.m_r,nr); + for(i=0;i<=nr-1;i++) + r0.m_r[i]=2*CMath::RandomReal()-1; + { + //--- This code passes data structure through serializers + //--- (serializes it to string and loads back) + CSerializer _local_serializer; + string _local_str; + //--- serialization + _local_serializer.Reset(); + _local_serializer.Alloc_Start(); + CTestAlglibBasicsUnit::Rec4SerializationAlloc(_local_serializer,r0); + _local_serializer.SStart_Str(); + CTestAlglibBasicsUnit::Rec4SerializationSerialize(_local_serializer,r0); + _local_serializer.Stop(); + _local_str=_local_serializer.Get_String(); + //--- unserialization + _local_serializer.Reset(); + _local_serializer.UStart_Str(_local_str); + CTestAlglibBasicsUnit::Rec4SerializationUnserialize(_local_serializer,r1); + _local_serializer.Stop(); + } + //--- check + if((CAp::Len(r0.m_b)==CAp::Len(r1.m_b) && CAp::Len(r0.m_i)==CAp::Len(r1.m_i)) && CAp::Len(r0.m_r)==CAp::Len(r1.m_r)) + { + //--- change value + for(i=0;i<=nb-1;i++) + okb=okb && ((r0.m_b[i] && r1.m_b[i]) || (!r0.m_b[i] && !r1.m_b[i])); + for(i=0;i<=ni-1;i++) + oki=oki && r0.m_i[i]==r1.m_i[i]; + for(i=0;i<=nr-1;i++) + okr=okr && r0.m_r[i]==r1.m_r[i]; + } + else + oki=false; + } + } + } +//--- summary + result=result && okb; + result=result && oki; + result=result && okr; +//--- check + if(!silent) + { + //--- check + if(result) + Print("SERIALIZATION FUNCTIONS: OK"); + else + { + Print("SERIALIZATION FUNCTIONS: FAILED"); + Print("* BOOLEAN "); + //--- check + if(okb) + Print("OK"); + else + Print("FAILED"); + Print("* INTEGER "); + //--- check + if(oki) + Print("OK"); + else + Print("FAILED"); + Print("* REAL "); + //--- check + if(okr) + Print("OK"); + else + Print("FAILED"); + } + } +//--- return result + return(result); + } +//+------------------------------------------------------------------+ diff --git a/Scripts/UnitTests/Alglib/TestInterfaces.mq5 b/Scripts/UnitTests/Alglib/TestInterfaces.mq5 new file mode 100644 index 0000000..4b477ef --- /dev/null +++ b/Scripts/UnitTests/Alglib/TestInterfaces.mq5 @@ -0,0 +1,148 @@ +//+------------------------------------------------------------------+ +//| TestInterfaces.mq5 | +//| Copyright 2003-2012 Sergey Bochkanov (ALGLIB project) | +//| Copyright 2012-2017, MetaQuotes Software Corp. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +//| Implementation of ALGLIB library in MetaQuotes Language 5 | +//| | +//| The features of the library include: | +//| - Linear algebra (direct algorithms, EVD, SVD) | +//| - Solving systems of linear and non-linear equations | +//| - Interpolation | +//| - Optimization | +//| - FFT (Fast Fourier Transform) | +//| - Numerical integration | +//| - Linear and nonlinear least-squares fitting | +//| - Ordinary differential equations | +//| - Computation of special functions | +//| - Descriptive statistics and hypothesis testing | +//| - Data analysis - classification, regression | +//| - Implementing linear algebra algorithms, interpolation, etc. | +//| in high-precision arithmetic (using MPFR) | +//| | +//| This program is free software; 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. | +//+------------------------------------------------------------------+ +#include "TestInterfaces.mqh" + +//+------------------------------------------------------------------+ +//| Testing script | +//+------------------------------------------------------------------+ +void OnStart() + { +//--- total result + bool _TotalResult=true; +//--- temp result + bool _TestResult; +//--- spoil scenario + int _spoil_scenario; + Print("MQL5 interface tests. Please wait..."); + Print("0/91"); +//--- testing + TEST_NNeighbor_D_1(_spoil_scenario,_TestResult,_TotalResult); + TEST_NNeighbor_T_2(_spoil_scenario,_TestResult,_TotalResult); + TEST_NNeighbor_D_2(_spoil_scenario,_TestResult,_TotalResult); + TEST_BaseStat_D_Base(_spoil_scenario,_TestResult,_TotalResult); + TEST_BaseStat_D_C2(_spoil_scenario,_TestResult,_TotalResult); + TEST_BaseStat_D_CM(_spoil_scenario,_TestResult,_TotalResult); + TEST_BaseStat_D_CM2(_spoil_scenario,_TestResult,_TotalResult); + TEST_BaseStat_T_Base(_spoil_scenario,_TestResult,_TotalResult); + TEST_BaseStat_T_CovCorr(_spoil_scenario,_TestResult,_TotalResult); + TEST_MatInv_D_R1(_spoil_scenario,_TestResult,_TotalResult); + TEST_MatInv_D_C1(_spoil_scenario,_TestResult,_TotalResult); + TEST_MatInv_D_SPD1(_spoil_scenario,_TestResult,_TotalResult); + TEST_MatInv_D_HPD1(_spoil_scenario,_TestResult,_TotalResult); + TEST_MatInv_T_R1(_spoil_scenario,_TestResult,_TotalResult); + TEST_MatInv_T_C1(_spoil_scenario,_TestResult,_TotalResult); + TEST_MatInv_E_SPD1(_spoil_scenario,_TestResult,_TotalResult); + TEST_MatInv_E_HPD1(_spoil_scenario,_TestResult,_TotalResult); + TEST_MinCG_D_1(_spoil_scenario,_TestResult,_TotalResult); + TEST_MinCG_D_2(_spoil_scenario,_TestResult,_TotalResult); + TEST_MinCG_NumDiff(_spoil_scenario,_TestResult,_TotalResult); + TEST_MinCG_FTRIM(_spoil_scenario,_TestResult,_TotalResult); + TEST_MinBLEIC_D_1(_spoil_scenario,_TestResult,_TotalResult); + TEST_MinBLEIC_D_2(_spoil_scenario,_TestResult,_TotalResult); + TEST_MinBLEIC_NumDiff(_spoil_scenario,_TestResult,_TotalResult); + TEST_MinBLEIC_FTRIM(_spoil_scenario,_TestResult,_TotalResult); + TEST_MCPD_Simple1(_spoil_scenario,_TestResult,_TotalResult); + TEST_MCPD_Simple2(_spoil_scenario,_TestResult,_TotalResult); + TEST_MinLBFGS_D_1(_spoil_scenario,_TestResult,_TotalResult); + TEST_MinLBFGS_D_2(_spoil_scenario,_TestResult,_TotalResult); + TEST_MinLBFGS_NumDiff(_spoil_scenario,_TestResult,_TotalResult); + TEST_MinLBFGS_FTRIM(_spoil_scenario,_TestResult,_TotalResult); + TEST_ODESolver_D1(_spoil_scenario,_TestResult,_TotalResult); + TEST_FFT_Complex_D1(_spoil_scenario,_TestResult,_TotalResult); + TEST_FFT_Complex_D2(_spoil_scenario,_TestResult,_TotalResult); + TEST_FFT_Real_D1(_spoil_scenario,_TestResult,_TotalResult); + TEST_FFT_Real_D2(_spoil_scenario,_TestResult,_TotalResult); + TEST_FFT_Complex_E1(_spoil_scenario,_TestResult,_TotalResult); + TEST_AutoGK_D1(_spoil_scenario,_TestResult,_TotalResult); + TEST_PolInt_D_CalcDiff(_spoil_scenario,_TestResult,_TotalResult); + TEST_PolInt_D_Conv(_spoil_scenario,_TestResult,_TotalResult); + TEST_PolInt_D_Spec(_spoil_scenario,_TestResult,_TotalResult); + TEST_PolInt_T_1(_spoil_scenario,_TestResult,_TotalResult); + TEST_PolInt_T_2(_spoil_scenario,_TestResult,_TotalResult); + TEST_PolInt_T_3(_spoil_scenario,_TestResult,_TotalResult); + TEST_PolInt_T_4(_spoil_scenario,_TestResult,_TotalResult); + TEST_PolInt_T_5(_spoil_scenario,_TestResult,_TotalResult); + TEST_PolInt_T_6(_spoil_scenario,_TestResult,_TotalResult); + TEST_PolInt_T_7(_spoil_scenario,_TestResult,_TotalResult); + TEST_PolInt_T_8(_spoil_scenario,_TestResult,_TotalResult); + TEST_PolInt_T_9(_spoil_scenario,_TestResult,_TotalResult); + //--- 50 blocks were successful + Print("50/91"); + TEST_PolInt_T_10(_spoil_scenario,_TestResult,_TotalResult); + TEST_PolInt_T_11(_spoil_scenario,_TestResult,_TotalResult); + TEST_PolInt_T_12(_spoil_scenario,_TestResult,_TotalResult); + TEST_PolInt_T_13(_spoil_scenario,_TestResult,_TotalResult); + TEST_Spline1D_D_Linear(_spoil_scenario,_TestResult,_TotalResult); + TEST_Spline1D_D_Cubic(_spoil_scenario,_TestResult,_TotalResult); + TEST_Spline1D_D_GridDiff(_spoil_scenario,_TestResult,_TotalResult); + TEST_Spline1D_D_ConvDiff(_spoil_scenario,_TestResult,_TotalResult); + TEST_MinQP_D_U1(_spoil_scenario,_TestResult,_TotalResult); + TEST_MinQP_D_BC1(_spoil_scenario,_TestResult,_TotalResult); + TEST_MinLM_D_V(_spoil_scenario,_TestResult,_TotalResult); + TEST_MinLM_D_VJ(_spoil_scenario,_TestResult,_TotalResult); + TEST_MinLM_D_FGH(_spoil_scenario,_TestResult,_TotalResult); + TEST_MinLM_D_VB(_spoil_scenario,_TestResult,_TotalResult); + TEST_MinLM_D_Restarts(_spoil_scenario,_TestResult,_TotalResult); + TEST_MinLM_T_1(_spoil_scenario,_TestResult,_TotalResult); + TEST_MinLM_T_2(_spoil_scenario,_TestResult,_TotalResult); + TEST_LSFit_D_NLF(_spoil_scenario,_TestResult,_TotalResult); + TEST_LSFit_D_NLFG(_spoil_scenario,_TestResult,_TotalResult); + TEST_LSFit_D_NLFGH(_spoil_scenario,_TestResult,_TotalResult); + TEST_LSFit_D_NLFB(_spoil_scenario,_TestResult,_TotalResult); + TEST_LSFit_D_NLScale(_spoil_scenario,_TestResult,_TotalResult); + TEST_LSFit_D_Lin(_spoil_scenario,_TestResult,_TotalResult); + TEST_LSFit_D_Linc(_spoil_scenario,_TestResult,_TotalResult); + TEST_LSFit_D_Pol(_spoil_scenario,_TestResult,_TotalResult); + TEST_LSFit_D_Polc(_spoil_scenario,_TestResult,_TotalResult); + TEST_LSFit_D_Spline(_spoil_scenario,_TestResult,_TotalResult); + TEST_LSFit_T_PolFit_1(_spoil_scenario,_TestResult,_TotalResult); + TEST_LSFit_T_PolFit_2(_spoil_scenario,_TestResult,_TotalResult); + TEST_LSFit_T_PolFit_3(_spoil_scenario,_TestResult,_TotalResult); + TEST_MatDet_D_1(_spoil_scenario,_TestResult,_TotalResult); + TEST_MatDet_D_2(_spoil_scenario,_TestResult,_TotalResult); + TEST_MatDet_D_3(_spoil_scenario,_TestResult,_TotalResult); + TEST_MatDet_D_4(_spoil_scenario,_TestResult,_TotalResult); + TEST_MatDet_D_5(_spoil_scenario,_TestResult,_TotalResult); + TEST_MatDet_T_0(_spoil_scenario,_TestResult,_TotalResult); + TEST_MatDet_T_1(_spoil_scenario,_TestResult,_TotalResult); + TEST_MatDet_T_2(_spoil_scenario,_TestResult,_TotalResult); + TEST_MatDet_T_3(_spoil_scenario,_TestResult,_TotalResult); + TEST_MatDet_T_4(_spoil_scenario,_TestResult,_TotalResult); + TEST_MatDet_T_5(_spoil_scenario,_TestResult,_TotalResult); + //--- all blocks were successful + Print("91/91"); + //--- print total result + Print("Result = ",_TotalResult); + } +//+------------------------------------------------------------------+ diff --git a/Scripts/UnitTests/Alglib/TestInterfaces.mqh b/Scripts/UnitTests/Alglib/TestInterfaces.mqh new file mode 100644 index 0000000..6419177 --- /dev/null +++ b/Scripts/UnitTests/Alglib/TestInterfaces.mqh @@ -0,0 +1,11821 @@ +//+------------------------------------------------------------------+ +//| TestInterfaces.mqh | +//| Copyright 2003-2012 Sergey Bochkanov (ALGLIB project) | +//| Copyright 2012-2017, MetaQuotes Software Corp. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +//| Implementation of ALGLIB library in MetaQuotes Language 5 | +//| | +//| The features of the library include: | +//| - Linear algebra (direct algorithms, EVD, SVD) | +//| - Solving systems of linear and non-linear equations | +//| - Interpolation | +//| - Optimization | +//| - FFT (Fast Fourier Transform) | +//| - Numerical integration | +//| - Linear and nonlinear least-squares fitting | +//| - Ordinary differential equations | +//| - Computation of special functions | +//| - Descriptive statistics and hypothesis testing | +//| - Data analysis - classification, regression | +//| - Implementing linear algebra algorithms, interpolation, etc. | +//| in high-precision arithmetic (using MPFR) | +//| | +//| This file is free software; 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. | +//+------------------------------------------------------------------+ +#include + +//+------------------------------------------------------------------+ +//| Derived class from CNDimensional_Func | +//+------------------------------------------------------------------+ +class CNDimensional_Func1 : public CNDimensional_Func + { +public: + CNDimensional_Func1(void); + ~CNDimensional_Func1(void); + + virtual void Func(double &x[],double &func,CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CNDimensional_Func1::CNDimensional_Func1(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CNDimensional_Func1::~CNDimensional_Func1(void) + { + + } +//+------------------------------------------------------------------+ +//| This callback calculates f(x0,x1)=100*(x0+3)^4 + (x1-3)^4 | +//+------------------------------------------------------------------+ +void CNDimensional_Func1::Func(double &x[],double &func,CObject &obj) + { + func=100*MathPow(x[0]+3,4)+MathPow(x[1]-3,4); + } +//+------------------------------------------------------------------+ +//| Derived class from CNDimensional_Func | +//+------------------------------------------------------------------+ +class CNDimensional_Func2 : public CNDimensional_Func + { +public: + //--- constructor, destructor + CNDimensional_Func2(void); + ~CNDimensional_Func2(void); + //--- method + virtual void Func(double &x[],double &func,CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CNDimensional_Func2::CNDimensional_Func2(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CNDimensional_Func2::~CNDimensional_Func2(void) + { + + } +//+------------------------------------------------------------------+ +//| This callback calculates f(x0,x1)=(x0^2+1)^2 + (x1-1)^2 | +//+------------------------------------------------------------------+ +void CNDimensional_Func2::Func(double &x[],double &func,CObject &obj) + { + func=MathPow(x[0]*x[0]+1,2)+MathPow(x[1]-1,2); + } +//+------------------------------------------------------------------+ +//| Derived class from CNDimensional_Func | +//+------------------------------------------------------------------+ +class CNDimensional_Bad_Func : public CNDimensional_Func + { +public: + //--- constructor, destructor + CNDimensional_Bad_Func(void); + ~CNDimensional_Bad_Func(void); + //--- method + virtual void Func(double &x[],double &func,CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CNDimensional_Bad_Func::CNDimensional_Bad_Func(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CNDimensional_Bad_Func::~CNDimensional_Bad_Func(void) + { + + } +//+------------------------------------------------------------------+ +//| This callback calculates 'bad' function, i.e. function with | +//| incorrectly calculated derivatives | +//+------------------------------------------------------------------+ +void CNDimensional_Bad_Func::Func(double &x[],double &func,CObject &obj) + { + func=100*MathPow(x[0]+3,4)+MathPow(x[1]-3,4); + } +//+------------------------------------------------------------------+ +//| Derived class from CNDimensional_Grad | +//+------------------------------------------------------------------+ +class CNDimensional_Grad1 : public CNDimensional_Grad + { +public: + //--- constructor, destructor + CNDimensional_Grad1(void); + ~CNDimensional_Grad1(void); + //--- method + virtual void Grad(double &x[],double &func,double &grad[],CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CNDimensional_Grad1::CNDimensional_Grad1(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CNDimensional_Grad1::~CNDimensional_Grad1(void) + { + + } +//+------------------------------------------------------------------+ +//| This callback calculates f(x0,x1)=100*(x0+3)^4 + (x1-3)^4 and its| +//| derivatives df/d0 and df/dx1 | +//+------------------------------------------------------------------+ +void CNDimensional_Grad1::Grad(double &x[],double &func, + double &grad[],CObject &obj) + { + func=100*MathPow(x[0]+3,4)+MathPow(x[1]-3,4); + grad[0]=400*MathPow(x[0]+3,3); + grad[1]=4*MathPow(x[1]-3,3); + } +//+------------------------------------------------------------------+ +//| Derived class from CNDimensional_Grad | +//+------------------------------------------------------------------+ +class CNDimensional_Grad2 : public CNDimensional_Grad + { +public: + //--- constructor, destructor + CNDimensional_Grad2(void); + ~CNDimensional_Grad2(void); + //--- method + virtual void Grad(double &x[],double &func,double &grad[],CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CNDimensional_Grad2::CNDimensional_Grad2(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CNDimensional_Grad2::~CNDimensional_Grad2(void) + { + + } +//+------------------------------------------------------------------+ +//| This callback calculates f(x0,x1)=(x0^2+1)^2 + (x1-1)^2 and its | +//| derivatives df/d0 and df/dx1 | +//+------------------------------------------------------------------+ +void CNDimensional_Grad2::Grad(double &x[],double &func, + double &grad[],CObject &obj) + { + func=MathPow(x[0]*x[0]+1,2)+MathPow(x[1]-1,2); + grad[0]=4*(x[0]*x[0]+1)*x[0]; + grad[1]=2*(x[1]-1); + } +//+------------------------------------------------------------------+ +//| Derived class from CNDimensional_Grad | +//+------------------------------------------------------------------+ +class CNDimensional_Bad_Grad : public CNDimensional_Grad + { +public: + //--- constructor, destructor + CNDimensional_Bad_Grad(void); + ~CNDimensional_Bad_Grad(void); + //--- method + virtual void Grad(double &x[],double &func,double &grad[],CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CNDimensional_Bad_Grad::CNDimensional_Bad_Grad(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CNDimensional_Bad_Grad::~CNDimensional_Bad_Grad(void) + { + + } +//+------------------------------------------------------------------+ +//| This callback calculates 'bad' function, i.e. function with | +//| incorrectly calculated derivatives | +//+------------------------------------------------------------------+ +void CNDimensional_Bad_Grad::Grad(double &x[],double &func,double &grad[],CObject &obj) + { + func=100*MathPow(x[0]+3,4)+MathPow(x[1]-3,4); + grad[0]=40*MathPow(x[0]+3,3); + grad[1]=40*MathPow(x[1]-3,3); + } +//+------------------------------------------------------------------+ +//| Derived class from CNDimensional_Grad | +//+------------------------------------------------------------------+ +class CNDimensional_S1_Grad : public CNDimensional_Grad + { +public: + CNDimensional_S1_Grad(void); + ~CNDimensional_S1_Grad(void); + + virtual void Grad(double &x[],double &func,double &grad[],CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CNDimensional_S1_Grad::CNDimensional_S1_Grad(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CNDimensional_S1_Grad::~CNDimensional_S1_Grad(void) + { + + } +//+------------------------------------------------------------------+ +//| 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. | +//+------------------------------------------------------------------+ +void CNDimensional_S1_Grad::Grad(double &x[],double &func,double &grad[],CObject &obj) + { + if((x[0]<=-0.999999999999) || (x[0]>=+0.999999999999)) + { + func=1.0E+300; + return; + } + func=MathPow(1+x[0],-0.2)+MathPow(1-x[0],-0.3)+1000*x[0]; + grad[0]=-0.2*MathPow(1+x[0],-1.2)+0.3*MathPow(1-x[0],-1.3)+1000; + } +//+------------------------------------------------------------------+ +//| Derived class from CNDimensional_Hess | +//+------------------------------------------------------------------+ +class CNDimensional_Hess1 : public CNDimensional_Hess + { +public: + CNDimensional_Hess1(void); + ~CNDimensional_Hess1(void); + + virtual void Hess(double &x[],double &func,double &grad[],CMatrixDouble &hess,CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CNDimensional_Hess1::CNDimensional_Hess1(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CNDimensional_Hess1::~CNDimensional_Hess1(void) + { + + } +//+------------------------------------------------------------------+ +//| This callback calculates f(x0,x1)=100*(x0+3)^4 + (x1-3)^4 | +//| its derivatives df/d0 and df/dx1 | +//| and its Hessian. | +//+------------------------------------------------------------------+ +void CNDimensional_Hess1::Hess(double &x[],double &func,double &grad[], + CMatrixDouble &hess,CObject &obj) + { + func=100*MathPow(x[0]+3,4)+MathPow(x[1]-3,4); + grad[0]=400*MathPow(x[0]+3,3); + grad[1]=4*MathPow(x[1]-3,3); + hess[0].Set(0,1200*MathPow(x[0]+3,2)); + hess[0].Set(1,0); + hess[1].Set(0,0); + hess[1].Set(1,12*MathPow(x[1]-3,2)); + } +//+------------------------------------------------------------------+ +//| Derived class from CNDimensional_Hess | +//+------------------------------------------------------------------+ +class CNDimensional_Hess2 : public CNDimensional_Hess + { +public: + //--- constructor, destructor + CNDimensional_Hess2(void); + ~CNDimensional_Hess2(void); + //--- method + virtual void Hess(double &x[],double &func,double &grad[],CMatrixDouble &hess,CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CNDimensional_Hess2::CNDimensional_Hess2(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CNDimensional_Hess2::~CNDimensional_Hess2(void) + { + + } +//+------------------------------------------------------------------+ +//| This callback calculates f(x0,x1)=(x0^2+1)^2 + (x1-1)^2 | +//| its gradient and Hessian | +//+------------------------------------------------------------------+ +void CNDimensional_Hess2::Hess(double &x[],double &func,double &grad[], + CMatrixDouble &hess,CObject &obj) + { + func=MathPow(x[0]*x[0]+1,2)+MathPow(x[1]-1,2); + grad[0]=4*(x[0]*x[0]+1)*x[0]; + grad[1]=2*(x[1]-1); + hess[0].Set(0,12*x[0]*x[0]+4); + hess[0].Set(1,0); + hess[1].Set(0,0); + hess[1].Set(1,2); + } +//+------------------------------------------------------------------+ +//| Derived class from CNDimensional_Hess | +//+------------------------------------------------------------------+ +class CNDimensional_Bad_Hess : public CNDimensional_Hess + { +public: + //--- constructor, destructor + CNDimensional_Bad_Hess(void); + ~CNDimensional_Bad_Hess(void); + //--- method + virtual void Hess(double &x[],double &func,double &grad[],CMatrixDouble &hess,CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CNDimensional_Bad_Hess::CNDimensional_Bad_Hess(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CNDimensional_Bad_Hess::~CNDimensional_Bad_Hess(void) + { + + } +//+------------------------------------------------------------------+ +//| This callback calculates 'bad' function, i.e. function with | +//| incorrectly calculated derivatives | +//+------------------------------------------------------------------+ +void CNDimensional_Bad_Hess::Hess(double &x[],double &func,double &grad[], + CMatrixDouble &hess,CObject &obj) + { + func=100*MathPow(x[0]+3,4)+MathPow(x[1]-3,4); + grad[0]=40*MathPow(x[0]+3,3); + grad[1]=40*MathPow(x[1]-3,3); + hess[0].Set(0,120*MathPow(x[0]+3,2)); + hess[0].Set(1,1); + hess[1].Set(0,1); + hess[1].Set(1,120*MathPow(x[1]-3,2)); + } +//+------------------------------------------------------------------+ +//| Derived class from CNDimensional_FVec | +//+------------------------------------------------------------------+ +class CNDimensional_FVec1 : public CNDimensional_FVec + { +public: + //--- constructor, destructor + CNDimensional_FVec1(void); + ~CNDimensional_FVec1(void); + //--- method + virtual void FVec(double &x[],double &fi[],CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CNDimensional_FVec1::CNDimensional_FVec1(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CNDimensional_FVec1::~CNDimensional_FVec1(void) + { + + } +//+------------------------------------------------------------------+ +//| This callback calculates | +//| f0(x0,x1)=100*(x0+3)^4, | +//| f1(x0,x1)=(x1-3)^4 | +//+------------------------------------------------------------------+ +void CNDimensional_FVec1::FVec(double &x[],double &fi[],CObject &obj) + { + fi[0]=10*MathPow(x[0]+3,2); + fi[1]=MathPow(x[1]-3,2); + } +//+------------------------------------------------------------------+ +//| Derived class from CNDimensional_FVec | +//+------------------------------------------------------------------+ +class CNDimensional_FVec2 : public CNDimensional_FVec + { +public: + //--- constructor, destructor + CNDimensional_FVec2(void); + ~CNDimensional_FVec2(void); + //--- method + virtual void FVec(double &x[],double &fi[],CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CNDimensional_FVec2::CNDimensional_FVec2(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CNDimensional_FVec2::~CNDimensional_FVec2(void) + { + + } +//+------------------------------------------------------------------+ +//| This callback calculates | +//| f0(x0,x1)=100*(x0+3)^4, | +//| f1(x0,x1)=(x1-3)^4 | +//+------------------------------------------------------------------+ +void CNDimensional_FVec2::FVec(double &x[],double &fi[],CObject &obj) + { + fi[0]=x[0]*x[0]+1; + fi[1]=x[1]-1; + } +//+------------------------------------------------------------------+ +//| Derived class from CNDimensional_FVec | +//+------------------------------------------------------------------+ +class CNDimensional_Bad_FVec : public CNDimensional_FVec + { +public: + //--- constructor, destructor + CNDimensional_Bad_FVec(void); + ~CNDimensional_Bad_FVec(void); + //--- method + virtual void FVec(double &x[],double &fi[],CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CNDimensional_Bad_FVec::CNDimensional_Bad_FVec(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CNDimensional_Bad_FVec::~CNDimensional_Bad_FVec(void) + { + + } +//+------------------------------------------------------------------+ +//| This callback calculates 'bad' function, i.e. function with | +//| incorrectly calculated derivatives | +//+------------------------------------------------------------------+ +void CNDimensional_Bad_FVec::FVec(double &x[],double &fi[],CObject &obj) + { + fi[0]=10*MathPow(x[0]+3,2); + fi[1]=MathPow(x[1]-3,2); + } +//+------------------------------------------------------------------+ +//| Derived class from CNDimensional_Jac | +//+------------------------------------------------------------------+ +class CNDimensional_Jac1 : public CNDimensional_Jac + { +public: + //--- constructor, destructor + CNDimensional_Jac1(void); + ~CNDimensional_Jac1(void); + //--- method + virtual void Jac(double &x[],double &fi[],CMatrixDouble &jac,CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CNDimensional_Jac1::CNDimensional_Jac1(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CNDimensional_Jac1::~CNDimensional_Jac1(void) + { + + } +//+------------------------------------------------------------------+ +//| This callback calculates | +//| f0(x0,x1)=100*(x0+3)^4, | +//| f1(x0,x1)=(x1-3)^4 | +//| and Jacobian matrix J=[dfi/dxj] | +//+------------------------------------------------------------------+ +void CNDimensional_Jac1::Jac(double &x[],double &fi[],CMatrixDouble &jac, + CObject &obj) + { + fi[0]=10*MathPow(x[0]+3,2); + fi[1]=MathPow(x[1]-3,2); + jac[0].Set(0,20*(x[0]+3)); + jac[0].Set(1,0); + jac[1].Set(0,0); + jac[1].Set(1,2*(x[1]-3)); + } +//+------------------------------------------------------------------+ +//| Derived class from CNDimensional_Jac | +//+------------------------------------------------------------------+ +class CNDimensional_Jac2 : public CNDimensional_Jac + { +public: + //--- constructor, destructor + CNDimensional_Jac2(void); + ~CNDimensional_Jac2(void); + //--- method + virtual void Jac(double &x[],double &fi[],CMatrixDouble &jac,CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CNDimensional_Jac2::CNDimensional_Jac2(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CNDimensional_Jac2::~CNDimensional_Jac2(void) + { + + } +//+------------------------------------------------------------------+ +//| This callback calculates | +//| f0(x0,x1)=x0^2+1 | +//| f1(x0,x1)=x1-1 | +//| and Jacobian matrix J=[dfi/dxj] | +//+------------------------------------------------------------------+ +void CNDimensional_Jac2::Jac(double &x[],double &fi[],CMatrixDouble &jac, + CObject &obj) + { + fi[0]=x[0]*x[0]+1; + fi[1]=x[1]-1; + jac[0].Set(0,2*x[0]); + jac[0].Set(1,0); + jac[1].Set(0,0); + jac[1].Set(1,1); + } +//+------------------------------------------------------------------+ +//| Derived class from CNDimensional_Jac | +//+------------------------------------------------------------------+ +class CNDimensional_Bad_Jac : public CNDimensional_Jac + { +public: + //--- constructor, destructor + CNDimensional_Bad_Jac(void); + ~CNDimensional_Bad_Jac(void); + //--- method + virtual void Jac(double &x[],double &fi[],CMatrixDouble &jac,CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CNDimensional_Bad_Jac::CNDimensional_Bad_Jac(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CNDimensional_Bad_Jac::~CNDimensional_Bad_Jac(void) + { + + } +//+------------------------------------------------------------------+ +//| This callback calculates 'bad' function, | +//| i.e. function with incorrectly calculated derivatives | +//+------------------------------------------------------------------+ +void CNDimensional_Bad_Jac::Jac(double &x[],double &fi[],CMatrixDouble &jac, + CObject &obj) + { + fi[0]=10*MathPow(x[0]+3,2); + fi[1]=MathPow(x[1]-3,2); + jac[0].Set(0,20*(x[0]+3)); + jac[0].Set(1,0); + jac[1].Set(0,1); + jac[1].Set(1,20*(x[1]-3)); + } +//+------------------------------------------------------------------+ +//| Derived class from CNDimensional_PFunc | +//+------------------------------------------------------------------+ +class CNDimensional_CX_1_Func : public CNDimensional_PFunc + { +public: + //--- constructor, destructor + CNDimensional_CX_1_Func(void); + ~CNDimensional_CX_1_Func(void); + //--- method + virtual void PFunc(double &c[],double &x[],double &func,CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CNDimensional_CX_1_Func::CNDimensional_CX_1_Func(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CNDimensional_CX_1_Func::~CNDimensional_CX_1_Func(void) + { + + } +//+------------------------------------------------------------------+ +//| This callback calculates f(c,x)=exp(-c0*sqr(x0)) where x is a | +//| position on X-axis and c is adjustable parameter | +//+------------------------------------------------------------------+ +void CNDimensional_CX_1_Func::PFunc(double &c[],double &x[],double &func, + CObject &obj) + { + func=MathExp(-c[0]*x[0]*x[0]); + } +//+------------------------------------------------------------------+ +//| Derived class from CNDimensional_PFunc | +//+------------------------------------------------------------------+ +class CNDimensional_Debt_Func : public CNDimensional_PFunc + { +public: + //--- constructor, destructor + CNDimensional_Debt_Func(void); + ~CNDimensional_Debt_Func(void); + //--- method + virtual void PFunc(double &c[],double &x[],double &func,CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CNDimensional_Debt_Func::CNDimensional_Debt_Func(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CNDimensional_Debt_Func::~CNDimensional_Debt_Func(void) + { + + } +//+------------------------------------------------------------------+ +//| This callback calculates | +//| f(c,x)=c[0]*(1+c[1]*(pow(x[0]-1999,c[2])-1)) | +//+------------------------------------------------------------------+ +void CNDimensional_Debt_Func::PFunc(double &c[],double &x[],double &func, + CObject &obj) + { + func=c[0]*(1+c[1]*(MathPow(x[0]-1999,c[2])-1)); + } +//+------------------------------------------------------------------+ +//| Derived class from CNDimensional_PGrad | +//+------------------------------------------------------------------+ +class CNDimensional_CX_1_Grad : public CNDimensional_PGrad + { +public: + //--- constructor, destructor + CNDimensional_CX_1_Grad(void); + ~CNDimensional_CX_1_Grad(void); + //--- method + virtual void PGrad(double &c[],double &x[],double &func,double &grad[],CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CNDimensional_CX_1_Grad::CNDimensional_CX_1_Grad(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CNDimensional_CX_1_Grad::~CNDimensional_CX_1_Grad(void) + { + + } +//+------------------------------------------------------------------+ +//| 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 | +//+------------------------------------------------------------------+ +void CNDimensional_CX_1_Grad::PGrad(double &c[],double &x[],double &func, + double &grad[],CObject &obj) + { + func=MathExp(-c[0]*MathPow(x[0],2)); + grad[0]=-MathPow(x[0],2)*func; + } +//+------------------------------------------------------------------+ +//| Derived class from CNDimensional_PHess | +//+------------------------------------------------------------------+ +class CNDimensional_CX_1_Hess : public CNDimensional_PHess + { +public: + //--- constructor, destructor + CNDimensional_CX_1_Hess(void); + ~CNDimensional_CX_1_Hess(void); + //--- method + virtual void PHess(double &c[],double &x[],double &func,double &grad[],CMatrixDouble &hess,CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CNDimensional_CX_1_Hess::CNDimensional_CX_1_Hess(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CNDimensional_CX_1_Hess::~CNDimensional_CX_1_Hess(void) + { + + } +//+------------------------------------------------------------------+ +//| 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 | +//+------------------------------------------------------------------+ +void CNDimensional_CX_1_Hess::PHess(double &c[],double &x[],double &func, + double &grad[],CMatrixDouble &hess, + CObject &obj) + { + func=MathExp(-c[0]*MathPow(x[0],2)); + grad[0]=-MathPow(x[0],2)*func; + hess[0].Set(0,MathPow(x[0],4)*func); + } +//+------------------------------------------------------------------+ +//| Derived class from CNDimensional_ODE_RP | +//+------------------------------------------------------------------+ +class CNDimensional_ODE_Function_1_Dif : public CNDimensional_ODE_RP + { +public: + //--- constructor, destructor + CNDimensional_ODE_Function_1_Dif(void); + ~CNDimensional_ODE_Function_1_Dif(void); + //--- method + virtual void ODE_RP(double &y[],double x,double &dy[],CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CNDimensional_ODE_Function_1_Dif::CNDimensional_ODE_Function_1_Dif(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CNDimensional_ODE_Function_1_Dif::~CNDimensional_ODE_Function_1_Dif(void) + { + + } +//+------------------------------------------------------------------+ +//| This callback calculates f(y[],x)=-y[0] | +//+------------------------------------------------------------------+ +CNDimensional_ODE_Function_1_Dif::ODE_RP(double &y[],double x,double &dy[], + CObject &obj) + { + dy[0]=-y[0]; + } +//+------------------------------------------------------------------+ +//| Derived class from CIntegrator1_Func | +//+------------------------------------------------------------------+ +class CInt_Function_1_Func : public CIntegrator1_Func + { +public: + //--- constructor, destructor + CInt_Function_1_Func(void); + ~CInt_Function_1_Func(void); + //--- method + virtual void Int_Func(double x,double xminusa,double bminusx,double &y,CObject &obj); + }; +//+------------------------------------------------------------------+ +//| Constructor without parameters | +//+------------------------------------------------------------------+ +CInt_Function_1_Func::CInt_Function_1_Func(void) + { + + } +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CInt_Function_1_Func::~CInt_Function_1_Func(void) + { + + } +//+------------------------------------------------------------------+ +//| This callback calculates f(x)=exp(x) | +//+------------------------------------------------------------------+ +void CInt_Function_1_Func::Int_Func(double x,double xminusa,double bminusx, + double &y,CObject &obj) + { + y=MathExp(x); + } +//+------------------------------------------------------------------+ +//| A comparison of the two numbers | +//+------------------------------------------------------------------+ +bool Doc_Test_Int(int val,int test_val) + { +//--- return result + return(val==test_val); + } +//+------------------------------------------------------------------+ +//| A comparison of two numbers with an accuracy | +//+------------------------------------------------------------------+ +bool Doc_Test_Real(double val,double test_val,double _threshold) + { +//--- calculation + double s=_threshold>=0 ? 1.0 : MathAbs(test_val); + double threshold=MathAbs(_threshold); +//--- return result + return(MathAbs(val-test_val)/s<=threshold); + } +//+------------------------------------------------------------------+ +//| A comparison of two numbers with an accuracy | +//+------------------------------------------------------------------+ +bool Doc_Test_Complex(complex &val,complex &test_val,double _threshold) + { +//--- calculation + double s=_threshold>=0 ? 1.0 : CMath::AbsComplex(test_val); + double threshold=MathAbs(_threshold); +//--- return result + return(CMath::AbsComplex(val-test_val)/s<=threshold); + } +//+------------------------------------------------------------------+ +//| A comparison of two vectors | +//+------------------------------------------------------------------+ +bool Doc_Test_Int_Vector(int &val[],int &test_val[]) + { +//--- create a variable + int i; +//--- check + if(CAp::Len(val)!=CAp::Len(test_val)) + return(false); +//--- comparison + for(i=0;i=0 ? 1.0 : MathAbs(test_val[i]); + double threshold=MathAbs(_threshold); + //--- check + if(MathAbs(val[i]-test_val[i])/s>threshold) + return(false); + } +//--- return result + return(true); + } +//+------------------------------------------------------------------+ +//| A comparison of two vectors with an accuracy | +//+------------------------------------------------------------------+ +bool Doc_Test_Real_Matrix(CMatrixDouble &val,CMatrixDouble &test_val,double _threshold) + { +//--- create variables + int i,j; +//--- check + if(CAp::Rows(val)!=CAp::Rows(test_val)) + return(false); +//--- check + if(CAp::Cols(val)!=CAp::Cols(test_val)) + return(false); +//--- comparison + for(i=0;i=0 ? 1.0 : MathAbs(test_val[i][j]); + double threshold=MathAbs(_threshold); + //--- check + if(MathAbs(val[i][j]-test_val[i][j])/s>threshold) + return(false); + } +//--- return result + return(true); + } +//+------------------------------------------------------------------+ +//| A comparison of two vectors with an accuracy | +//+------------------------------------------------------------------+ +bool Doc_Test_Complex_Vector(complex &val[],complex &test_val[],double _threshold) + { +//--- create a variable + int i; +//--- check + if(CAp::Len(val)!=CAp::Len(test_val)) + return(false); +//--- comparison + for(i=0;i=0 ? 1.0 : CMath::AbsComplex(test_val[i]); + double threshold=MathAbs(_threshold); + //--- check + if(CMath::AbsComplex(val[i]-test_val[i])/s>threshold) + return(false); + } +//--- return result + return(true); + } +//+------------------------------------------------------------------+ +//| A comparison of two matrices with an accuracy | +//+------------------------------------------------------------------+ +bool Doc_Test_Complex_Matrix(CMatrixComplex &val,CMatrixComplex &test_val,double _threshold) + { +//--- create variables + int i,j; +//--- check + if(CAp::Rows(val)!=CAp::Rows(test_val)) + return(false); +//--- check + if(CAp::Cols(val)!=CAp::Cols(test_val)) + return(false); +//--- comparison + for(i=0;i=0 ? 1.0 : CMath::AbsComplex(test_val[i][j]); + double threshold=MathAbs(_threshold); + //--- check + if(CMath::AbsComplex(val[i][j]-test_val[i][j])/s>threshold) + return(false); + } +//--- return result + return(true); + } +//+------------------------------------------------------------------+ +//| Add to the vector random element | +//+------------------------------------------------------------------+ +void Spoil_Vector_By_Adding_Element(int &x[]) + { +//--- size calculation + int n=ArraySize(x); +//--- increasing the length of the vector + ArrayResize(x,n+1); +//--- set value + x[n]=MathRand(); + } +//+------------------------------------------------------------------+ +//| Add to the vector random element | +//+------------------------------------------------------------------+ +void Spoil_Vector_By_Adding_Element(double &x[]) + { +//--- size calculation + int n=ArraySize(x); +//--- increasing the length of the vector + ArrayResize(x,n+1); +//--- set value + x[n]=CMath::RandomReal(); + } +//+------------------------------------------------------------------+ +//| Add to the vector random element | +//+------------------------------------------------------------------+ +void Spoil_Vector_By_Adding_Element(complex &x[]) + { +//--- size calculation + int n=ArraySize(x); +//--- increasing the length of the vector + ArrayResize(x,n+1); +//--- set value + x[n].re=CMath::RandomReal(); + x[n].im=CMath::RandomReal(); + } +//+------------------------------------------------------------------+ +//| Removing the number of vector | +//+------------------------------------------------------------------+ +void Spoil_Vector_By_Deleting_Element(int &x[]) + { +//--- size calculation + int n=ArraySize(x); +//--- reduction length of the vector + ArrayResize(x,n-1); + } +//+------------------------------------------------------------------+ +//| Removing the number of vector | +//+------------------------------------------------------------------+ +void Spoil_Vector_By_Deleting_Element(double &x[]) + { +//--- size calculation + int n=ArraySize(x); +//--- reduction length of the vector + ArrayResize(x,n-1); + } +//+------------------------------------------------------------------+ +//| Removing the number of vector | +//+------------------------------------------------------------------+ +void Spoil_Vector_By_Deleting_Element(complex &x[]) + { +//--- size calculation + int n=ArraySize(x); +//--- reduction length of the vector + ArrayResize(x,n-1); + } +//+------------------------------------------------------------------+ +//| Add a row in the matrix | +//+------------------------------------------------------------------+ +void Spoil_Matrix_By_Adding_Row(CMatrixInt &x) + { +//--- cols and rows calculation + int n=CAp::Rows(x); + int m=CAp::Cols(x); +//--- increase the dimension + x.Resize(n+1,m); +//--- set values + for(int i=0;i=2 (posed as general linear constraint), + //--- * x+y>=6 + //--- using BLEIC optimizer. + ArrayResize(x,2); + //--- initialization + x[0]=5; + x[1]=5; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- allocation + c.Resize(2,3); + //--- initialization + c[0].Set(0,1); + c[0].Set(1,0); + c[0].Set(2,2); + c[1].Set(0,1); + c[1].Set(1,1); + c[1].Set(2,6); + //--- check + if(_spoil_scenario==3) + Spoil_Matrix_By_Value(c,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==4) + Spoil_Matrix_By_Value(c,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==5) + Spoil_Matrix_By_Value(c,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==6) + Spoil_Matrix_By_Deleting_Row(c); + //--- check + if(_spoil_scenario==7) + Spoil_Matrix_By_Deleting_Col(c); + //--- allocation + ArrayResize(ct,2); + //--- initialization + ct[0]=1; + ct[1]=1; + //--- check + if(_spoil_scenario==8) + Spoil_Vector_By_Deleting_Element(ct); + //--- create variables + CMinBLEICStateShell state; + CMinBLEICReportShell rep; + //--- These variables define stopping conditions for the underlying CG algorithm. + //--- They should be stringent enough in order to guarantee overall stability + //--- of the outer iterations. + //--- We use very simple condition - |g|<=epsg + double epsg=0.000001; + //--- check + if(_spoil_scenario==9) + epsg=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==10) + epsg=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==11) + epsg=CInfOrNaN::NegativeInfinity(); + double epsf=0; + //--- check + if(_spoil_scenario==12) + epsf=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==13) + epsf=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==14) + epsf=CInfOrNaN::NegativeInfinity(); + double epsx=0; + //--- check + if(_spoil_scenario==15) + epsx=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==16) + epsx=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==17) + epsx=CInfOrNaN::NegativeInfinity(); + //--- These variables define stopping conditions for the outer iterations: + //--- * epso controls convergence of outer iterations;algorithm will stop + //--- when difference between solutions of subsequent unconstrained problems + //--- will be less than 0.0001 + //--- * epsi controls amount of infeasibility allowed in the final solution + double epso=0.00001; + //--- check + if(_spoil_scenario==18) + epso=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==19) + epso=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==20) + epso=CInfOrNaN::NegativeInfinity(); + double epsi=0.00001; + //--- check + if(_spoil_scenario==21) + epsi=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==22) + epsi=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==23) + epsi=CInfOrNaN::NegativeInfinity(); + //--- 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... + CAlglib::MinBLEICCreate(x,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinBLEICSetLC(state,c,ct); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinBLEICSetInnerCond(state,epsg,epsf,epsx); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinBLEICSetOuterCond(state,epso,epsi); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinBLEICOptimize(state,fgrad,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinBLEICResults(state,x,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- ...and evaluate these results + ArrayResize(temparray,2); + //--- initialization + temparray[0]=2; + temparray[1]=4; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(rep.GetTerminationType(),4); + _TestResult=_TestResult && Doc_Test_Real_Vector(x,temparray,0.005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","minbleic_d_2"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Nonlinear optimization with bound constraints and numerical | +//| differentiation | +//+------------------------------------------------------------------+ +void TEST_MinBLEIC_NumDiff(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double temparray[]; + double bndl[]; + double bndu[]; + CObject obj; + CNDimensional_Func1 ffunc; + CNDimensional_Rep frep; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<25;_spoil_scenario++) + { + //--- 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. + ArrayResize(x,2); + //--- initialization + x[0]=0; + x[1]=0; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- allocation + ArrayResize(bndl,2); + //--- initialization + bndl[0]=-1; + bndl[1]=-1; + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Value(bndl,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==4) + Spoil_Vector_By_Deleting_Element(bndl); + //--- allocation + ArrayResize(bndu,2); + //--- initialization + bndu[0]=1; + bndu[1]=1; + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(bndu,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Deleting_Element(bndu); + CMinBLEICStateShell state; + CMinBLEICReportShell rep; + //--- These variables define stopping conditions for the underlying CG algorithm. + //--- They should be stringent enough in order to guarantee overall stability + //--- of the outer iterations. + //--- We use very simple condition - |g|<=epsg + double epsg=0.000001; + //--- check + if(_spoil_scenario==7) + epsg=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==8) + epsg=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==9) + epsg=CInfOrNaN::NegativeInfinity(); + double epsf=0; + //--- check + if(_spoil_scenario==10) + epsf=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==11) + epsf=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==12) + epsf=CInfOrNaN::NegativeInfinity(); + double epsx=0; + //--- check + if(_spoil_scenario==13) + epsx=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==14) + epsx=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==15) + epsx=CInfOrNaN::NegativeInfinity(); + //--- These variables define stopping conditions for the outer iterations: + //--- * epso controls convergence of outer iterations;algorithm will stop + //--- when difference between solutions of subsequent unconstrained problems + //--- will be less than 0.0001 + //--- * epsi controls amount of infeasibility allowed in the final solution + double epso=0.00001; + //--- check + if(_spoil_scenario==16) + epso=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==17) + epso=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==18) + epso=CInfOrNaN::NegativeInfinity(); + double epsi=0.00001; + //--- check + if(_spoil_scenario==19) + epsi=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==20) + epsi=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==21) + epsi=CInfOrNaN::NegativeInfinity(); + //--- This variable contains differentiation step + double diffstep=1.0e-6; + //--- check + if(_spoil_scenario==22) + diffstep=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==23) + diffstep=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==24) + diffstep=CInfOrNaN::NegativeInfinity(); + //--- 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... + CAlglib::MinBLEICCreateF(x,diffstep,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinBLEICSetBC(state,bndl,bndu); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinBLEICSetInnerCond(state,epsg,epsf,epsx); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinBLEICSetOuterCond(state,epso,epsi); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinBLEICOptimize(state,ffunc,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinBLEICResults(state,x,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- ...and evaluate these results + ArrayResize(temparray,2); + //--- initialization + temparray[0]=-1; + temparray[1]=1; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(rep.GetTerminationType(),4); + _TestResult=_TestResult && Doc_Test_Real_Vector(x,temparray,0.005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","minbleic_numdiff"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Nonlinear optimization by BLEIC, function with singularities | +//+------------------------------------------------------------------+ +void TEST_MinBLEIC_FTRIM(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double temparray[]; + CObject obj; + CNDimensional_S1_Grad fs1grad; + CNDimensional_Rep frep; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<18;_spoil_scenario++) + { + //--- 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 + //--- - withusing boundary constraints! + //--- See http://www.CAlglib::net/optimization/tipsandtricks.php#ftrimming for more information + //--- on this subject. + ArrayResize(x,1); + //--- initialization + x[0]=0; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + double epsg=1.0e-6; + //--- check + if(_spoil_scenario==3) + epsg=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==4) + epsg=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==5) + epsg=CInfOrNaN::NegativeInfinity(); + double epsf=0; + //--- check + if(_spoil_scenario==6) + epsf=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==7) + epsf=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==8) + epsf=CInfOrNaN::NegativeInfinity(); + double epsx=0; + //--- check + if(_spoil_scenario==9) + epsx=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==10) + epsx=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==11) + epsx=CInfOrNaN::NegativeInfinity(); + double epso=1.0e-6; + //--- check + if(_spoil_scenario==12) + epso=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==13) + epso=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==14) + epso=CInfOrNaN::NegativeInfinity(); + double epsi=1.0e-6; + //--- check + if(_spoil_scenario==15) + epsi=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==16) + epsi=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==17) + epsi=CInfOrNaN::NegativeInfinity(); + //--- create variables + CMinBLEICStateShell state; + CMinBLEICReportShell rep; + //--- function call + CAlglib::MinBLEICCreate(x,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinBLEICSetInnerCond(state,epsg,epsf,epsx); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinBLEICSetOuterCond(state,epso,epsi); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinBLEICOptimize(state,fs1grad,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinBLEICResults(state,x,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,1); + //--- initialization + temparray[0]=-0.99917305; + //--- check result + _TestResult=_TestResult && Doc_Test_Real_Vector(x,temparray,0.000005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","minbleic_ftrim"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Simple unconstrained MCPD model (no entry/exit states) | +//+------------------------------------------------------------------+ +void TEST_MCPD_Simple1(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + CMatrixDouble track0; + CMatrixDouble track1; + CMatrixDouble tempmatrix; + CMatrixDouble p; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<6;_spoil_scenario++) + { + //--- 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) + CMCPDStateShell s; + CMCPDReportShell rep; + //--- allocation + track0.Resize(5,2); + //--- initialization + track0[0].Set(0,1); + track0[0].Set(1,0); + track0[1].Set(0,0.95); + track0[1].Set(1,0.05); + track0[2].Set(0,0.9275); + track0[2].Set(1,0.0725); + track0[3].Set(0,0.91738); + track0[3].Set(1,0.08263); + track0[4].Set(0,0.91282); + track0[4].Set(1,0.08718); + //--- check + if(_spoil_scenario==0) + Spoil_Matrix_By_Value(track0,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Matrix_By_Value(track0,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Matrix_By_Value(track0,CInfOrNaN::NegativeInfinity()); + //--- allocation + track1.Resize(4,2); + //--- initialization + track1[0].Set(0,0.8); + track1[0].Set(1,0.2); + track1[1].Set(0,0.86); + track1[1].Set(1,0.14); + track1[2].Set(0,0.887); + track1[2].Set(1,0.113); + track1[3].Set(0,0.89915); + track1[3].Set(1,0.10085); + //--- check + if(_spoil_scenario==3) + Spoil_Matrix_By_Value(track1,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==4) + Spoil_Matrix_By_Value(track1,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==5) + Spoil_Matrix_By_Value(track1,CInfOrNaN::NegativeInfinity()); + //--- function call + CAlglib::MCPDCreate(2,s); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MCPDAddTrack(s,track0); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MCPDAddTrack(s,track1); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MCPDSolve(s); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MCPDResults(s,p,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- 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. + tempmatrix.Resize(2,2); + //--- initialization + tempmatrix[0].Set(0,0.95); + tempmatrix[0].Set(1,0.5); + tempmatrix[1].Set(0,0.05); + tempmatrix[1].Set(1,0.5); + //--- check result + _TestResult=_TestResult && Doc_Test_Real_Matrix(p,tempmatrix,0.005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","mcpd_simple1"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Simple MCPD model (no entry/exit states) with equality | +//| constraints | +//+------------------------------------------------------------------+ +void TEST_MCPD_Simple2(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + CMatrixDouble track0; + CMatrixDouble track1; + CMatrixDouble tempmatrix; + CMatrixDouble p; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<6;_spoil_scenario++) + { + //--- 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) + CMCPDStateShell s; + CMCPDReportShell rep; + //--- allocation + track0.Resize(5,3); + //--- initialization + track0[0].Set(0,1); + track0[0].Set(1,0); + track0[0].Set(2,0); + track0[1].Set(0,0.95); + track0[1].Set(1,0.05); + track0[1].Set(2,0); + track0[2].Set(0,0.9275); + track0[2].Set(1,0.06); + track0[2].Set(2,0.0125); + track0[3].Set(0,0.911125); + track0[3].Set(1,0.061375); + track0[3].Set(2,0.0275); + track0[4].Set(0,0.896256); + track0[4].Set(1,0.0609); + track0[4].Set(2,0.042844); + //--- check + if(_spoil_scenario==0) + Spoil_Matrix_By_Value(track0,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Matrix_By_Value(track0,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Matrix_By_Value(track0,CInfOrNaN::NegativeInfinity()); + //--- allocation + track1.Resize(5,3); + //--- initialization + track1[0].Set(0,0.8); + track1[0].Set(1,0.2); + track1[0].Set(2,0); + track1[1].Set(0,0.86); + track1[1].Set(1,0.09); + track1[1].Set(2,0.05); + track1[2].Set(0,0.862); + track1[2].Set(1,0.0655); + track1[2].Set(2,0.0725); + track1[3].Set(0,0.85165); + track1[3].Set(1,0.059475); + track1[3].Set(2,0.088875); + track1[4].Set(0,0.838805); + track1[4].Set(1,0.057451); + track1[4].Set(2,0.103744); + //--- check + if(_spoil_scenario==3) + Spoil_Matrix_By_Value(track1,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==4) + Spoil_Matrix_By_Value(track1,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==5) + Spoil_Matrix_By_Value(track1,CInfOrNaN::NegativeInfinity()); + //--- function call + CAlglib::MCPDCreate(3,s); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MCPDAddTrack(s,track0); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MCPDAddTrack(s,track1); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MCPDAddEC(s,0,2,0.0); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MCPDAddEC(s,1,2,0.0); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MCPDAddEC(s,2,2,1.0); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MCPDAddEC(s,2,0,0.0); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MCPDSolve(s); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MCPDResults(s,p,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- 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. + tempmatrix.Resize(3,3); + //--- initialization + tempmatrix[0].Set(0,0.95); + tempmatrix[0].Set(1,0.5); + tempmatrix[0].Set(2,0); + tempmatrix[1].Set(0,0.05); + tempmatrix[1].Set(1,0.25); + tempmatrix[1].Set(2,0); + tempmatrix[2].Set(0,0); + tempmatrix[2].Set(1,0.25); + tempmatrix[2].Set(2,1); + //--- check result + _TestResult=_TestResult && Doc_Test_Real_Matrix(p,tempmatrix,0.005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","mcpd_simple2"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Nonlinear optimization by L-BFGS | +//+------------------------------------------------------------------+ +void TEST_MinLBFGS_D_1(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double temparray[]; + CObject obj; + CNDimensional_Grad1 fgrad; + CNDimensional_Rep frep; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<12;_spoil_scenario++) + { + //--- This example demonstrates minimization of f(x,y)=100*(x+3)^4+(y-3)^4 + //--- using LBFGS method. + ArrayResize(x,2); + //--- initialization + x[0]=0; + x[1]=0; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + double epsg=0.0000000001; + //--- check + if(_spoil_scenario==3) + epsg=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==4) + epsg=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==5) + epsg=CInfOrNaN::NegativeInfinity(); + double epsf=0; + //--- check + if(_spoil_scenario==6) + epsf=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==7) + epsf=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==8) + epsf=CInfOrNaN::NegativeInfinity(); + double epsx=0; + //--- check + if(_spoil_scenario==9) + epsx=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==10) + epsx=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==11) + epsx=CInfOrNaN::NegativeInfinity(); + //--- create variables + int maxits=0; + CMinLBFGSStateShell state; + CMinLBFGSReportShell rep; + //--- function call + CAlglib::MinLBFGSCreate(1,x,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLBFGSSetCond(state,epsg,epsf,epsx,maxits); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLBFGSOptimize(state,fgrad,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLBFGSResults(state,x,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,2); + //--- initialization + temparray[0]=-3; + temparray[1]=3; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(rep.GetTerminationType(),4); + _TestResult=_TestResult && Doc_Test_Real_Vector(x,temparray,0.005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","minlbfgs_d_1"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Nonlinear optimization with additional settings and restarts | +//+------------------------------------------------------------------+ +void TEST_MinLBFGS_D_2(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double temparray[]; + CObject obj; + CNDimensional_Grad1 fgrad; + CNDimensional_Rep frep; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<18;_spoil_scenario++) + { + //--- 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 + ArrayResize(x,2); + //--- initialization + x[0]=0; + x[1]=0; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + double epsg=0.0000000001; + //--- check + if(_spoil_scenario==3) + epsg=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==4) + epsg=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==5) + epsg=CInfOrNaN::NegativeInfinity(); + double epsf=0; + //--- check + if(_spoil_scenario==6) + epsf=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==7) + epsf=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==8) + epsf=CInfOrNaN::NegativeInfinity(); + double epsx=0; + //--- check + if(_spoil_scenario==9) + epsx=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==10) + epsx=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==11) + epsx=CInfOrNaN::NegativeInfinity(); + double stpmax=0.1; + //--- check + if(_spoil_scenario==12) + stpmax=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==13) + stpmax=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==14) + stpmax=CInfOrNaN::NegativeInfinity(); + //--- create variables + int maxits=0; + CMinLBFGSStateShell state; + CMinLBFGSReportShell rep; + //--- first run + CAlglib::MinLBFGSCreate(1,x,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLBFGSSetCond(state,epsg,epsf,epsx,maxits); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLBFGSSetStpMax(state,stpmax); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLBFGSOptimize(state,fgrad,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLBFGSResults(state,x,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,2); + //--- initialization + temparray[0]=-3; + temparray[1]=3; + //--- check result + _TestResult=_TestResult && Doc_Test_Real_Vector(x,temparray,0.005); + //--- second run - algorithm is restarted + ArrayResize(x,2); + //--- initialization + x[0]=10; + x[1]=10; + //--- check + if(_spoil_scenario==15) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==16) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==17) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- function call + CAlglib::MinLBFGSRestartFrom(state,x); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLBFGSOptimize(state,fgrad,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLBFGSResults(state,x,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,2); + //--- initialization + temparray[0]=-3; + temparray[1]=3; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(rep.GetTerminationType(),4); + _TestResult=_TestResult && Doc_Test_Real_Vector(x,temparray,0.005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","minlbfgs_d_2"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Nonlinear optimization by L-BFGS with numerical differentiation | +//+------------------------------------------------------------------+ +void TEST_MinLBFGS_NumDiff(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double temparray[]; + CObject obj; + CNDimensional_Func1 ffunc; + CNDimensional_Rep frep; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<15;_spoil_scenario++) + { + //--- This example demonstrates minimization of f(x,y)=100*(x+3)^4+(y-3)^4 + //--- using numerical differentiation to calculate gradient. + ArrayResize(x,2); + //--- initialization + x[0]=0; + x[1]=0; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + double epsg=0.0000000001; + //--- check + if(_spoil_scenario==3) + epsg=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==4) + epsg=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==5) + epsg=CInfOrNaN::NegativeInfinity(); + double epsf=0; + //--- check + if(_spoil_scenario==6) + epsf=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==7) + epsf=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==8) + epsf=CInfOrNaN::NegativeInfinity(); + double epsx=0; + //--- check + if(_spoil_scenario==9) + epsx=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==10) + epsx=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==11) + epsx=CInfOrNaN::NegativeInfinity(); + double diffstep=1.0e-6; + //--- check + if(_spoil_scenario==12) + diffstep=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==13) + diffstep=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==14) + diffstep=CInfOrNaN::NegativeInfinity(); + int maxits=0; + CMinLBFGSStateShell state; + CMinLBFGSReportShell rep; + //--- function call + CAlglib::MinLBFGSCreateF(1,x,diffstep,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLBFGSSetCond(state,epsg,epsf,epsx,maxits); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLBFGSOptimize(state,ffunc,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLBFGSResults(state,x,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,2); + //--- initialization + temparray[0]=-3; + temparray[1]=3; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(rep.GetTerminationType(),4); + _TestResult=_TestResult && Doc_Test_Real_Vector(x,temparray,0.005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","minlbfgs_numdiff"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Nonlinear optimization by LBFGS, function with singularities | +//+------------------------------------------------------------------+ +void TEST_MinLBFGS_FTRIM(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double temparray[]; + CObject obj; + CNDimensional_S1_Grad fs1grad; + CNDimensional_Rep frep; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<12;_spoil_scenario++) + { + //--- 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.CAlglib::net/optimization/tipsandtricks.php#ftrimming for more information + //--- on this subject. + ArrayResize(x,1); + //--- initialization + x[0]=0; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + double epsg=1.0e-6; + //--- check + if(_spoil_scenario==3) + epsg=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==4) + epsg=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==5) + epsg=CInfOrNaN::NegativeInfinity(); + double epsf=0; + //--- check + if(_spoil_scenario==6) + epsf=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==7) + epsf=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==8) + epsf=CInfOrNaN::NegativeInfinity(); + double epsx=0; + //--- check + if(_spoil_scenario==9) + epsx=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==10) + epsx=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==11) + epsx=CInfOrNaN::NegativeInfinity(); + //--- create variables + int maxits=0; + CMinLBFGSStateShell state; + CMinLBFGSReportShell rep; + //--- function call + CAlglib::MinLBFGSCreate(1,x,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLBFGSSetCond(state,epsg,epsf,epsx,maxits); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLBFGSOptimize(state,fs1grad,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLBFGSResults(state,x,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,1); + //--- initialization + temparray[0]=-0.99917305; + //--- check result + _TestResult=_TestResult && Doc_Test_Real_Vector(x,temparray,0.000005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","minlbfgs_ftrim"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Solving y'=-y with ODE solver | +//+------------------------------------------------------------------+ +void TEST_ODESolver_D1(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double y[]; + double x[]; + int m; + double xtbl[]; + double temparray[]; + CMatrixDouble ytbl; + CMatrixDouble tempmatrix; + CObject obj; + CNDimensional_ODE_Function_1_Dif fode; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<13;_spoil_scenario++) + { + //--- allocation + ArrayResize(y,1); + //--- initialization + y[0]=1; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Deleting_Element(y); + //--- allocation + ArrayResize(x,4); + //--- initialization + x[0]=0; + x[1]=1; + x[2]=2; + x[3]=3; + //--- check + if(_spoil_scenario==4) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + double eps=0.00001; + //--- check + if(_spoil_scenario==7) + eps=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==8) + eps=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==9) + eps=CInfOrNaN::NegativeInfinity(); + double h=0; + //--- check + if(_spoil_scenario==10) + h=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==11) + h=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==12) + h=CInfOrNaN::NegativeInfinity(); + //--- create variables + CODESolverStateShell s; + CODESolverReportShell rep; + //--- function call + CAlglib::ODESolverRKCK(y,x,eps,h,s); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::ODESolverSolve(s,fode,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::ODESolverResults(s,m,xtbl,ytbl,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,4); + //--- initialization + temparray[0]=0; + temparray[1]=1; + temparray[2]=2; + temparray[3]=3; + //--- allocation + tempmatrix.Resize(4,1); + //--- initialization + tempmatrix[0].Set(0,1); + tempmatrix[1].Set(0,0.367); + tempmatrix[2].Set(0,0.135); + tempmatrix[3].Set(0,0.05); + //--- check result + _TestResult=_TestResult && Doc_Test_Int(m,4); + _TestResult=_TestResult && Doc_Test_Real_Vector(xtbl,temparray,0.005); + _TestResult=_TestResult && Doc_Test_Real_Matrix(ytbl,tempmatrix,0.005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","odesolver_d1"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Complex FFT: simple example | +//+------------------------------------------------------------------+ +void TEST_FFT_Complex_D1(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + complex z[]; + complex temparray[]; + complex tempcomplex1; + complex tempcomplex2; + complex cnan; + complex cpositiveinfinity; + complex cnegativeinfinity; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<3;_spoil_scenario++) + { + //--- first we demonstrate forward FFT: + //--- [1i,1i,1i,1i] is converted to [4i,0,0,0] + tempcomplex1.re=0; + tempcomplex1.im=1; + tempcomplex2.re=0; + tempcomplex2.im=4; + //--- allocation + ArrayResize(z,4); + //--- initialization + z[0]=tempcomplex1; + z[1]=tempcomplex1; + z[2]=tempcomplex1; + z[3]=tempcomplex1; + //--- initialization + cnan.re=CInfOrNaN::NaN(); + cnan.im=CInfOrNaN::NaN(); + cpositiveinfinity.re=CInfOrNaN::PositiveInfinity(); + cpositiveinfinity.im=CInfOrNaN::PositiveInfinity(); + cnegativeinfinity.re=CInfOrNaN::NegativeInfinity(); + cnegativeinfinity.im=CInfOrNaN::NegativeInfinity(); + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(z,cnan); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(z,cpositiveinfinity); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(z,cnegativeinfinity); + //--- function call + CAlglib::FFTC1D(z); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,4); + //--- initialization + temparray[0]=tempcomplex2; + temparray[1]=0; + temparray[2]=0; + temparray[3]=0; + //--- check result + _TestResult=_TestResult && Doc_Test_Complex_Vector(z,temparray,0.0001); + //--- now we convert [4i,0,0,0] back to [1i,1i,1i,1i] + //--- with backward FFT + CAlglib::FFTC1DInv(z); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,4); + //--- initialization + temparray[0]=tempcomplex1; + temparray[1]=tempcomplex1; + temparray[2]=tempcomplex1; + temparray[3]=tempcomplex1; + //--- check result + _TestResult=_TestResult && Doc_Test_Complex_Vector(z,temparray,0.0001); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","fft_complex_d1"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Complex FFT: advanced example | +//+------------------------------------------------------------------+ +void TEST_FFT_Complex_D2(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + complex z[]; + complex temparray[]; + complex tempcomplex1; + complex tempcomplex2; + complex tempcomplex3; + complex cnan; + complex cpositiveinfinity; + complex cnegativeinfinity; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<3;_spoil_scenario++) + { + //--- first we demonstrate forward FFT: + //--- [0,1,0,1i] is converted to [1+1i,-1-1i,-1-1i,1+1i] + tempcomplex1.re=0; + tempcomplex1.im=1; + //--- allocation + ArrayResize(z,4); + //--- initialization + z[0]=0; + z[1]=1; + z[2]=0; + z[3]=tempcomplex1; + //--- initialization + cnan.re=CInfOrNaN::NaN(); + cnan.im=CInfOrNaN::NaN(); + cpositiveinfinity.re=CInfOrNaN::PositiveInfinity(); + cpositiveinfinity.im=CInfOrNaN::PositiveInfinity(); + cnegativeinfinity.re=CInfOrNaN::NegativeInfinity(); + cnegativeinfinity.im=CInfOrNaN::NegativeInfinity(); + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(z,cnan); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(z,cpositiveinfinity); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(z,cnegativeinfinity); + //--- function call + CAlglib::FFTC1D(z); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- initialization + tempcomplex2.re=1; + tempcomplex2.im=1; + tempcomplex3.re=-1; + tempcomplex3.im=-1; + //--- allocation + ArrayResize(temparray,4); + //--- initialization + temparray[0]=tempcomplex2; + temparray[1]=tempcomplex3; + temparray[2]=tempcomplex3; + temparray[3]=tempcomplex2; + //--- check result + _TestResult=_TestResult && Doc_Test_Complex_Vector(z,temparray,0.0001); + //--- now we convert result back with backward FFT + CAlglib::FFTC1DInv(z); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,4); + //--- initialization + temparray[0]=0; + temparray[1]=1; + temparray[2]=0; + temparray[3]=tempcomplex1; + //--- check result + _TestResult=_TestResult && Doc_Test_Complex_Vector(z,temparray,0.0001); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","fft_complex_d2"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Real FFT: simple example | +//+------------------------------------------------------------------+ +void TEST_FFT_Real_D1(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + complex tempcarray[]; + double temparray[]; + complex f[]; + double x2[]; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<3;_spoil_scenario++) + { + //--- first we demonstrate forward FFT: + //--- [1,1,1,1] is converted to [4,0,0,0] + ArrayResize(x,4); + //--- initialization + x[0]=1; + x[1]=1; + x[2]=1; + x[3]=1; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- function call + CAlglib::FFTR1D(x,f); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(tempcarray,4); + //--- initialization + tempcarray[0]=4; + tempcarray[1]=0; + tempcarray[2]=0; + tempcarray[3]=0; + //--- check result + _TestResult=_TestResult && Doc_Test_Complex_Vector(f,tempcarray,0.0001); + //--- now we convert [4,0,0,0] back to [1,1,1,1] + //--- with backward FFT + CAlglib::FFTR1DInv(f,x2); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,4); + //--- initialization + temparray[0]=1; + temparray[1]=1; + temparray[2]=1; + temparray[3]=1; + //--- check result + _TestResult=_TestResult && Doc_Test_Real_Vector(x2,temparray,0.0001); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","fft_real_d1"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Real FFT: advanced example | +//+------------------------------------------------------------------+ +void TEST_FFT_Real_D2(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double temparray[]; + complex tempcarray[]; + complex f[]; + double x2[]; + complex tempcomplex1; + complex tempcomplex2; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<3;_spoil_scenario++) + { + //--- 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]) + ArrayResize(x,4); + //--- initialization + x[0]=1; + x[1]=2; + x[2]=3; + x[3]=4; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- function call + CAlglib::FFTR1D(x,f); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- initialization + tempcomplex1.re=-2; + tempcomplex1.im=2; + tempcomplex2.re=-2; + tempcomplex2.im=-2; + //--- allocation + ArrayResize(tempcarray,4); + //--- initialization + tempcarray[0]=10; + tempcarray[1]=tempcomplex1; + tempcarray[2]=-2; + tempcarray[3]=tempcomplex2; + //--- check result + _TestResult=_TestResult && Doc_Test_Complex_Vector(f,tempcarray,0.0001); + //--- now we convert [10,-2+2i,-2,-2-2i] back to [1,2,3,4] + CAlglib::FFTR1DInv(f,x2); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,4); + //--- initialization + temparray[0]=1; + temparray[1]=2; + temparray[2]=3; + temparray[3]=4; + //--- check result + _TestResult=_TestResult && Doc_Test_Real_Vector(x2,temparray,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. + ArrayResize(f,3); + //--- initialization + f[0]=10; + f[1]=tempcomplex1; + f[2]=-2; + //--- function call + CAlglib::FFTR1DInv(f,4,x2); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,4); + //--- initialization + temparray[0]=1; + temparray[1]=2; + temparray[2]=3; + temparray[3]=4; + //--- check result + _TestResult=_TestResult && Doc_Test_Real_Vector(x2,temparray,0.0001); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","fft_real_d2"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| error detection in backward FFT | +//+------------------------------------------------------------------+ +void TEST_FFT_Complex_E1(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + complex tempcomplex1; + complex tempcomplex2; + complex z[]; + complex temparray[]; + complex cnan; + complex cpositiveinfinity; + complex cnegativeinfinity; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<3;_spoil_scenario++) + { + //--- allocation + ArrayResize(z,4); + //--- initialization + z[0]=0; + z[1]=2; + z[2]=0; + z[3]=-2; + //--- initialization + cnan.re=CInfOrNaN::NaN(); + cnan.im=CInfOrNaN::NaN(); + cpositiveinfinity.re=CInfOrNaN::PositiveInfinity(); + cpositiveinfinity.im=CInfOrNaN::PositiveInfinity(); + cnegativeinfinity.re=CInfOrNaN::NegativeInfinity(); + cnegativeinfinity.im=CInfOrNaN::NegativeInfinity(); + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(z,cnan); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(z,cpositiveinfinity); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(z,cnegativeinfinity); + //--- function call + CAlglib::FFTC1DInv(z); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- initialization + tempcomplex1.re=0; + tempcomplex1.im=1; + tempcomplex2.re=0; + tempcomplex2.im=-1; + //--- allocation + ArrayResize(temparray,4); + //--- initialization + temparray[0]=0; + temparray[1]=tempcomplex1; + temparray[2]=0; + temparray[3]=tempcomplex2; + //--- check result + _TestResult=_TestResult && Doc_Test_Complex_Vector(z,temparray,0.0001); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","fft_complex_e1"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Integrating f=exp(x) by adaptive integrator | +//+------------------------------------------------------------------+ +void TEST_AutoGK_D1(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + CObject obj; + CInt_Function_1_Func fint; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<6;_spoil_scenario++) + { + //--- 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; + //--- check + if(_spoil_scenario==0) + a=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==1) + a=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==2) + a=CInfOrNaN::NegativeInfinity(); + double b=1; + //--- check + if(_spoil_scenario==3) + b=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==4) + b=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==5) + b=CInfOrNaN::NegativeInfinity(); + //--- create variables + CAutoGKStateShell s; + double v; + CAutoGKReportShell rep; + //--- function call + CAlglib::AutoGKSmooth(a,b,s); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::AutoGKIntegrate(s,fint,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::AutoGKResults(s,v,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,1.7182,0.005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","autogk_d1"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Interpolation and differentiation using barycentric | +//| representation | +//+------------------------------------------------------------------+ +void TEST_PolInt_D_CalcDiff(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double y[]; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<12;_spoil_scenario++) + { + //--- Here we demonstrate polynomial interpolation and differentiation + //--- of y=x^2-x sampled at [0,1,2]. Barycentric representation of polynomial is used. + ArrayResize(x,3); + //--- initialization + x[0]=0; + x[1]=1; + x[2]=2; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Adding_Element(x); + //--- check + if(_spoil_scenario==4) + Spoil_Vector_By_Deleting_Element(x); + //--- allocation + ArrayResize(y,3); + //--- initialization + y[0]=0; + y[1]=0; + y[2]=2; + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==8) + Spoil_Vector_By_Adding_Element(y); + //--- check + if(_spoil_scenario==9) + Spoil_Vector_By_Deleting_Element(y); + double t=-1; + //--- check + if(_spoil_scenario==10) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==11) + t=CInfOrNaN::NegativeInfinity(); + //--- create variables + double v; + double dv; + double d2v; + CBarycentricInterpolantShell p; + //--- barycentric model is created + CAlglib::PolynomialBuild(x,y,p); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- barycentric interpolation is demonstrated + v=CAlglib::BarycentricCalc(p,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,2.0,0.00005); + //--- barycentric differentation is demonstrated + CAlglib::BarycentricDiff1(p,t,v,dv); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _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 + CAlglib::BarycentricDiff1(p,t,v,dv); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,2.0,0.00005); + _TestResult=_TestResult && Doc_Test_Real(dv,-3.0,0.00005); + //--- function call + CAlglib::BarycentricDiff2(p,t,v,dv,d2v); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _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); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","polint_d_calcdiff"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Conversion between power basis and barycentric representation | +//+------------------------------------------------------------------+ +void TEST_PolInt_D_Conv(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double a[]; + double temparray[]; + double a2[]; + double v; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<5;_spoil_scenario++) + { + //--- Here we demonstrate conversion of y=x^2-x + //--- between power basis and barycentric representation. + ArrayResize(a,3); + //--- initialization + a[0]=0; + a[1]=-1; + a[2]=1; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(a,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(a,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(a,CInfOrNaN::NegativeInfinity()); + double t=2; + //--- check + if(_spoil_scenario==3) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==4) + t=CInfOrNaN::NegativeInfinity(); + //--- create a variable + CBarycentricInterpolantShell 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. + CAlglib::PolynomialPow2Bar(a,p); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- now we have barycentric interpolation;we can use it for interpolation + v=CAlglib::BarycentricCalc(p,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,2.0,0.005); + //--- we can also convert back from barycentric representation to power basis + CAlglib::PolynomialBar2Pow(p,a2); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,3); + //--- initialization + temparray[0]=0; + temparray[1]=-1; + temparray[2]=1; + //--- check result + _TestResult=_TestResult && Doc_Test_Real_Vector(a2,temparray,0.005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","polint_d_conv"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Polynomial interpolation on special grids (equidistant, | +//| Chebyshev I/II) | +//+------------------------------------------------------------------+ +void TEST_PolInt_D_Spec(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double y_eqdist[]; + double y_cheb1[]; + double y_cheb2[]; + double a_eqdist[]; + double a_cheb1[]; + double a_cheb2[]; + double temparray[]; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<11;_spoil_scenario++) + { + //--- 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 + ArrayResize(y_eqdist,3); + //--- initialization + y_eqdist[0]=0; + y_eqdist[1]=0; + y_eqdist[2]=2; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(y_eqdist,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(y_eqdist,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(y_eqdist,CInfOrNaN::NegativeInfinity()); + //--- allocation + ArrayResize(y_cheb1,3); + //--- initialization + y_cheb1[0]=-0.116025; + y_cheb1[1]=0; + y_cheb1[2]=1.616025; + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Value(y_cheb1,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==4) + Spoil_Vector_By_Value(y_cheb1,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(y_cheb1,CInfOrNaN::NegativeInfinity()); + //--- allocation + ArrayResize(y_cheb2,3); + //--- initialization + y_cheb2[0]=0; + y_cheb2[1]=0; + y_cheb2[2]=2; + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Value(y_cheb2,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Value(y_cheb2,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==8) + Spoil_Vector_By_Value(y_cheb2,CInfOrNaN::NegativeInfinity()); + //--- create variables + CBarycentricInterpolantShell p_eqdist; + CBarycentricInterpolantShell p_cheb1; + CBarycentricInterpolantShell p_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. + CAlglib::PolynomialBuildEqDist(0.0,2.0,y_eqdist,p_eqdist); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::PolynomialBar2Pow(p_eqdist,a_eqdist); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,3); + //--- initialization + temparray[0]=0; + temparray[1]=-1; + temparray[2]=1; + //--- check result + _TestResult=_TestResult && Doc_Test_Real_Vector(a_eqdist,temparray,0.00005); + //--- function call + CAlglib::PolynomialBuildCheb1(-1,+1,y_cheb1,p_cheb1); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::PolynomialBar2Pow(p_cheb1,a_cheb1); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,3); + //--- initialization + temparray[0]=0; + temparray[1]=-1; + temparray[2]=1; + //--- check result + _TestResult=_TestResult && Doc_Test_Real_Vector(a_cheb1,temparray,0.00005); + //--- function call + CAlglib::PolynomialBuildCheb2(-1,+1,y_cheb2,p_cheb2); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::PolynomialBar2Pow(p_cheb2,a_cheb2); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,3); + //--- initialization + temparray[0]=0; + temparray[1]=-1; + temparray[2]=1; + //--- check result + _TestResult=_TestResult && Doc_Test_Real_Vector(a_cheb2,temparray,0.00005); + //--- Now we demonstrate polynomial interpolation withconstruction + //--- of the barycentricinterpolant structure. + //--- We calculate interpolant value at x=-2. + //--- In all three cases we should get same f=6 + double t=-2; + //--- check + if(_spoil_scenario==9) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==10) + t=CInfOrNaN::NegativeInfinity(); + double v; + //--- function call + v=CAlglib::PolynomialCalcEqDist(0.0,2.0,y_eqdist,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,6.0,0.00005); + //--- function call + v=CAlglib::PolynomialCalcCheb1(-1,+1,y_cheb1,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,6.0,0.00005); + //--- function call + v=CAlglib::PolynomialCalcCheb2(-1,+1,y_cheb2,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,6.0,0.00005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","polint_d_spec"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Polynomial interpolation,full list of parameters. | +//+------------------------------------------------------------------+ +void TEST_PolInt_T_1(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double y[]; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<10;_spoil_scenario++) + { + //--- allocation + ArrayResize(x,3); + //--- initialization + x[0]=0; + x[1]=1; + x[2]=2; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Deleting_Element(x); + //--- allocation + ArrayResize(y,3); + //--- initialization + y[0]=0; + y[1]=0; + y[2]=2; + //--- check + if(_spoil_scenario==4) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Deleting_Element(y); + double t=-1; + //--- check + if(_spoil_scenario==8) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==9) + t=CInfOrNaN::NegativeInfinity(); + //--- create variables + CBarycentricInterpolantShell p; + double v; + //--- function call + CAlglib::PolynomialBuild(x,y,3,p); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + v=CAlglib::BarycentricCalc(p,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,2.0,0.00005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","polint_t_1"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Polynomial interpolation,full list of parameters. | +//+------------------------------------------------------------------+ +void TEST_PolInt_T_2(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double y[]; + double t; + double v; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<6;_spoil_scenario++) + { + //--- allocation + ArrayResize(y,3); + //--- initialization + y[0]=0; + y[1]=0; + y[2]=2; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Deleting_Element(y); + t=-1; + //--- check + if(_spoil_scenario==4) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==5) + t=CInfOrNaN::NegativeInfinity(); + CBarycentricInterpolantShell p; + //--- function call + CAlglib::PolynomialBuildEqDist(0.0,2.0,y,3,p); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + v=CAlglib::BarycentricCalc(p,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,2.0,0.00005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","polint_t_2"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Polynomial interpolation,full list of parameters. | +//+------------------------------------------------------------------+ +void TEST_PolInt_T_3(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double y[]; + double t; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<6;_spoil_scenario++) + { + //--- allocation + ArrayResize(y,3); + //--- initialization + y[0]=-0.116025; + y[1]=0; + y[2]=1.616025; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Deleting_Element(y); + t=-1; + //--- check + if(_spoil_scenario==4) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==5) + t=CInfOrNaN::NegativeInfinity(); + CBarycentricInterpolantShell p; + //--- function call + CAlglib::PolynomialBuildCheb1(-1.0,+1.0,y,3,p); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- create a variable + double v; + //--- function call + v=CAlglib::BarycentricCalc(p,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,2.0,0.00005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","polint_t_3"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Polynomial interpolation,full list of parameters. | +//+------------------------------------------------------------------+ +void TEST_PolInt_T_4(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double y[]; + double t; + double a; + double b; + double v; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<12;_spoil_scenario++) + { + //--- allocation + ArrayResize(y,3); + //--- initialization + y[0]=0; + y[1]=0; + y[2]=2; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Deleting_Element(y); + t=-2; + //--- check + if(_spoil_scenario==4) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==5) + t=CInfOrNaN::NegativeInfinity(); + a=-1; + //--- check + if(_spoil_scenario==6) + a=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==7) + a=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==8) + a=CInfOrNaN::NegativeInfinity(); + b=1; + //--- check + if(_spoil_scenario==9) + b=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==10) + b=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==11) + b=CInfOrNaN::NegativeInfinity(); + //--- create a variable + CBarycentricInterpolantShell p; + //--- function call + CAlglib::PolynomialBuildCheb2(a,b,y,3,p); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + v=CAlglib::BarycentricCalc(p,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,6.0,0.00005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","polint_t_4"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Polynomial interpolation,full list of parameters. | +//+------------------------------------------------------------------+ +void TEST_PolInt_T_5(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double y[]; + double t; + double v; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<6;_spoil_scenario++) + { + //--- allocation + ArrayResize(y,3); + //--- initialization + y[0]=0; + y[1]=0; + y[2]=2; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Deleting_Element(y); + t=-1; + //--- check + if(_spoil_scenario==4) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==5) + t=CInfOrNaN::NegativeInfinity(); + //--- function call + v=CAlglib::PolynomialCalcEqDist(0.0,2.0,y,3,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,2.0,0.00005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","polint_t_5"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Polynomial interpolation,full list of parameters. | +//+------------------------------------------------------------------+ +void TEST_PolInt_T_6(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double y[]; + double t; + double a; + double b; + double v; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<12;_spoil_scenario++) + { + //--- allocation + ArrayResize(y,3); + //--- initialization + y[0]=-0.116025; + y[1]=0; + y[2]=1.616025; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Deleting_Element(y); + t=-1; + //--- check + if(_spoil_scenario==4) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==5) + t=CInfOrNaN::NegativeInfinity(); + a=-1; + //--- check + if(_spoil_scenario==6) + a=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==7) + a=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==8) + a=CInfOrNaN::NegativeInfinity(); + b=1; + //--- check + if(_spoil_scenario==9) + b=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==10) + b=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==11) + b=CInfOrNaN::NegativeInfinity(); + //--- function call + v=CAlglib::PolynomialCalcCheb1(a,b,y,3,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,2.0,0.00005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","polint_t_6"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Polynomial interpolation,full list of parameters. | +//+------------------------------------------------------------------+ +void TEST_PolInt_T_7(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double y[]; + double t; + double a; + double b; + double v; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<12;_spoil_scenario++) + { + //--- allocation + ArrayResize(y,3); + //--- initialization + y[0]=0; + y[1]=0; + y[2]=2; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Deleting_Element(y); + t=-2; + //--- check + if(_spoil_scenario==4) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==5) + t=CInfOrNaN::NegativeInfinity(); + a=-1; + //--- check + if(_spoil_scenario==6) + a=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==7) + a=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==8) + a=CInfOrNaN::NegativeInfinity(); + b=1; + //--- check + if(_spoil_scenario==9) + b=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==10) + b=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==11) + b=CInfOrNaN::NegativeInfinity(); + //--- function call + v=CAlglib::PolynomialCalcCheb2(a,b,y,3,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,6.0,0.00005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","polint_t_7"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Polynomial interpolation: y=x^2-x,equidistant grid, barycentric | +//| form | +//+------------------------------------------------------------------+ +void TEST_PolInt_T_8(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double y[]; + double t; + double v; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<5;_spoil_scenario++) + { + //--- allocation + ArrayResize(y,3); + //--- initialization + y[0]=0; + y[1]=0; + y[2]=2; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + t=-1; + //--- check + if(_spoil_scenario==3) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==4) + t=CInfOrNaN::NegativeInfinity(); + CBarycentricInterpolantShell p; + //--- function call + CAlglib::PolynomialBuildEqDist(0.0,2.0,y,p); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + v=CAlglib::BarycentricCalc(p,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,2.0,0.00005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","polint_t_8"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Polynomial interpolation: y=x^2-x, Chebyshev grid (first kind), | +//| barycentric form | +//+------------------------------------------------------------------+ +void TEST_PolInt_T_9(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double y[]; + double t; + double a; + double b; + double v; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<11;_spoil_scenario++) + { + //--- allocation + ArrayResize(y,3); + //--- initialization + y[0]=-0.116025; + y[1]=0; + y[2]=1.616025; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + t=-1; + //--- check + if(_spoil_scenario==3) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==4) + t=CInfOrNaN::NegativeInfinity(); + a=-1; + //--- check + if(_spoil_scenario==5) + a=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==6) + a=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==7) + a=CInfOrNaN::NegativeInfinity(); + b=1; + //--- check + if(_spoil_scenario==8) + b=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==9) + b=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==10) + b=CInfOrNaN::NegativeInfinity(); + //--- create a variable + CBarycentricInterpolantShell p; + //--- function call + CAlglib::PolynomialBuildCheb1(a,b,y,p); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + v=CAlglib::BarycentricCalc(p,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,2.0,0.00005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","polint_t_9"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Polynomial interpolation: y=x^2-x, Chebyshev grid (second kind), | +//| barycentric form | +//+------------------------------------------------------------------+ +void TEST_PolInt_T_10(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double y[]; + double t; + double a; + double b; + double v; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<11;_spoil_scenario++) + { + //--- allocation + ArrayResize(y,3); + //--- initialization + y[0]=0; + y[1]=0; + y[2]=2; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + t=-2; + //--- check + if(_spoil_scenario==3) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==4) + t=CInfOrNaN::NegativeInfinity(); + a=-1; + //--- check + if(_spoil_scenario==5) + a=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==6) + a=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==7) + a=CInfOrNaN::NegativeInfinity(); + b=1; + //--- check + if(_spoil_scenario==8) + b=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==9) + b=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==10) + b=CInfOrNaN::NegativeInfinity(); + //--- create a variable + CBarycentricInterpolantShell p; + //--- function call + CAlglib::PolynomialBuildCheb2(a,b,y,p); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + v=CAlglib::BarycentricCalc(p,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,6.0,0.00005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","polint_t_10"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Polynomial interpolation: y=x^2-x,equidistant grid | +//+------------------------------------------------------------------+ +void TEST_PolInt_T_11(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double y[]; + double t; + double v; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<5;_spoil_scenario++) + { + //--- allocation + ArrayResize(y,3); + //--- initialization + y[0]=0; + y[1]=0; + y[2]=2; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + t=-1; + //--- check + if(_spoil_scenario==3) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==4) + t=CInfOrNaN::NegativeInfinity(); + //--- function call + v=CAlglib::PolynomialCalcEqDist(0.0,2.0,y,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,2.0,0.00005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","polint_t_11"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Polynomial interpolation: y=x^2-x,Chebyshev grid (first kind) | +//+------------------------------------------------------------------+ +void TEST_PolInt_T_12(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double y[]; + double t; + double a; + double b; + double v; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<11;_spoil_scenario++) + { + //--- allocation + ArrayResize(y,3); + //--- initialization + y[0]=-0.116025; + y[1]=0; + y[2]=1.616025; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + t=-1; + //--- check + if(_spoil_scenario==3) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==4) + t=CInfOrNaN::NegativeInfinity(); + a=-1; + //--- check + if(_spoil_scenario==5) + a=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==6) + a=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==7) + a=CInfOrNaN::NegativeInfinity(); + b=+1; + //--- check + if(_spoil_scenario==8) + b=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==9) + b=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==10) + b=CInfOrNaN::NegativeInfinity(); + //--- function call + v=CAlglib::PolynomialCalcCheb1(a,b,y,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,2.0,0.00005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","polint_t_12"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Polynomial interpolation: y=x^2-x,Chebyshev grid (second kind) | +//+------------------------------------------------------------------+ +void TEST_PolInt_T_13(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double y[]; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<11;_spoil_scenario++) + { + //--- allocation + ArrayResize(y,3); + //--- initialization + y[0]=0; + y[1]=0; + y[2]=2; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + double t=-2; + //--- check + if(_spoil_scenario==3) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==4) + t=CInfOrNaN::NegativeInfinity(); + double a=-1; + //--- check + if(_spoil_scenario==5) + a=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==6) + a=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==7) + a=CInfOrNaN::NegativeInfinity(); + double b=+1; + //--- check + if(_spoil_scenario==8) + b=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==9) + b=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==10) + b=CInfOrNaN::NegativeInfinity(); + double v; + //--- function call + v=CAlglib::PolynomialCalcCheb2(a,b,y,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,6.0,0.00005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","polint_t_13"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Piecewise linear spline interpolation | +//+------------------------------------------------------------------+ +void TEST_Spline1D_D_Linear(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double y[]; + double t; + double v; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<12;_spoil_scenario++) + { + //--- We use piecewise linear spline to interpolate f(x)=x^2 sampled + //--- at 5 equidistant nodes on [-1,+1]. + ArrayResize(x,5); + //--- initialization + x[0]=-1; + x[1]=-0.5; + x[2]=0; + x[3]=0.5; + x[4]=1; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Adding_Element(x); + //--- check + if(_spoil_scenario==4) + Spoil_Vector_By_Deleting_Element(x); + //--- allocation + ArrayResize(y,5); + //--- initialization + y[0]=1; + y[1]=0.25; + y[2]=0; + y[3]=0.25; + y[4]=1; + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==8) + Spoil_Vector_By_Adding_Element(y); + //--- check + if(_spoil_scenario==9) + Spoil_Vector_By_Deleting_Element(y); + t=0.25; + //--- check + if(_spoil_scenario==10) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==11) + t=CInfOrNaN::NegativeInfinity(); + //--- create a variable + CSpline1DInterpolantShell s; + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- build spline + CAlglib::Spline1DBuildLinear(x,y,s); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- calculate S(0.25) - it is quite different from 0.25^2=0.0625 + v=CAlglib::Spline1DCalc(s,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,0.125,0.00005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","spline1d_d_linear"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Cubic spline interpolation | +//+------------------------------------------------------------------+ +void TEST_Spline1D_D_Cubic(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double y[]; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<10;_spoil_scenario++) + { + //--- 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. + ArrayResize(x,5); + //--- initialization + x[0]=-1; + x[1]=-0.5; + x[2]=0; + x[3]=0.5; + x[4]=1; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Deleting_Element(x); + //--- allocation + ArrayResize(y,5); + //--- initialization + y[0]=1; + y[1]=0.25; + y[2]=0; + y[3]=0.25; + y[4]=1; + //--- check + if(_spoil_scenario==4) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Deleting_Element(y); + double t=0.25; + //--- check + if(_spoil_scenario==8) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==9) + t=CInfOrNaN::NegativeInfinity(); + //--- create variables + double v; + CSpline1DInterpolantShell s; + int natural_bound_type=2; + //--- Test exact boundary conditions: build S(x),calculare S(0.25) + //--- (almost same as original function) + CAlglib::Spline1DBuildCubic(x,y,s); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + v=CAlglib::Spline1DCalc(s,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,0.0625,0.00001); + //--- Test natural boundary conditions: build S(x),calculare S(0.25) + //--- (small interpolation error) + CAlglib::Spline1DBuildCubic(x,y,5,natural_bound_type,0.0,natural_bound_type,0.0,s); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + v=CAlglib::Spline1DCalc(s,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,0.0580,0.0001); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","spline1d_d_cubic"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Differentiation on the grid using cubic splines | +//+------------------------------------------------------------------+ +void TEST_Spline1D_D_GridDiff(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double y[]; + double d1[]; + double d2[]; + double temparray1[]; + double temparray2[]; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<10;_spoil_scenario++) + { + //--- 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. + ArrayResize(x,5); + //--- initialization + x[0]=-1; + x[1]=-0.5; + x[2]=0; + x[3]=0.5; + x[4]=1; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Adding_Element(x); + //--- check + if(_spoil_scenario==4) + Spoil_Vector_By_Deleting_Element(x); + //--- allocation + ArrayResize(y,5); + //--- initialization + y[0]=1; + y[1]=0.25; + y[2]=0; + y[3]=0.25; + y[4]=1; + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==8) + Spoil_Vector_By_Adding_Element(y); + //--- check + if(_spoil_scenario==9) + Spoil_Vector_By_Deleting_Element(y); + //--- We calculate first derivatives: they must be equal to 2*x + CAlglib::Spline1DGridDiffCubic(x,y,d1); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray1,5); + //--- initialization + temparray1[0]=-2; + temparray1[1]=-1; + temparray1[2]=0; + temparray1[3]=1; + temparray1[4]=2; + //--- check result + _TestResult=_TestResult && Doc_Test_Real_Vector(d1,temparray1,0.0001); + //--- Now test griddiff2,which returns first AND second derivatives. + //--- First derivative is 2*x,second is equal to 2.0 + CAlglib::Spline1DGridDiff2Cubic(x,y,d1,d2); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray2,5); + //--- initialization + temparray2[0]=2; + temparray2[1]=2; + temparray2[2]=2; + temparray2[3]=2; + temparray2[4]=2; + //--- check result + _TestResult=_TestResult && Doc_Test_Real_Vector(d1,temparray1,0.0001); + _TestResult=_TestResult && Doc_Test_Real_Vector(d2,temparray2,0.0001); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","spline1d_d_griddiff"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Resampling using cubic splines | +//+------------------------------------------------------------------+ +void TEST_Spline1D_D_ConvDiff(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x_old[]; + double y_old[]; + double x_new[]; + double y_new[]; + double d1_new[]; + double d2_new[]; + double temparray1[]; + double temparray2[]; + double temparray3[]; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<11;_spoil_scenario++) + { + //--- 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. + ArrayResize(x_old,5); + //--- initialization + x_old[0]=-1; + x_old[1]=-0.5; + x_old[2]=0; + x_old[3]=0.5; + x_old[4]=1; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x_old,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x_old,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x_old,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Deleting_Element(x_old); + //--- allocation + ArrayResize(y_old,5); + //--- initialization + y_old[0]=1; + y_old[1]=0.25; + y_old[2]=0; + y_old[3]=0.25; + y_old[4]=1; + //--- check + if(_spoil_scenario==4) + Spoil_Vector_By_Value(y_old,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(y_old,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Value(y_old,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Deleting_Element(y_old); + //--- allocation + ArrayResize(x_new,9); + //--- initialization + x_new[0]=-1; + x_new[1]=-0.75; + x_new[2]=-0.5; + x_new[3]=-0.25; + x_new[4]=0; + x_new[5]=0.25; + x_new[6]=0.5; + x_new[7]=0.75; + x_new[8]=1; + //--- check + if(_spoil_scenario==8) + Spoil_Vector_By_Value(x_new,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==9) + Spoil_Vector_By_Value(x_new,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==10) + Spoil_Vector_By_Value(x_new,CInfOrNaN::NegativeInfinity()); + //--- First,conversion withdifferentiation. + CAlglib::Spline1DConvCubic(x_old,y_old,x_new,y_new); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray1,9); + //--- initialization + temparray1[0]=1; + temparray1[1]=0.5625; + temparray1[2]=0.25; + temparray1[3]=0.0625; + temparray1[4]=0; + temparray1[5]=0.0625; + temparray1[6]=0.25; + temparray1[7]=0.5625; + temparray1[8]=1; + //--- check result + _TestResult=_TestResult && Doc_Test_Real_Vector(y_new,temparray1,0.0001); + //--- Then,conversion with differentiation (first derivatives only) + CAlglib::Spline1DConvDiffCubic(x_old,y_old,x_new,y_new,d1_new); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray2,9); + //--- initialization + temparray2[0]=-2; + temparray2[1]=-1.5; + temparray2[2]=-1; + temparray2[3]=-0.5; + temparray2[4]=0; + temparray2[5]=0.5; + temparray2[6]=1.0; + temparray2[7]=1.5; + temparray2[8]=2; + //--- check result + _TestResult=_TestResult && Doc_Test_Real_Vector(y_new,temparray1,0.0001); + _TestResult=_TestResult && Doc_Test_Real_Vector(d1_new,temparray2,0.0001); + //--- Finally,conversion with first and second derivatives + CAlglib::Spline1DConvDiff2Cubic(x_old,y_old,x_new,y_new,d1_new,d2_new); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray3,9); + //--- initialization + temparray3[0]=2; + temparray3[1]=2; + temparray3[2]=2; + temparray3[3]=2; + temparray3[4]=2; + temparray3[5]=2; + temparray3[6]=2; + temparray3[7]=2; + temparray3[8]=2; + //--- check result + _TestResult=_TestResult && Doc_Test_Real_Vector(y_new,temparray1,0.0001); + _TestResult=_TestResult && Doc_Test_Real_Vector(d1_new,temparray2,0.0001); + _TestResult=_TestResult && Doc_Test_Real_Vector(d2_new,temparray3,0.0001); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","spline1d_d_convdiff"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Unconstrained dense quadratic programming | +//+------------------------------------------------------------------+ +void TEST_MinQP_D_U1(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + CMatrixDouble a; + double b[]; + double x0[]; + double x[]; + double temparray[]; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<13;_spoil_scenario++) + { + //--- 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 withsuch 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)! + a.Resize(2,2); + //--- initialization + a[0].Set(0,2); + a[0].Set(1,0); + a[1].Set(0,0); + a[1].Set(1,2); + //--- check + if(_spoil_scenario==0) + Spoil_Matrix_By_Value(a,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Matrix_By_Value(a,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Matrix_By_Value(a,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Matrix_By_Deleting_Row(a); + //--- check + if(_spoil_scenario==4) + Spoil_Matrix_By_Deleting_Col(a); + //--- allocation + ArrayResize(b,2); + //--- initialization + b[0]=-6; + b[1]=-4; + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(b,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Value(b,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Value(b,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==8) + Spoil_Vector_By_Deleting_Element(b); + //--- allocation + ArrayResize(x0,2); + //--- initialization + x0[0]=0; + x0[1]=1; + //--- check + if(_spoil_scenario==9) + Spoil_Vector_By_Value(x0,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==10) + Spoil_Vector_By_Value(x0,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==11) + Spoil_Vector_By_Value(x0,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==12) + Spoil_Vector_By_Deleting_Element(x0); + //--- create variables + CMinQPStateShell state; + CMinQPReportShell rep; + //--- function call + CAlglib::MinQPCreate(2,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinQPSetQuadraticTerm(state,a); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinQPSetLinearTerm(state,b); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinQPSetStartingPoint(state,x0); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinQPOptimize(state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinQPResults(state,x,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,2); + //--- initialization + temparray[0]=3; + temparray[1]=2; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(rep.GetTerminationType(),4); + _TestResult=_TestResult && Doc_Test_Real_Vector(x,temparray,0.005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","minqp_d_u1"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Constrained dense quadratic programming | +//+------------------------------------------------------------------+ +void TEST_MinQP_D_BC1(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + CMatrixDouble a; + double b[]; + double x0[]; + double bndl[]; + double bndu[]; + double temparray[]; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<17;_spoil_scenario++) + { + //--- 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)! + a.Resize(2,2); + //--- initialization + a[0].Set(0,2); + a[0].Set(1,0); + a[1].Set(0,0); + a[1].Set(1,2); + //--- check + if(_spoil_scenario==0) + Spoil_Matrix_By_Value(a,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Matrix_By_Value(a,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Matrix_By_Value(a,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Matrix_By_Deleting_Row(a); + //--- check + if(_spoil_scenario==4) + Spoil_Matrix_By_Deleting_Col(a); + //--- allocation + ArrayResize(b,2); + //--- initialization + b[0]=-6; + b[1]=-4; + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(b,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Value(b,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Value(b,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==8) + Spoil_Vector_By_Deleting_Element(b); + //--- allocation + ArrayResize(x0,2); + //--- initialization + x0[0]=0; + x0[1]=1; + //--- check + if(_spoil_scenario==9) + Spoil_Vector_By_Value(x0,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==10) + Spoil_Vector_By_Value(x0,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==11) + Spoil_Vector_By_Value(x0,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==12) + Spoil_Vector_By_Deleting_Element(x0); + //--- allocation + ArrayResize(bndl,2); + //--- initialization + bndl[0]=0; + bndl[1]=0; + //--- check + if(_spoil_scenario==13) + Spoil_Vector_By_Value(bndl,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==14) + Spoil_Vector_By_Deleting_Element(bndl); + //--- allocation + ArrayResize(bndu,2); + //--- initialization + bndu[0]=2.5; + bndu[1]=2.5; + //--- check + if(_spoil_scenario==15) + Spoil_Vector_By_Value(bndu,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==16) + Spoil_Vector_By_Deleting_Element(bndu); + double x[]; + CMinQPStateShell state; + CMinQPReportShell rep; + //--- function call + CAlglib::MinQPCreate(2,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinQPSetQuadraticTerm(state,a); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinQPSetLinearTerm(state,b); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinQPSetStartingPoint(state,x0); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinQPSetBC(state,bndl,bndu); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinQPOptimize(state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinQPResults(state,x,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,2); + //--- initialization + temparray[0]=2.5; + temparray[1]=2; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(rep.GetTerminationType(),4); + _TestResult=_TestResult && Doc_Test_Real_Vector(x,temparray,0.005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","minqp_d_bc1"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Nonlinear least squares optimization using function vector only | +//+------------------------------------------------------------------+ +void TEST_MinLM_D_V(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double temparray[]; + CObject obj; + CNDimensional_FVec1 ffvec; + CNDimensional_Rep frep; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<12;_spoil_scenario++) + { + //--- 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. + ArrayResize(x,2); + //--- initialization + x[0]=0; + x[1]=0; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + double epsg=0.0000000001; + //--- check + if(_spoil_scenario==3) + epsg=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==4) + epsg=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==5) + epsg=CInfOrNaN::NegativeInfinity(); + double epsf=0; + //--- check + if(_spoil_scenario==6) + epsf=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==7) + epsf=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==8) + epsf=CInfOrNaN::NegativeInfinity(); + double epsx=0; + //--- check + if(_spoil_scenario==9) + epsx=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==10) + epsx=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==11) + epsx=CInfOrNaN::NegativeInfinity(); + int maxits=0; + //--- objects of classes + CMinLMStateShell state; + CMinLMReportShell rep; + //--- function call + CAlglib::MinLMCreateV(2,x,0.0001,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMSetCond(state,epsg,epsf,epsx,maxits); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMOptimize(state,ffvec,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMResults(state,x,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,2); + //--- initialization + temparray[0]=-3; + temparray[1]=3; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(rep.GetTerminationType(),4); + _TestResult=_TestResult && Doc_Test_Real_Vector(x,temparray,0.005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","minlm_d_v"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Nonlinear least squares optimization using function vector and | +//| Jacobian | +//+------------------------------------------------------------------+ +void TEST_MinLM_D_VJ(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { +//--- TEST minlm_d_vj +//--- Nonlinear least squares optimization using function vector and Jacobian + _TestResult=true; +//--- create variables + double x[]; + double temparray[]; + CObject obj; + CNDimensional_FVec1 ffvec; + CNDimensional_Jac1 fjac; + CNDimensional_Rep frep; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<12;_spoil_scenario++) + { + //--- 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}. + ArrayResize(x,2); + //--- initialization + x[0]=0; + x[1]=0; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + double epsg=0.0000000001; + //--- check + if(_spoil_scenario==3) + epsg=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==4) + epsg=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==5) + epsg=CInfOrNaN::NegativeInfinity(); + double epsf=0; + //--- check + if(_spoil_scenario==6) + epsf=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==7) + epsf=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==8) + epsf=CInfOrNaN::NegativeInfinity(); + double epsx=0; + //--- check + if(_spoil_scenario==9) + epsx=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==10) + epsx=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==11) + epsx=CInfOrNaN::NegativeInfinity(); + //--- create variables + int maxits=0; + CMinLMStateShell state; + CMinLMReportShell rep; + //--- function call + CAlglib::MinLMCreateVJ(2,x,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMSetCond(state,epsg,epsf,epsx,maxits); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMOptimize(state,ffvec,fjac,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMResults(state,x,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,2); + //--- initialization + temparray[0]=-3; + temparray[1]=3; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(rep.GetTerminationType(),4); + _TestResult=_TestResult && Doc_Test_Real_Vector(x,temparray,0.005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","minlm_d_vj"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Nonlinear Hessian-based optimization for general functions | +//+------------------------------------------------------------------+ +void TEST_MinLM_D_FGH(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double temparray[]; + CObject obj; + CNDimensional_Func1 ffunc; + CNDimensional_Grad1 fgrad; + CNDimensional_Hess1 fhess; + CNDimensional_Rep frep; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<12;_spoil_scenario++) + { + //--- 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 withinternal 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)} + ArrayResize(x,2); + //--- initialization + x[0]=0; + x[1]=0; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + double epsg=0.0000000001; + //--- check + if(_spoil_scenario==3) + epsg=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==4) + epsg=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==5) + epsg=CInfOrNaN::NegativeInfinity(); + double epsf=0; + //--- check + if(_spoil_scenario==6) + epsf=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==7) + epsf=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==8) + epsf=CInfOrNaN::NegativeInfinity(); + double epsx=0; + //--- check + if(_spoil_scenario==9) + epsx=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==10) + epsx=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==11) + epsx=CInfOrNaN::NegativeInfinity(); + //--- create variables + int maxits=0; + CMinLMStateShell state; + CMinLMReportShell rep; + //--- function call + CAlglib::MinLMCreateFGH(x,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMSetCond(state,epsg,epsf,epsx,maxits); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMOptimize(state,ffunc,fgrad,fhess,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMResults(state,x,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,2); + //--- initialization + temparray[0]=-3; + temparray[1]=3; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(rep.GetTerminationType(),4); + _TestResult=_TestResult && Doc_Test_Real_Vector(x,temparray,0.005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","minlm_d_fgh"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Bound constrained nonlinear least squares optimization | +//+------------------------------------------------------------------+ +void TEST_MinLM_D_VB(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double bndl[]; + double bndu[]; + double temparray[]; + CObject obj; + CNDimensional_FVec1 ffvec; + CNDimensional_Rep frep; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<16;_spoil_scenario++) + { + //--- 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. + ArrayResize(x,2); + //--- initialization + x[0]=0; + x[1]=0; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- allocation + ArrayResize(bndl,2); + //--- initialization + bndl[0]=-1; + bndl[1]=-1; + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Value(bndl,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==4) + Spoil_Vector_By_Deleting_Element(bndl); + //--- allocation + ArrayResize(bndu,2); + //--- initialization + bndu[0]=1; + bndu[1]=1; + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(bndu,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Deleting_Element(bndu); + double epsg=0.0000000001; + //--- check + if(_spoil_scenario==7) + epsg=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==8) + epsg=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==9) + epsg=CInfOrNaN::NegativeInfinity(); + double epsf=0; + //--- check + if(_spoil_scenario==10) + epsf=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==11) + epsf=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==12) + epsf=CInfOrNaN::NegativeInfinity(); + double epsx=0; + //--- check + if(_spoil_scenario==13) + epsx=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==14) + epsx=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==15) + epsx=CInfOrNaN::NegativeInfinity(); + //--- create variables + int maxits=0; + CMinLMStateShell state; + CMinLMReportShell rep; + //--- function call + CAlglib::MinLMCreateV(2,x,0.0001,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMSetBC(state,bndl,bndu); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMSetCond(state,epsg,epsf,epsx,maxits); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMOptimize(state,ffvec,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMResults(state,x,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,2); + //--- initialization + temparray[0]=-1; + temparray[1]=1; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(rep.GetTerminationType(),4); + _TestResult=_TestResult && Doc_Test_Real_Vector(x,temparray,0.005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","minlm_d_vb"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Efficient restarts of LM optimizer | +//+------------------------------------------------------------------+ +void TEST_MinLM_D_Restarts(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double temparray[]; + CObject obj; + CNDimensional_FVec1 ffvec1; + CNDimensional_FVec2 ffvec2; + CNDimensional_Rep frep; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<15;_spoil_scenario++) + { + //--- 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. + double epsg=0.0000000001; + //--- check + if(_spoil_scenario==0) + epsg=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==1) + epsg=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==2) + epsg=CInfOrNaN::NegativeInfinity(); + double epsf=0; + //--- check + if(_spoil_scenario==3) + epsf=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==4) + epsf=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==5) + epsf=CInfOrNaN::NegativeInfinity(); + double epsx=0; + //--- check + if(_spoil_scenario==6) + epsx=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==7) + epsx=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==8) + epsx=CInfOrNaN::NegativeInfinity(); + //--- create variables + int maxits=0; + CMinLMStateShell state; + CMinLMReportShell rep; + //--- create optimizer using minlmcreatev() + ArrayResize(x,2); + //--- initialization + x[0]=10; + x[1]=10; + //--- check + if(_spoil_scenario==9) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==10) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==11) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- function call + CAlglib::MinLMCreateV(2,x,0.0001,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMSetCond(state,epsg,epsf,epsx,maxits); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMOptimize(state,ffvec1,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMResults(state,x,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,2); + //--- initialization + temparray[0]=-3; + temparray[1]=3; + //--- check result + _TestResult=_TestResult && Doc_Test_Real_Vector(x,temparray,0.005); + //--- restart optimizer using minlmrestartfrom() + //--- we can use different starting point,different function, + //--- different stopping conditions,but problem size + //--- must remain unchanged. + ArrayResize(x,2); + //--- initialization + x[0]=4; + x[1]=4; + //--- check + if(_spoil_scenario==12) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==13) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==14) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- function call + CAlglib::MinLMRestartFrom(state,x); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMOptimize(state,ffvec2,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMResults(state,x,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,2); + //--- initialization + temparray[0]=0; + temparray[1]=1; + //--- check result + _TestResult=_TestResult && Doc_Test_Real_Vector(x,temparray,0.005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","minlm_d_restarts"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Nonlinear least squares optimization, FJ scheme (obsolete, but | +//| supported) | +//+------------------------------------------------------------------+ +void TEST_MinLM_T_1(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double temparray[]; + CObject obj; + CNDimensional_Func1 ffunc; + CNDimensional_Jac1 fjac; + CNDimensional_Rep frep; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<12;_spoil_scenario++) + { + //--- allocation + ArrayResize(x,2); + //--- initialization + x[0]=0; + x[1]=0; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + double epsg=0.0000000001; + //--- check + if(_spoil_scenario==3) + epsg=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==4) + epsg=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==5) + epsg=CInfOrNaN::NegativeInfinity(); + double epsf=0; + //--- check + if(_spoil_scenario==6) + epsf=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==7) + epsf=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==8) + epsf=CInfOrNaN::NegativeInfinity(); + double epsx=0; + //--- check + if(_spoil_scenario==9) + epsx=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==10) + epsx=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==11) + epsx=CInfOrNaN::NegativeInfinity(); + int maxits=0; + CMinLMStateShell state; + CMinLMReportShell rep; + //--- function call + CAlglib::MinLMCreateFJ(2,x,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMSetCond(state,epsg,epsf,epsx,maxits); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMOptimize(state,ffunc,fjac,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMResults(state,x,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,2); + //--- initialization + temparray[0]=-3; + temparray[1]=3; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(rep.GetTerminationType(),4); + _TestResult=_TestResult && Doc_Test_Real_Vector(x,temparray,0.005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","minlm_t_1"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Nonlinear least squares optimization, FGJ scheme (obsolete, but | +//| supported) | +//+------------------------------------------------------------------+ +void TEST_MinLM_T_2(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double temparray[]; + CObject obj; + CNDimensional_Func1 ffunc; + CNDimensional_Grad1 fgrad; + CNDimensional_Jac1 fjac; + CNDimensional_Rep frep; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<12;_spoil_scenario++) + { + //--- allocation + ArrayResize(x,2); + //--- initialization + x[0]=0; + x[1]=0; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + double epsg=0.0000000001; + //--- check + if(_spoil_scenario==3) + epsg=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==4) + epsg=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==5) + epsg=CInfOrNaN::NegativeInfinity(); + double epsf=0; + //--- check + if(_spoil_scenario==6) + epsf=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==7) + epsf=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==8) + epsf=CInfOrNaN::NegativeInfinity(); + double epsx=0; + //--- check + if(_spoil_scenario==9) + epsx=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==10) + epsx=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==11) + epsx=CInfOrNaN::NegativeInfinity(); + //--- create variables + int maxits=0; + CMinLMStateShell state; + CMinLMReportShell rep; + //--- function call + CAlglib::MinLMCreateFGJ(2,x,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMSetCond(state,epsg,epsf,epsx,maxits); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMOptimize(state,ffunc,fgrad,fjac,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::MinLMResults(state,x,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,2); + //--- initialization + temparray[0]=-3; + temparray[1]=3; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(rep.GetTerminationType(),4); + _TestResult=_TestResult && Doc_Test_Real_Vector(x,temparray,0.005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","minlm_t_2"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Nonlinear fitting using function value only | +//+------------------------------------------------------------------+ +void TEST_LSFit_D_NLF(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + CMatrixDouble x; + double y[]; + double c[]; + double temparray[]; + double w[]; + CObject obj; + CNDimensional_CX_1_Func fcx1func; + CNDimensional_Rep frep; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<27;_spoil_scenario++) + { + //--- 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). + x.Resize(11,1); + //--- initialization + x[0].Set(0,-1); + x[1].Set(0,-0.8); + x[2].Set(0,-0.6); + x[3].Set(0,-0.4); + x[4].Set(0,-0.2); + x[5].Set(0,0); + x[6].Set(0,0.2); + x[7].Set(0,0.4); + x[8].Set(0,0.6); + x[9].Set(0,0.8); + x[10].Set(0,1); + //--- check + if(_spoil_scenario==0) + Spoil_Matrix_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Matrix_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Matrix_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Matrix_By_Deleting_Row(x); + //--- check + if(_spoil_scenario==4) + Spoil_Matrix_By_Deleting_Col(x); + //--- allocation + ArrayResize(y,11); + //--- initialization + y[0]=0.22313; + y[1]=0.382893; + y[2]=0.582748; + y[3]=0.786628; + y[4]=0.941765; + y[5]=1; + y[6]=0.941765; + y[7]=0.786628; + y[8]=0.582748; + y[9]=0.382893; + y[10]=0.22313; + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==8) + Spoil_Vector_By_Adding_Element(y); + //--- check + if(_spoil_scenario==9) + Spoil_Vector_By_Deleting_Element(y); + //--- allocation + ArrayResize(c,1); + //--- initialization + c[0]=0.3; + //--- check + if(_spoil_scenario==10) + Spoil_Vector_By_Value(c,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==11) + Spoil_Vector_By_Value(c,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==12) + Spoil_Vector_By_Value(c,CInfOrNaN::NegativeInfinity()); + double epsf=0; + //--- check + if(_spoil_scenario==13) + epsf=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==14) + epsf=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==15) + epsf=CInfOrNaN::NegativeInfinity(); + double epsx=0.000001; + //--- check + if(_spoil_scenario==16) + epsx=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==17) + epsx=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==18) + epsx=CInfOrNaN::NegativeInfinity(); + //--- create variables + int maxits=0; + int info; + CLSFitStateShell state; + CLSFitReportShell rep; + double diffstep=0.0001; + //--- check + if(_spoil_scenario==19) + diffstep=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==20) + diffstep=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==21) + diffstep=CInfOrNaN::NegativeInfinity(); + //--- Fitting withweights + CAlglib::LSFitCreateF(x,y,c,diffstep,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitSetCond(state,epsf,epsx,maxits); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitFit(state,fcx1func,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitResults(state,info,c,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,1); + //--- initialization + temparray[0]=1.5; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(info,2); + _TestResult=_TestResult && Doc_Test_Real_Vector(c,temparray,0.05); + //--- Fitting with weights + //--- (you can change weights and see how it changes result) + ArrayResize(w,11); + //--- initialization + w[0]=1; + w[1]=1; + w[2]=1; + w[3]=1; + w[4]=1; + w[5]=1; + w[6]=1; + w[7]=1; + w[8]=1; + w[9]=1; + w[10]=1; + //--- check + if(_spoil_scenario==22) + Spoil_Vector_By_Value(w,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==23) + Spoil_Vector_By_Value(w,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==24) + Spoil_Vector_By_Value(w,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==25) + Spoil_Vector_By_Adding_Element(w); + //--- check + if(_spoil_scenario==26) + Spoil_Vector_By_Deleting_Element(w); + //--- function call + CAlglib::LSFitCreateWF(x,y,w,c,diffstep,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitSetCond(state,epsf,epsx,maxits); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitFit(state,fcx1func,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitResults(state,info,c,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,1); + //--- initialization + temparray[0]=1.5; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(info,2); + _TestResult=_TestResult && Doc_Test_Real_Vector(c,temparray,0.05); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","lsfit_d_nlf"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Nonlinear fitting using gradient | +//+------------------------------------------------------------------+ +void TEST_LSFit_D_NLFG(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + CMatrixDouble x; + double y[]; + double c[]; + double temparray[]; + double w[]; + CObject obj; + CNDimensional_CX_1_Func fcx1func; + CNDimensional_CX_1_Grad fcx1grad; + CNDimensional_Rep frep; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<24;_spoil_scenario++) + { + //--- In this example we demonstrate exponential fitting + //--- by f(x)=exp(-c*x^2) + //--- using function value and gradient (with respect to c). + x.Resize(11,1); + //--- initialization + x[0].Set(0,-1); + x[1].Set(0,-0.8); + x[2].Set(0,-0.6); + x[3].Set(0,-0.4); + x[4].Set(0,-0.2); + x[5].Set(0,0); + x[6].Set(0,0.2); + x[7].Set(0,0.4); + x[8].Set(0,0.6); + x[9].Set(0,0.8); + x[10].Set(0,1); + //--- check + if(_spoil_scenario==0) + Spoil_Matrix_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Matrix_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Matrix_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Matrix_By_Deleting_Row(x); + //--- check + if(_spoil_scenario==4) + Spoil_Matrix_By_Deleting_Col(x); + //--- allocation + ArrayResize(y,11); + //--- initialization + y[0]=0.22313; + y[1]=0.382893; + y[2]=0.582748; + y[3]=0.786628; + y[4]=0.941765; + y[5]=1; + y[6]=0.941765; + y[7]=0.786628; + y[8]=0.582748; + y[9]=0.382893; + y[10]=0.22313; + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==8) + Spoil_Vector_By_Adding_Element(y); + //--- check + if(_spoil_scenario==9) + Spoil_Vector_By_Deleting_Element(y); + //--- allocation + ArrayResize(c,1); + //--- initialization + c[0]=0.3; + //--- check + if(_spoil_scenario==10) + Spoil_Vector_By_Value(c,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==11) + Spoil_Vector_By_Value(c,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==12) + Spoil_Vector_By_Value(c,CInfOrNaN::NegativeInfinity()); + double epsf=0; + //--- check + if(_spoil_scenario==13) + epsf=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==14) + epsf=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==15) + epsf=CInfOrNaN::NegativeInfinity(); + double epsx=0.000001; + //--- check + if(_spoil_scenario==16) + epsx=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==17) + epsx=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==18) + epsx=CInfOrNaN::NegativeInfinity(); + //--- create variables + int maxits=0; + int info; + CLSFitStateShell state; + CLSFitReportShell rep; + //--- Fitting withweights + CAlglib::LSFitCreateFG(x,y,c,true,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitSetCond(state,epsf,epsx,maxits); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitFit(state,fcx1func,fcx1grad,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitResults(state,info,c,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,1); + //--- initialization + temparray[0]=1.5; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(info,2); + _TestResult=_TestResult && Doc_Test_Real_Vector(c,temparray,0.05); + //--- Fitting with weights + //--- (you can change weights and see how it changes result) + ArrayResize(w,11); + //--- initialization + w[0]=1; + w[1]=1; + w[2]=1; + w[3]=1; + w[4]=1; + w[5]=1; + w[6]=1; + w[7]=1; + w[8]=1; + w[9]=1; + w[10]=1; + //--- check + if(_spoil_scenario==19) + Spoil_Vector_By_Value(w,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==20) + Spoil_Vector_By_Value(w,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==21) + Spoil_Vector_By_Value(w,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==22) + Spoil_Vector_By_Adding_Element(w); + //--- check + if(_spoil_scenario==23) + Spoil_Vector_By_Deleting_Element(w); + //--- function call + CAlglib::LSFitCreateWFG(x,y,w,c,true,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitSetCond(state,epsf,epsx,maxits); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitFit(state,fcx1func,fcx1grad,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitResults(state,info,c,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,1); + //--- initialization + temparray[0]=1.5; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(info,2); + _TestResult=_TestResult && Doc_Test_Real_Vector(c,temparray,0.05); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","lsfit_d_nlfg"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Nonlinear fitting using gradient and Hessian | +//+------------------------------------------------------------------+ +void TEST_LSFit_D_NLFGH(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + CMatrixDouble x; + double y[]; + double c[]; + double temparray[]; + double w[]; + CObject obj; + CNDimensional_CX_1_Func fcx1func; + CNDimensional_CX_1_Grad fcx1grad; + CNDimensional_CX_1_Hess fcx1hess; + CNDimensional_Rep frep; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<24;_spoil_scenario++) + { + //--- In this example we demonstrate exponential fitting + //--- by f(x)=exp(-c*x^2) + //--- using function value,gradient and Hessian (with respect to c) + x.Resize(11,1); + //--- initialization + x[0].Set(0,-1); + x[1].Set(0,-0.8); + x[2].Set(0,-0.6); + x[3].Set(0,-0.4); + x[4].Set(0,-0.2); + x[5].Set(0,0); + x[6].Set(0,0.2); + x[7].Set(0,0.4); + x[8].Set(0,0.6); + x[9].Set(0,0.8); + x[10].Set(0,1); + //--- check + if(_spoil_scenario==0) + Spoil_Matrix_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Matrix_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Matrix_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Matrix_By_Deleting_Row(x); + //--- check + if(_spoil_scenario==4) + Spoil_Matrix_By_Deleting_Col(x); + //--- allocation + ArrayResize(y,11); + //--- initialization + y[0]=0.22313; + y[1]=0.382893; + y[2]=0.582748; + y[3]=0.786628; + y[4]=0.941765; + y[5]=1; + y[6]=0.941765; + y[7]=0.786628; + y[8]=0.582748; + y[9]=0.382893; + y[10]=0.22313; + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==8) + Spoil_Vector_By_Adding_Element(y); + //--- check + if(_spoil_scenario==9) + Spoil_Vector_By_Deleting_Element(y); + //--- allocation + ArrayResize(c,1); + //--- initialization + c[0]=0.3; + //--- check + if(_spoil_scenario==10) + Spoil_Vector_By_Value(c,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==11) + Spoil_Vector_By_Value(c,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==12) + Spoil_Vector_By_Value(c,CInfOrNaN::NegativeInfinity()); + double epsf=0; + //--- check + if(_spoil_scenario==13) + epsf=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==14) + epsf=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==15) + epsf=CInfOrNaN::NegativeInfinity(); + double epsx=0.000001; + //--- check + if(_spoil_scenario==16) + epsx=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==17) + epsx=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==18) + epsx=CInfOrNaN::NegativeInfinity(); + //--- create variables + int maxits=0; + int info; + CLSFitStateShell state; + CLSFitReportShell rep; + //--- Fitting withweights + CAlglib::LSFitCreateFGH(x,y,c,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitSetCond(state,epsf,epsx,maxits); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitFit(state,fcx1func,fcx1grad,fcx1hess,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitResults(state,info,c,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,1); + //--- initialization + temparray[0]=1.5; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(info,2); + _TestResult=_TestResult && Doc_Test_Real_Vector(c,temparray,0.05); + //--- Fitting with weights + //--- (you can change weights and see how it changes result) + ArrayResize(w,11); + //--- initialization + w[0]=1; + w[1]=1; + w[2]=1; + w[3]=1; + w[4]=1; + w[5]=1; + w[6]=1; + w[7]=1; + w[8]=1; + w[9]=1; + w[10]=1; + //--- check + if(_spoil_scenario==19) + Spoil_Vector_By_Value(w,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==20) + Spoil_Vector_By_Value(w,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==21) + Spoil_Vector_By_Value(w,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==22) + Spoil_Vector_By_Adding_Element(w); + //--- check + if(_spoil_scenario==23) + Spoil_Vector_By_Deleting_Element(w); + //--- function call + CAlglib::LSFitCreateWFGH(x,y,w,c,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitSetCond(state,epsf,epsx,maxits); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitFit(state,fcx1func,fcx1grad,fcx1hess,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitResults(state,info,c,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,1); + //--- initialization + temparray[0]=1.5; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(info,2); + _TestResult=_TestResult && Doc_Test_Real_Vector(c,temparray,0.05); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","lsfit_d_nlfgh"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Bound contstrained nonlinear fitting using function value only | +//+------------------------------------------------------------------+ +void TEST_LSFit_D_NLFB(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + CMatrixDouble x; + double y[]; + double c[]; + double temparray[]; + double w[]; + double bndl[]; + double bndu[]; + CObject obj; + CNDimensional_CX_1_Func fcx1func; + CNDimensional_Rep frep; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<26;_spoil_scenario++) + { + //--- 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). + x.Resize(11,1); + //--- initialization + x[0].Set(0,-1); + x[1].Set(0,-0.8); + x[2].Set(0,-0.6); + x[3].Set(0,-0.4); + x[4].Set(0,-0.2); + x[5].Set(0,0); + x[6].Set(0,0.2); + x[7].Set(0,0.4); + x[8].Set(0,0.6); + x[9].Set(0,0.8); + x[10].Set(0,1); + //--- check + if(_spoil_scenario==0) + Spoil_Matrix_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Matrix_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Matrix_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Matrix_By_Deleting_Row(x); + //--- check + if(_spoil_scenario==4) + Spoil_Matrix_By_Deleting_Col(x); + //--- allocation + ArrayResize(y,11); + //--- initialization + y[0]=0.22313; + y[1]=0.382893; + y[2]=0.582748; + y[3]=0.786628; + y[4]=0.941765; + y[5]=1; + y[6]=0.941765; + y[7]=0.786628; + y[8]=0.582748; + y[9]=0.382893; + y[10]=0.22313; + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==8) + Spoil_Vector_By_Adding_Element(y); + //--- check + if(_spoil_scenario==9) + Spoil_Vector_By_Deleting_Element(y); + //--- allocation + ArrayResize(c,1); + //--- initialization + c[0]=0.3; + //--- check + if(_spoil_scenario==10) + Spoil_Vector_By_Value(c,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==11) + Spoil_Vector_By_Value(c,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==12) + Spoil_Vector_By_Value(c,CInfOrNaN::NegativeInfinity()); + //--- allocation + ArrayResize(bndl,1); + //--- initialization + bndl[0]=0; + //--- check + if(_spoil_scenario==13) + Spoil_Vector_By_Value(bndl,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==14) + Spoil_Vector_By_Deleting_Element(bndl); + //--- allocation + ArrayResize(bndu,1); + //--- initialization + bndu[0]=1; + //--- check + if(_spoil_scenario==15) + Spoil_Vector_By_Value(bndu,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==16) + Spoil_Vector_By_Deleting_Element(bndu); + double epsf=0; + //--- check + if(_spoil_scenario==17) + epsf=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==18) + epsf=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==19) + epsf=CInfOrNaN::NegativeInfinity(); + double epsx=0.000001; + //--- check + if(_spoil_scenario==20) + epsx=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==21) + epsx=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==22) + epsx=CInfOrNaN::NegativeInfinity(); + //--- create variables + int maxits=0; + int info; + CLSFitStateShell state; + CLSFitReportShell rep; + double diffstep=0.0001; + //--- check + if(_spoil_scenario==23) + diffstep=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==24) + diffstep=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==25) + diffstep=CInfOrNaN::NegativeInfinity(); + //--- function call + CAlglib::LSFitCreateF(x,y,c,diffstep,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitSetBC(state,bndl,bndu); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitSetCond(state,epsf,epsx,maxits); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitFit(state,fcx1func,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitResults(state,info,c,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,1); + //--- initialization + temparray[0]=1; + //--- check result + _TestResult=_TestResult && Doc_Test_Real_Vector(c,temparray,0.05); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","lsfit_d_nlfb"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Nonlinear fitting with custom scaling and bound constraints | +//+------------------------------------------------------------------+ +void TEST_LSFit_D_NLScale(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + CMatrixDouble x; + double y[]; + double c[]; + double bndl[]; + double bndu[]; + double s[]; + double temparray[]; + CObject obj; + CNDimensional_Debt_Func fdebtfunc; + CNDimensional_Rep frep; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<30;_spoil_scenario++) + { + //--- 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 ab1 in + //--- magnitude. Such problem is difficult to solve withsome + //--- 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 lsfitsetscale() call - and you will + //--- see that algorithm will fail to converge. + x.Resize(9,1); + //--- initialization + x[0].Set(0,2000); + x[1].Set(0,2001); + x[2].Set(0,2002); + x[3].Set(0,2003); + x[4].Set(0,2004); + x[5].Set(0,2005); + x[6].Set(0,2006); + x[7].Set(0,2007); + x[8].Set(0,2008); + //--- check + if(_spoil_scenario==0) + Spoil_Matrix_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Matrix_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Matrix_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Matrix_By_Deleting_Row(x); + //--- check + if(_spoil_scenario==4) + Spoil_Matrix_By_Deleting_Col(x); + //--- allocation + ArrayResize(y,9); + //--- initialization + y[0]=4323239600000.0; + y[1]=4560913100000.0; + y[2]=5564091500000.0; + y[3]=6743189300000.0; + y[4]=7284064600000.0; + y[5]=7050129600000.0; + y[6]=7092221500000.0; + y[7]=8483907600000.0; + y[8]=8625804400000.0; + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==8) + Spoil_Vector_By_Adding_Element(y); + //--- check + if(_spoil_scenario==9) + Spoil_Vector_By_Deleting_Element(y); + //--- allocation + ArrayResize(c,3); + //--- initialization + c[0]=1.0e+13; + c[1]=1; + c[2]=1; + //--- check + if(_spoil_scenario==10) + Spoil_Vector_By_Value(c,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==11) + Spoil_Vector_By_Value(c,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==12) + Spoil_Vector_By_Value(c,CInfOrNaN::NegativeInfinity()); + double epsf=0; + //--- check + if(_spoil_scenario==13) + epsf=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==14) + epsf=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==15) + epsf=CInfOrNaN::NegativeInfinity(); + double epsx=1.0e-5; + //--- check + if(_spoil_scenario==16) + epsx=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==17) + epsx=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==18) + epsx=CInfOrNaN::NegativeInfinity(); + //--- allocation + ArrayResize(bndl,3); + //--- initialization + bndl[0]=-CInfOrNaN::PositiveInfinity(); + bndl[1]=-10; + bndl[2]=0.1; + //--- check + if(_spoil_scenario==19) + Spoil_Vector_By_Value(bndl,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==20) + Spoil_Vector_By_Deleting_Element(bndl); + //--- allocation + ArrayResize(bndu,3); + //--- initialization + bndu[0]=CInfOrNaN::PositiveInfinity(); + bndu[1]=10; + bndu[2]=2; + //--- check + if(_spoil_scenario==21) + Spoil_Vector_By_Value(bndu,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==22) + Spoil_Vector_By_Deleting_Element(bndu); + //--- allocation + ArrayResize(s,3); + //--- initialization + s[0]=1.0e+12; + s[1]=1; + s[2]=1; + //--- check + if(_spoil_scenario==23) + Spoil_Vector_By_Value(s,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==24) + Spoil_Vector_By_Value(s,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==25) + Spoil_Vector_By_Value(s,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==26) + Spoil_Vector_By_Deleting_Element(s); + //--- create variables + int maxits=0; + int info; + CLSFitStateShell state; + CLSFitReportShell rep; + double diffstep=1.0e-5; + //--- check + if(_spoil_scenario==27) + diffstep=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==28) + diffstep=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==29) + diffstep=CInfOrNaN::NegativeInfinity(); + //--- function call + CAlglib::LSFitCreateF(x,y,c,diffstep,state); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitSetCond(state,epsf,epsx,maxits); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitSetBC(state,bndl,bndu); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitSetScale(state,s); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitFit(state,fdebtfunc,frep,0,obj); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + CAlglib::LSFitResults(state,info,c,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,3); + //--- initialization + temparray[0]=4.142560e+12; + temparray[1]=0.43424; + temparray[2]=0.565376; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(info,2); + _TestResult=_TestResult && Doc_Test_Real_Vector(c,temparray,-0.005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","lsfit_d_nlscale"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Unconstrained (general) linear least squares fitting with and | +//| withweights | +//+------------------------------------------------------------------+ +void TEST_LSFit_D_Lin(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + CMatrixDouble fmatrix; + int info; + double c[]; + double y[]; + double temparray[]; + double w[]; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<13;_spoil_scenario++) + { + //--- 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). + fmatrix.Resize(11,1); + //--- initialization + fmatrix[0].Set(0,0.606531); + fmatrix[1].Set(0,0.67032); + fmatrix[2].Set(0,0.740818); + fmatrix[3].Set(0,0.818731); + fmatrix[4].Set(0,0.904837); + fmatrix[5].Set(0,1); + fmatrix[6].Set(0,1.105171); + fmatrix[7].Set(0,1.221403); + fmatrix[8].Set(0,1.349859); + fmatrix[9].Set(0,1.491825); + fmatrix[10].Set(0,1.648721); + //--- check + if(_spoil_scenario==0) + Spoil_Matrix_By_Value(fmatrix,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Matrix_By_Value(fmatrix,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Matrix_By_Value(fmatrix,CInfOrNaN::NegativeInfinity()); + //--- allocation + ArrayResize(y,11); + //--- initialization + y[0]=1.133719; + y[1]=1.306522; + y[2]=1.504604; + y[3]=1.554663; + y[4]=1.884638; + y[5]=2.072436; + y[6]=2.257285; + y[7]=2.534068; + y[8]=2.622017; + y[9]=2.897713; + y[10]=3.219371; + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==4) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Adding_Element(y); + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Deleting_Element(y); + //--- create a variable + CLSFitReportShell rep; + //--- Linear fitting withweights + CAlglib::LSFitLinear(y,fmatrix,info,c,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,1); + //--- initialization + temparray[0]=1.9865; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(info,1); + _TestResult=_TestResult && Doc_Test_Real_Vector(c,temparray,0.00005); + //--- Linear fitting with individual weights. + //--- Slightly different result is returned. + ArrayResize(w,11); + //--- initialization + w[0]=1.414213; + w[1]=1; + w[2]=1; + w[3]=1; + w[4]=1; + w[5]=1; + w[6]=1; + w[7]=1; + w[8]=1; + w[9]=1; + w[10]=1; + //--- check + if(_spoil_scenario==8) + Spoil_Vector_By_Value(w,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==9) + Spoil_Vector_By_Value(w,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==10) + Spoil_Vector_By_Value(w,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==11) + Spoil_Vector_By_Adding_Element(w); + //--- check + if(_spoil_scenario==12) + Spoil_Vector_By_Deleting_Element(w); + //--- function call + CAlglib::LSFitLinearW(y,w,fmatrix,info,c,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,1); + //--- initialization + temparray[0]=1.983354; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(info,1); + _TestResult=_TestResult && Doc_Test_Real_Vector(c,temparray,0.00005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","lsfit_d_lin"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Constrained (general) linear least squares fitting with and | +//| withweights | +//+------------------------------------------------------------------+ +void TEST_LSFit_D_Linc(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + CMatrixDouble fmatrix; + CMatrixDouble cmatrix; + double y[]; + double c[]; + double temparray[]; + double w[]; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<20;_spoil_scenario++) + { + //--- 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" + ArrayResize(y,6); + //--- initialization + y[0]=0.072436; + y[1]=0.246944; + y[2]=0.491263; + y[3]=0.5223; + y[4]=0.714064; + y[5]=0.921929; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Adding_Element(y); + //--- check + if(_spoil_scenario==4) + Spoil_Vector_By_Deleting_Element(y); + //--- allocation + fmatrix.Resize(6,2); + //--- initialization + fmatrix[0].Set(0,1); + fmatrix[0].Set(1,0); + fmatrix[1].Set(0,1); + fmatrix[1].Set(1,0.2); + fmatrix[2].Set(0,1); + fmatrix[2].Set(1,0.4); + fmatrix[3].Set(0,1); + fmatrix[3].Set(1,0.6); + fmatrix[4].Set(0,1); + fmatrix[4].Set(1,0.8); + fmatrix[5].Set(0,1); + fmatrix[5].Set(1,1); + //--- check + if(_spoil_scenario==5) + Spoil_Matrix_By_Value(fmatrix,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==6) + Spoil_Matrix_By_Value(fmatrix,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==7) + Spoil_Matrix_By_Value(fmatrix,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==8) + Spoil_Matrix_By_Adding_Row(fmatrix); + //--- check + if(_spoil_scenario==9) + Spoil_Matrix_By_Adding_Col(fmatrix); + //--- check + if(_spoil_scenario==10) + Spoil_Matrix_By_Deleting_Row(fmatrix); + //--- check + if(_spoil_scenario==11) + Spoil_Matrix_By_Deleting_Col(fmatrix); + //--- allocation + cmatrix.Resize(1,3); + //--- initialization + cmatrix[0].Set(0,1); + cmatrix[0].Set(1,0); + cmatrix[0].Set(2,0); + //--- check + if(_spoil_scenario==12) + Spoil_Matrix_By_Value(cmatrix,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==13) + Spoil_Matrix_By_Value(cmatrix,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==14) + Spoil_Matrix_By_Value(cmatrix,CInfOrNaN::NegativeInfinity()); + //--- create variables + int info; + CLSFitReportShell rep; + //--- Constrained fitting withweights + CAlglib::LSFitLinearC(y,fmatrix,cmatrix,info,c,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,2); + //--- initialization + temparray[0]=0; + temparray[1]=0.932933; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(info,1); + _TestResult=_TestResult && Doc_Test_Real_Vector(c,temparray,0.0005); + //--- Constrained fitting with individual weights + ArrayResize(w,6); + //--- initialization + w[0]=1; + w[1]=1.414213; + w[2]=1; + w[3]=1; + w[4]=1; + w[5]=1; + //--- check + if(_spoil_scenario==15) + Spoil_Vector_By_Value(w,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==16) + Spoil_Vector_By_Value(w,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==17) + Spoil_Vector_By_Value(w,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==18) + Spoil_Vector_By_Adding_Element(w); + //--- check + if(_spoil_scenario==19) + Spoil_Vector_By_Deleting_Element(w); + //--- function call + CAlglib::LSFitLinearWC(y,w,fmatrix,cmatrix,info,c,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- allocation + ArrayResize(temparray,2); + //--- initialization + temparray[0]=0; + temparray[1]=0.938322; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(info,1); + _TestResult=_TestResult && Doc_Test_Real_Vector(c,temparray,0.0005); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","lsfit_d_linc"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Unconstrained polynomial fitting | +//+------------------------------------------------------------------+ +void TEST_LSFit_D_Pol(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double y[]; + double w[]; + double xc[]; + double yc[]; + int dc[]; + int m; + double t; + double v; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<20;_spoil_scenario++) + { + //--- 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. + ArrayResize(x,11); + //--- initialization + x[0]=0; + x[1]=0.1; + x[2]=0.2; + x[3]=0.3; + x[4]=0.4; + x[5]=0.5; + x[6]=0.6; + x[7]=0.7; + x[8]=0.8; + x[9]=0.9; + x[10]=1; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Adding_Element(x); + //--- check + if(_spoil_scenario==4) + Spoil_Vector_By_Deleting_Element(x); + //--- allocation + ArrayResize(y,11); + //--- initialization + y[0]=0; + y[1]=0.05; + y[2]=0.26; + y[3]=0.32; + y[4]=0.33; + y[5]=0.43; + y[6]=0.6; + y[7]=0.6; + y[8]=0.77; + y[9]=0.98; + y[10]=1.02; + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==8) + Spoil_Vector_By_Adding_Element(y); + //--- check + if(_spoil_scenario==9) + Spoil_Vector_By_Deleting_Element(y); + m=2; + t=2; + //--- check + if(_spoil_scenario==10) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==11) + t=CInfOrNaN::NegativeInfinity(); + //--- create variables + int info; + CBarycentricInterpolantShell p; + CPolynomialFitReportShell rep; + //--- Fitting withindividual 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). + CAlglib::PolynomialFit(x,y,m,info,p,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + v=CAlglib::BarycentricCalc(p,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,2.011,0.002); + //--- Fitting with individual weights + //--- NOTE: slightly different result is returned + ArrayResize(w,11); + //--- initialization + w[0]=1; + w[1]=1.414213562; + w[2]=1; + w[3]=1; + w[4]=1; + w[5]=1; + w[6]=1; + w[7]=1; + w[8]=1; + w[9]=1; + w[10]=1; + //--- check + if(_spoil_scenario==12) + Spoil_Vector_By_Value(w,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==13) + Spoil_Vector_By_Value(w,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==14) + Spoil_Vector_By_Value(w,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==15) + Spoil_Vector_By_Adding_Element(w); + //--- check + if(_spoil_scenario==16) + Spoil_Vector_By_Deleting_Element(w); + //--- allocation + ArrayResize(xc,0); + //--- check + if(_spoil_scenario==17) + Spoil_Vector_By_Adding_Element(xc); + //--- allocation + ArrayResize(yc,0); + //--- check + if(_spoil_scenario==18) + Spoil_Vector_By_Adding_Element(yc); + //--- allocation + ArrayResize(dc,0); + //--- check + if(_spoil_scenario==19) + Spoil_Vector_By_Adding_Element(dc); + //--- function call + CAlglib::PolynomialFitWC(x,y,w,xc,yc,dc,m,info,p,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + v=CAlglib::BarycentricCalc(p,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,2.023,0.002); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","lsfit_d_pol"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Constrained polynomial fitting | +//+------------------------------------------------------------------+ +void TEST_LSFit_D_Polc(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double y[]; + double w[]; + double xc[]; + double yc[]; + int dc[]; + int m; + int info; + double v; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<29;_spoil_scenario++) + { + //--- 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) + ArrayResize(x,2); + //--- initialization + x[0]=1; + x[1]=1; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Adding_Element(x); + //--- check + if(_spoil_scenario==4) + Spoil_Vector_By_Deleting_Element(x); + //--- allocation + ArrayResize(y,2); + //--- initialization + y[0]=0.9; + y[1]=1.1; + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==8) + Spoil_Vector_By_Adding_Element(y); + //--- check + if(_spoil_scenario==9) + Spoil_Vector_By_Deleting_Element(y); + //--- allocation + ArrayResize(w,2); + //--- initialization + w[0]=1; + w[1]=1; + //--- check + if(_spoil_scenario==10) + Spoil_Vector_By_Value(w,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==11) + Spoil_Vector_By_Value(w,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==12) + Spoil_Vector_By_Value(w,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==13) + Spoil_Vector_By_Adding_Element(w); + //--- check + if(_spoil_scenario==14) + Spoil_Vector_By_Deleting_Element(w); + //--- allocation + ArrayResize(xc,1); + //--- initialization + xc[0]=0; + //--- check + if(_spoil_scenario==15) + Spoil_Vector_By_Value(xc,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==16) + Spoil_Vector_By_Value(xc,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==17) + Spoil_Vector_By_Value(xc,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==18) + Spoil_Vector_By_Adding_Element(xc); + //--- check + if(_spoil_scenario==19) + Spoil_Vector_By_Deleting_Element(xc); + //--- allocation + ArrayResize(yc,1); + //--- initialization + yc[0]=0; + //--- check + if(_spoil_scenario==20) + Spoil_Vector_By_Value(yc,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==21) + Spoil_Vector_By_Value(yc,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==22) + Spoil_Vector_By_Value(yc,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==23) + Spoil_Vector_By_Adding_Element(yc); + //--- check + if(_spoil_scenario==24) + Spoil_Vector_By_Deleting_Element(yc); + //--- allocation + ArrayResize(dc,1); + //--- initialization + dc[0]=0; + //--- check + if(_spoil_scenario==25) + Spoil_Vector_By_Adding_Element(dc); + //--- check + if(_spoil_scenario==26) + Spoil_Vector_By_Deleting_Element(dc); + double t=2; + //--- check + if(_spoil_scenario==27) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==28) + t=CInfOrNaN::NegativeInfinity(); + m=2; + //--- create variables + CBarycentricInterpolantShell p; + CPolynomialFitReportShell rep; + //--- function call + CAlglib::PolynomialFitWC(x,y,w,xc,yc,dc,m,info,p,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + v=CAlglib::BarycentricCalc(p,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,2.000,0.001); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","lsfit_d_polc"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Unconstrained fitting by penalized regression spline | +//+------------------------------------------------------------------+ +void TEST_LSFit_D_Spline(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double y[]; + int info; + double v; + double rho; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<19;_spoil_scenario++) + { + //--- 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 + ArrayResize(x,10); + //--- initialization + x[0]=0; + x[1]=0.1; + x[2]=0.2; + x[3]=0.3; + x[4]=0.4; + x[5]=0.5; + x[6]=0.6; + x[7]=0.7; + x[8]=0.8; + x[9]=0.9; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Adding_Element(x); + //--- check + if(_spoil_scenario==4) + Spoil_Vector_By_Deleting_Element(x); + //--- allocation + ArrayResize(y,10); + //--- initialization + y[0]=0.1; + y[1]=0; + y[2]=0.3; + y[3]=0.4; + y[4]=0.3; + y[5]=0.4; + y[6]=0.62; + y[7]=0.68; + y[8]=0.75; + y[9]=0.95; + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==8) + Spoil_Vector_By_Adding_Element(y); + //--- check + if(_spoil_scenario==9) + Spoil_Vector_By_Deleting_Element(y); + //--- create variables + CSpline1DInterpolantShell s; + CSpline1DFitReportShell rep; + //--- 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; + //--- check + if(_spoil_scenario==10) + rho=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==11) + rho=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==12) + rho=CInfOrNaN::NegativeInfinity(); + //--- function call + CAlglib::Spline1DFitPenalized(x,y,50,rho,info,s,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(info,1); + //--- function call + v=CAlglib::Spline1DCalc(s,0.0); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _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; + //--- check + if(_spoil_scenario==13) + rho=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==14) + rho=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==15) + rho=CInfOrNaN::NegativeInfinity(); + //--- function call + CAlglib::Spline1DFitPenalized(x,y,50,rho,info,s,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(info,1); + //--- function call + v=CAlglib::Spline1DCalc(s,1.0); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _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; + //--- check + if(_spoil_scenario==16) + rho=CInfOrNaN::NaN(); + //--- check + if(_spoil_scenario==17) + rho=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==18) + rho=CInfOrNaN::NegativeInfinity(); + //--- function call + CAlglib::Spline1DFitPenalized(x,y,50,rho,info,s,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Int(info,1); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","lsfit_d_spline"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Polynomial fitting, full list of parameters. | +//+------------------------------------------------------------------+ +void TEST_LSFit_T_PolFit_1(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double y[]; + int info; + double v; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<10;_spoil_scenario++) + { + //--- allocation + ArrayResize(x,11); + //--- initialization + x[0]=0; + x[1]=0.1; + x[2]=0.2; + x[3]=0.3; + x[4]=0.4; + x[5]=0.5; + x[6]=0.6; + x[7]=0.7; + x[8]=0.8; + x[9]=0.9; + x[10]=1; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Deleting_Element(x); + //--- allocation + ArrayResize(y,11); + //--- initialization + y[0]=0; + y[1]=0.05; + y[2]=0.26; + y[3]=0.32; + y[4]=0.33; + y[5]=0.43; + y[6]=0.6; + y[7]=0.6; + y[8]=0.77; + y[9]=0.98; + y[10]=1.02; + //--- check + if(_spoil_scenario==4) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Deleting_Element(y); + int m=2; + double t=2; + //--- check + if(_spoil_scenario==8) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==9) + t=CInfOrNaN::NegativeInfinity(); + //--- create variables + CBarycentricInterpolantShell p; + CPolynomialFitReportShell rep; + //--- function call + CAlglib::PolynomialFit(x,y,11,m,info,p,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + v=CAlglib::BarycentricCalc(p,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,2.011,0.002); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","lsfit_t_polfit_1"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Polynomial fitting, full list of parameters. | +//+------------------------------------------------------------------+ +void TEST_LSFit_T_PolFit_2(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double y[]; + double w[]; + double xc[]; + double yc[]; + int dc[]; + int m; + double t; + int info; + double v; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<14;_spoil_scenario++) + { + //--- allocation + ArrayResize(x,11); + //--- initialization + x[0]=0; + x[1]=0.1; + x[2]=0.2; + x[3]=0.3; + x[4]=0.4; + x[5]=0.5; + x[6]=0.6; + x[7]=0.7; + x[8]=0.8; + x[9]=0.9; + x[10]=1; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Deleting_Element(x); + //--- allocation + ArrayResize(y,11); + //--- initialization + y[0]=0; + y[1]=0.05; + y[2]=0.26; + y[3]=0.32; + y[4]=0.33; + y[5]=0.43; + y[6]=0.6; + y[7]=0.6; + y[8]=0.77; + y[9]=0.98; + y[10]=1.02; + //--- check + if(_spoil_scenario==4) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Deleting_Element(y); + //--- allocation + ArrayResize(w,11); + //--- initialization + w[0]=1; + w[1]=1.414213562; + w[2]=1; + w[3]=1; + w[4]=1; + w[5]=1; + w[6]=1; + w[7]=1; + w[8]=1; + w[9]=1; + w[10]=1; + //--- check + if(_spoil_scenario==8) + Spoil_Vector_By_Value(w,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==9) + Spoil_Vector_By_Value(w,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==10) + Spoil_Vector_By_Value(w,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==11) + Spoil_Vector_By_Deleting_Element(w); + //--- allocation + ArrayResize(xc,0); + ArrayResize(yc,0); + ArrayResize(dc,0); + //--- initialization + m=2; + t=2; + //--- check + if(_spoil_scenario==12) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==13) + t=CInfOrNaN::NegativeInfinity(); + //--- create variables + CBarycentricInterpolantShell p; + CPolynomialFitReportShell rep; + //--- function call + CAlglib::PolynomialFitWC(x,y,w,11,xc,yc,dc,0,m,info,p,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + v=CAlglib::BarycentricCalc(p,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,2.023,0.002); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","lsfit_t_polfit_2"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Polynomial fitting,full list of parameters. | +//+------------------------------------------------------------------+ +void TEST_LSFit_T_PolFit_3(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double x[]; + double y[]; + double w[]; + double xc[]; + double yc[]; + int dc[]; + int m; + double t; + int info; + double v; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<23;_spoil_scenario++) + { + //--- allocation + ArrayResize(x,2); + //--- initialization + x[0]=1; + x[1]=1; + //--- check + if(_spoil_scenario==0) + Spoil_Vector_By_Value(x,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Vector_By_Value(x,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Vector_By_Value(x,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Vector_By_Deleting_Element(x); + //--- allocation + ArrayResize(y,2); + //--- initialization + y[0]=0.9; + y[1]=1.1; + //--- check + if(_spoil_scenario==4) + Spoil_Vector_By_Value(y,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Value(y,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==6) + Spoil_Vector_By_Value(y,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Deleting_Element(y); + //--- allocation + ArrayResize(w,2); + //--- initialization + w[0]=1; + w[1]=1; + //--- check + if(_spoil_scenario==8) + Spoil_Vector_By_Value(w,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==9) + Spoil_Vector_By_Value(w,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==10) + Spoil_Vector_By_Value(w,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==11) + Spoil_Vector_By_Deleting_Element(w); + //--- allocation + ArrayResize(xc,1); + //--- initialization + xc[0]=0; + //--- check + if(_spoil_scenario==12) + Spoil_Vector_By_Value(xc,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==13) + Spoil_Vector_By_Value(xc,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==14) + Spoil_Vector_By_Value(xc,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==15) + Spoil_Vector_By_Deleting_Element(xc); + //--- allocation + ArrayResize(yc,1); + //--- initialization + yc[0]=0; + //--- check + if(_spoil_scenario==16) + Spoil_Vector_By_Value(yc,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==17) + Spoil_Vector_By_Value(yc,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==18) + Spoil_Vector_By_Value(yc,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==19) + Spoil_Vector_By_Deleting_Element(yc); + //--- allocation + ArrayResize(dc,1); + //--- initialization + dc[0]=0; + //--- check + if(_spoil_scenario==20) + Spoil_Vector_By_Deleting_Element(dc); + m=2; + t=2; + //--- check + if(_spoil_scenario==21) + t=CInfOrNaN::PositiveInfinity(); + //--- check + if(_spoil_scenario==22) + t=CInfOrNaN::NegativeInfinity(); + //--- create variables + CBarycentricInterpolantShell p; + CPolynomialFitReportShell rep; + //--- function call + CAlglib::PolynomialFitWC(x,y,w,2,xc,yc,dc,1,m,info,p,rep); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- function call + v=CAlglib::BarycentricCalc(p,t); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(v,2.000,0.001); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","lsfit_t_polfit_3"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Determinant calculation, real matrix, short form | +//+------------------------------------------------------------------+ +void TEST_MatDet_D_1(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double a; + CMatrixDouble b; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<7;_spoil_scenario++) + { + //--- allocation + b.Resize(2,2); + //--- initialization + b[0].Set(0,1); + b[0].Set(1,2); + b[1].Set(0,2); + b[1].Set(1,1); + //--- check + if(_spoil_scenario==0) + Spoil_Matrix_By_Value(b,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Matrix_By_Value(b,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Matrix_By_Value(b,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Matrix_By_Adding_Row(b); + //--- check + if(_spoil_scenario==4) + Spoil_Matrix_By_Adding_Col(b); + //--- check + if(_spoil_scenario==5) + Spoil_Matrix_By_Deleting_Row(b); + //--- check + if(_spoil_scenario==6) + Spoil_Matrix_By_Deleting_Col(b); + //--- function call + a=CAlglib::RMatrixDet(b); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(a,-3,0.0001); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","matdet_d_1"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Determinant calculation, real matrix, full form | +//+------------------------------------------------------------------+ +void TEST_MatDet_D_2(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double a; + CMatrixDouble b; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<5;_spoil_scenario++) + { + //--- allocation + b.Resize(2,2); + //--- initialization + b[0].Set(0,5); + b[0].Set(1,4); + b[1].Set(0,4); + b[1].Set(1,5); + //--- check + if(_spoil_scenario==0) + Spoil_Matrix_By_Value(b,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Matrix_By_Value(b,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Matrix_By_Value(b,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Matrix_By_Deleting_Row(b); + //--- check + if(_spoil_scenario==4) + Spoil_Matrix_By_Deleting_Col(b); + //--- function call + a=CAlglib::RMatrixDet(b,2); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(a,9,0.0001); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","matdet_d_2"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Determinant calculation, complex matrix, short form | +//+------------------------------------------------------------------+ +void TEST_MatDet_D_3(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + complex a; + complex tempcomplex1; + complex tempcomplex2; + complex tempcomplex3; + CMatrixComplex b; + complex cnan; + complex cpositiveinfinity; + complex cnegativeinfinity; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<7;_spoil_scenario++) + { + //--- initialization + tempcomplex1.re=1; + tempcomplex1.im=1; + tempcomplex2.re=1; + tempcomplex2.im=-1; + //--- allocation + b.Resize(2,2); + //--- initialization + b[0].Set(0,tempcomplex1); + b[0].Set(1,2); + b[1].Set(0,2); + b[1].Set(1,tempcomplex2); + //--- initialization + cnan.re=CInfOrNaN::NaN(); + cnan.im=CInfOrNaN::NaN(); + cpositiveinfinity.re=CInfOrNaN::PositiveInfinity(); + cpositiveinfinity.im=CInfOrNaN::PositiveInfinity(); + cnegativeinfinity.re=CInfOrNaN::NegativeInfinity(); + cnegativeinfinity.im=CInfOrNaN::NegativeInfinity(); + //--- check + if(_spoil_scenario==0) + Spoil_Matrix_By_Value(b,cnan); + //--- check + if(_spoil_scenario==1) + Spoil_Matrix_By_Value(b,cpositiveinfinity); + //--- check + if(_spoil_scenario==2) + Spoil_Matrix_By_Value(b,cnegativeinfinity); + //--- check + if(_spoil_scenario==3) + Spoil_Matrix_By_Adding_Row(b); + //--- check + if(_spoil_scenario==4) + Spoil_Matrix_By_Adding_Col(b); + //--- check + if(_spoil_scenario==5) + Spoil_Matrix_By_Deleting_Row(b); + //--- check + if(_spoil_scenario==6) + Spoil_Matrix_By_Deleting_Col(b); + //--- function call + a=CAlglib::CMatrixDet(b); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- initialization + tempcomplex3.re=-2; + tempcomplex3.im=0; + //--- check result + _TestResult=_TestResult && Doc_Test_Complex(a,tempcomplex3,0.0001); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","matdet_d_3"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Determinant calculation, complex matrix, full form | +//+------------------------------------------------------------------+ +void TEST_MatDet_D_4(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + complex a; + complex tempcomplex1; + complex tempcomplex2; + complex tempcomplex3; + CMatrixComplex b; + complex cnan; + complex cpositiveinfinity; + complex cnegativeinfinity; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<5;_spoil_scenario++) + { + //--- initialization + tempcomplex1.re=0; + tempcomplex1.im=5; + tempcomplex2.re=0; + tempcomplex2.im=4; + //--- allocation + b.Resize(2,2); + //--- initialization + b[0].Set(0,tempcomplex1); + b[0].Set(1,4); + b[1].Set(0,tempcomplex2); + b[1].Set(1,5); + //--- initialization + cnan.re=CInfOrNaN::NaN(); + cnan.im=CInfOrNaN::NaN(); + cpositiveinfinity.re=CInfOrNaN::PositiveInfinity(); + cpositiveinfinity.im=CInfOrNaN::PositiveInfinity(); + cnegativeinfinity.re=CInfOrNaN::NegativeInfinity(); + cnegativeinfinity.im=CInfOrNaN::NegativeInfinity(); + //--- check + if(_spoil_scenario==0) + Spoil_Matrix_By_Value(b,cnan); + //--- check + if(_spoil_scenario==1) + Spoil_Matrix_By_Value(b,cpositiveinfinity); + //--- check + if(_spoil_scenario==2) + Spoil_Matrix_By_Value(b,cnegativeinfinity); + //--- check + if(_spoil_scenario==3) + Spoil_Matrix_By_Deleting_Row(b); + //--- check + if(_spoil_scenario==4) + Spoil_Matrix_By_Deleting_Col(b); + //--- function call + a=CAlglib::CMatrixDet(b,2); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- initialization + tempcomplex3.re=0; + tempcomplex3.im=9; + //--- check result + _TestResult=_TestResult && Doc_Test_Complex(a,tempcomplex3,0.0001); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","matdet_d_4"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Determinant calculation, complex matrix with zero imaginary part,| +//| short form | +//+------------------------------------------------------------------+ +void TEST_MatDet_D_5(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + complex a; + complex tempcomplex; + CMatrixComplex b; + complex cnan; + complex cpositiveinfinity; + complex cnegativeinfinity; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<7;_spoil_scenario++) + { + //--- allocation + b.Resize(2,2); + //--- initialization + b[0].Set(0,9); + b[0].Set(1,1); + b[1].Set(0,2); + b[1].Set(1,1); + //--- initialization + cnan.re=CInfOrNaN::NaN(); + cnan.im=CInfOrNaN::NaN(); + cpositiveinfinity.re=CInfOrNaN::PositiveInfinity(); + cpositiveinfinity.im=CInfOrNaN::PositiveInfinity(); + cnegativeinfinity.re=CInfOrNaN::NegativeInfinity(); + cnegativeinfinity.im=CInfOrNaN::NegativeInfinity(); + //--- check + if(_spoil_scenario==0) + Spoil_Matrix_By_Value(b,cnan); + //--- check + if(_spoil_scenario==1) + Spoil_Matrix_By_Value(b,cpositiveinfinity); + //--- check + if(_spoil_scenario==2) + Spoil_Matrix_By_Value(b,cnegativeinfinity); + //--- check + if(_spoil_scenario==3) + Spoil_Matrix_By_Adding_Row(b); + //--- check + if(_spoil_scenario==4) + Spoil_Matrix_By_Adding_Col(b); + //--- check + if(_spoil_scenario==5) + Spoil_Matrix_By_Deleting_Row(b); + //--- check + if(_spoil_scenario==6) + Spoil_Matrix_By_Deleting_Col(b); + //--- function call + a=CAlglib::CMatrixDet(b); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- initialization + tempcomplex.re=7; + tempcomplex.im=0; + //--- check result + _TestResult=_TestResult && Doc_Test_Complex(a,tempcomplex,0.0001); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","matdet_d_5"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Determinant calculation, real matrix, full form | +//+------------------------------------------------------------------+ +void TEST_MatDet_T_0(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double a; + CMatrixDouble b; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<5;_spoil_scenario++) + { + //--- allocation + b.Resize(2,2); + //--- initialization + b[0].Set(0,3); + b[0].Set(1,4); + b[1].Set(0,-4); + b[1].Set(1,3); + //--- check + if(_spoil_scenario==0) + Spoil_Matrix_By_Value(b,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Matrix_By_Value(b,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Matrix_By_Value(b,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Matrix_By_Deleting_Row(b); + //--- check + if(_spoil_scenario==4) + Spoil_Matrix_By_Deleting_Col(b); + //--- function call + a=CAlglib::RMatrixDet(b,2); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(a,25,0.0001); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","matdet_t_0"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Determinant calculation, real matrix, LU, short form | +//+------------------------------------------------------------------+ +void TEST_MatDet_T_1(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double a; + CMatrixDouble b; + int p[]; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<9;_spoil_scenario++) + { + //--- allocation + b.Resize(2,2); + //--- initialization + b[0].Set(0,1); + b[0].Set(1,2); + b[1].Set(0,2); + b[1].Set(1,5); + //--- check + if(_spoil_scenario==0) + Spoil_Matrix_By_Value(b,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Matrix_By_Value(b,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Matrix_By_Value(b,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Matrix_By_Adding_Row(b); + //--- check + if(_spoil_scenario==4) + Spoil_Matrix_By_Adding_Col(b); + //--- check + if(_spoil_scenario==5) + Spoil_Matrix_By_Deleting_Row(b); + //--- check + if(_spoil_scenario==6) + Spoil_Matrix_By_Deleting_Col(b); + //--- allocation + ArrayResize(p,2); + //--- initialization + p[0]=1; + p[1]=1; + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Adding_Element(p); + //--- check + if(_spoil_scenario==8) + Spoil_Vector_By_Deleting_Element(p); + //--- function call + a=CAlglib::RMatrixLUDet(b,p); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(a,-5,0.0001); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","matdet_t_1"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Determinant calculation, real matrix, LU, full form | +//+------------------------------------------------------------------+ +void TEST_MatDet_T_2(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + double a; + int p[]; + CMatrixDouble b; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<6;_spoil_scenario++) + { + //--- allocation + b.Resize(2,2); + //--- initialization + b[0].Set(0,5); + b[0].Set(1,4); + b[1].Set(0,4); + b[1].Set(1,5); + //--- check + if(_spoil_scenario==0) + Spoil_Matrix_By_Value(b,CInfOrNaN::NaN()); + //--- check + if(_spoil_scenario==1) + Spoil_Matrix_By_Value(b,CInfOrNaN::PositiveInfinity()); + //--- check + if(_spoil_scenario==2) + Spoil_Matrix_By_Value(b,CInfOrNaN::NegativeInfinity()); + //--- check + if(_spoil_scenario==3) + Spoil_Matrix_By_Deleting_Row(b); + //--- check + if(_spoil_scenario==4) + Spoil_Matrix_By_Deleting_Col(b); + //--- allocation + ArrayResize(p,2); + //--- initialization + p[0]=0; + p[1]=1; + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Deleting_Element(p); + //--- function call + a=CAlglib::RMatrixLUDet(b,p,2); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- check result + _TestResult=_TestResult && Doc_Test_Real(a,25,0.0001); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","matdet_t_2"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Determinant calculation, complex matrix, full form | +//+------------------------------------------------------------------+ +void TEST_MatDet_T_3(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + complex a; + CMatrixComplex b; + complex tempcomplex1; + complex tempcomplex2; + complex cnan; + complex cpositiveinfinity; + complex cnegativeinfinity; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<5;_spoil_scenario++) + { + //--- initialization + tempcomplex1.re=0; + tempcomplex1.im=5; + //--- allocation + b.Resize(2,2); + //--- initialization + b[0].Set(0,tempcomplex1); + b[0].Set(1,4); + b[1].Set(0,-4); + b[1].Set(1,tempcomplex1); + //--- initialization + cnan.re=CInfOrNaN::NaN(); + cnan.im=CInfOrNaN::NaN(); + cpositiveinfinity.re=CInfOrNaN::PositiveInfinity(); + cpositiveinfinity.im=CInfOrNaN::PositiveInfinity(); + cnegativeinfinity.re=CInfOrNaN::NegativeInfinity(); + cnegativeinfinity.im=CInfOrNaN::NegativeInfinity(); + //--- check + if(_spoil_scenario==0) + Spoil_Matrix_By_Value(b,cnan); + //--- check + if(_spoil_scenario==1) + Spoil_Matrix_By_Value(b,cpositiveinfinity); + //--- check + if(_spoil_scenario==2) + Spoil_Matrix_By_Value(b,cnegativeinfinity); + //--- check + if(_spoil_scenario==3) + Spoil_Matrix_By_Deleting_Row(b); + //--- check + if(_spoil_scenario==4) + Spoil_Matrix_By_Deleting_Col(b); + //--- function call + a=CAlglib::CMatrixDet(b,2); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- initialization + tempcomplex2.re=-9; + tempcomplex2.im=0; + //--- check result + _TestResult=_TestResult && Doc_Test_Complex(a,tempcomplex2,0.0001); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","matdet_t_3"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Determinant calculation, complex matrix, LU, short form | +//+------------------------------------------------------------------+ +void TEST_MatDet_T_4(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + complex a; + int p[]; + complex tempcomplex1; + complex tempcomplex2; + CMatrixComplex b; + complex cnan; + complex cpositiveinfinity; + complex cnegativeinfinity; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<9;_spoil_scenario++) + { + //--- initialization + tempcomplex1.re=0; + tempcomplex1.im=5; + //--- allocation + b.Resize(2,2); + //--- initialization + b[0].Set(0,1); + b[0].Set(1,2); + b[1].Set(0,2); + b[1].Set(1,tempcomplex1); + //--- initialization + cnan.re=CInfOrNaN::NaN(); + cnan.im=CInfOrNaN::NaN(); + cpositiveinfinity.re=CInfOrNaN::PositiveInfinity(); + cpositiveinfinity.im=CInfOrNaN::PositiveInfinity(); + cnegativeinfinity.re=CInfOrNaN::NegativeInfinity(); + cnegativeinfinity.im=CInfOrNaN::NegativeInfinity(); + //--- check + if(_spoil_scenario==0) + Spoil_Matrix_By_Value(b,cnan); + //--- check + if(_spoil_scenario==1) + Spoil_Matrix_By_Value(b,cpositiveinfinity); + //--- check + if(_spoil_scenario==2) + Spoil_Matrix_By_Value(b,cnegativeinfinity); + //--- check + if(_spoil_scenario==3) + Spoil_Matrix_By_Adding_Row(b); + //--- check + if(_spoil_scenario==4) + Spoil_Matrix_By_Adding_Col(b); + //--- check + if(_spoil_scenario==5) + Spoil_Matrix_By_Deleting_Row(b); + //--- check + if(_spoil_scenario==6) + Spoil_Matrix_By_Deleting_Col(b); + //--- allocation + ArrayResize(p,2); + //--- initialization + p[0]=1; + p[1]=1; + //--- check + if(_spoil_scenario==7) + Spoil_Vector_By_Adding_Element(p); + //--- check + if(_spoil_scenario==8) + Spoil_Vector_By_Deleting_Element(p); + //--- function call + a=CAlglib::CMatrixLUDet(b,p); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- initialization + tempcomplex2.re=0; + tempcomplex2.im=-5; + //--- check result + _TestResult=_TestResult && Doc_Test_Complex(a,tempcomplex2,0.0001); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","matdet_t_4"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ +//| Determinant calculation, complex matrix, LU, full form | +//+------------------------------------------------------------------+ +void TEST_MatDet_T_5(int &_spoil_scenario,bool &_TestResult,bool &_TotalResult) + { + _TestResult=true; +//--- create variables + complex a; + complex tempcomplex1; + complex tempcomplex2; + CMatrixComplex b; + complex cnan; + complex cpositiveinfinity; + complex cnegativeinfinity; + int p[]; +//--- testing + for(_spoil_scenario=-1;_spoil_scenario<6;_spoil_scenario++) + { + //--- initialization + tempcomplex1.re=0; + tempcomplex1.im=4; + //--- allocation + b.Resize(2,2); + //--- initialization + b[0].Set(0,5); + b[0].Set(1,tempcomplex1); + b[1].Set(0,4); + b[1].Set(1,5); + //--- initialization + cnan.re=CInfOrNaN::NaN(); + cnan.im=CInfOrNaN::NaN(); + cpositiveinfinity.re=CInfOrNaN::PositiveInfinity(); + cpositiveinfinity.im=CInfOrNaN::PositiveInfinity(); + cnegativeinfinity.re=CInfOrNaN::NegativeInfinity(); + cnegativeinfinity.im=CInfOrNaN::NegativeInfinity(); + //--- check + if(_spoil_scenario==0) + Spoil_Matrix_By_Value(b,cnan); + //--- check + if(_spoil_scenario==1) + Spoil_Matrix_By_Value(b,cpositiveinfinity); + //--- check + if(_spoil_scenario==2) + Spoil_Matrix_By_Value(b,cnegativeinfinity); + //--- check + if(_spoil_scenario==3) + Spoil_Matrix_By_Deleting_Row(b); + //--- check + if(_spoil_scenario==4) + Spoil_Matrix_By_Deleting_Col(b); + //--- allocation + ArrayResize(p,2); + //--- initialization + p[0]=0; + p[1]=1; + //--- check + if(_spoil_scenario==5) + Spoil_Vector_By_Deleting_Element(p); + //--- function call + a=CAlglib::CMatrixLUDet(b,p,2); + //--- handling exceptions + if(!Func_spoil_scenario(_spoil_scenario,_TestResult)) + continue; + //--- initialization + tempcomplex2.re=25; + tempcomplex2.im=0; + //--- check result + _TestResult=_TestResult && Doc_Test_Complex(a,tempcomplex2,0.0001); + _TestResult=_TestResult && (_spoil_scenario==-1); + } +//--- check + if(!_TestResult) + Print("{0,-32} FAILED","matdet_t_5"); +//--- change total result + _TotalResult=_TotalResult && _TestResult; + } +//+------------------------------------------------------------------+ diff --git a/Scripts/UnitTests/Fuzzy/TestFuzzy.mq5 b/Scripts/UnitTests/Fuzzy/TestFuzzy.mq5 new file mode 100644 index 0000000..01f9213 --- /dev/null +++ b/Scripts/UnitTests/Fuzzy/TestFuzzy.mq5 @@ -0,0 +1,661 @@ +//+------------------------------------------------------------------+ +//| TestFuzzy.mq5 | +//| Copyright 2015-2017, MetaQuotes Software Corp. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +//| Implementation of Fuzzy library in MetaQuotes Language 5 | +//| | +//| The features of the library include: | +//| - Create Mamdani fuzzy model | +//| - Create Sugeno fuzzy model | +//| - Normal membership function | +//| - Triangular membership function | +//| - Trapezoidal membership function | +//| - Constant membership function | +//| - Defuzzification method of center of gravity (COG) | +//| - Defuzzification method of bisector of area (BOA) | +//| - Defuzzification method of mean of maxima (MeOM) | +//| | +//| This file is free software; 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. | +//+------------------------------------------------------------------+ +#include +#include +//+------------------------------------------------------------------+ +//| Test_NormalCombinationMembershipFunction() | +//+------------------------------------------------------------------+ +bool Test_NormalCombinationMembershipFunction() + { + bool result=true; + double delta=1e-20; + double x[]={-4.0,5.1,0.1}; + double b1=1.2; + double sigma1=0.45; + double b2=3.1; + double sigma2=0.9; + CNormalCombinationMembershipFunction function(b1,sigma1,b2,sigma2); + for(int i=0; i3.1) + { + expected=MathExp(MathPow(x[i]-b2,2)/(-2.0*MathPow(0.9,2))); + } + if(MathAbs(actual-expected)>1e-20) + { + Print("Expected: ",expected," +/- ",delta," ; But was: ",actual); + result=false; + } + } + return (result); + } +//+------------------------------------------------------------------+ +//| Test_GeneralizedBellShapedMembershipFunction() | +//+------------------------------------------------------------------+ +bool Test_GeneralizedBellShapedMembershipFunction() + { + bool result=true; + double delta=1e-20; + double x[]={-4,5.1,0.1}; + double a = 2.4; + double b = 0.9; + double c = 1.33; + CGeneralizedBellShapedMembershipFunction function(a,b,c); + for(int i=0; i2 && x[i]M_PI) + { + expected=0; + } + if(actual!=expected) + { + Print("Expected: ",expected," +/- ",delta," ; But was: ",actual); + result=false; + } + } + return (result); + } +//+------------------------------------------------------------------+ +//| Test_NormalMembershipFunction() | +//+------------------------------------------------------------------+ +bool Test_NormalMembershipFunction() + { + bool result=true; + double delta=1e-20; + double x[]={-4,5.1,0.1}; + double b=1.33; + double sigma=0.45; + CNormalMembershipFunction function(b,sigma); + for(int i=0; ix1 && x[i]x2 && x[i]=delta) + { + Print("Expected: ",expected," +/- ",delta," ; But was: ",actual); + return (false); + } + return (true); + } +//+------------------------------------------------------------------+ +//| Test_Centroid() | +//+------------------------------------------------------------------+ +bool Test_Centroid() + { + bool result=true; + double delta=1e-1; + CMamdaniFuzzySystem system(); + system.DefuzzificationMethod(CentroidDef); + double mean[]={-5,-3,-1,1,3,5}; + double sigma[]={1,2}; + for(int i=0; i=delta) + { + Print("Expected: ",expected," +/- ",delta," ; But was: ",actual); + result=false; + } + } + } + return (result); + } +//+------------------------------------------------------------------+ +//| Test_Defuzzification() | +//+------------------------------------------------------------------+ +bool Test_Defuzzification() + { + bool result=true; + double delta=1e-12; + CMamdaniFuzzySystem system(); + double actual=0.0; + double expected=0.0; +//--- + system.DefuzzificationMethod(CentroidDef); + actual=system.Defuzzify(new CNormalMembershipFunction(0,2),-10,10); + if(MathAbs(actual-expected)>=delta) + { + Print("Expected: ",expected," +/- ",delta," ; But was: ",actual); + result=false; + } +//--- + system.DefuzzificationMethod(BisectorDef); + actual=system.Defuzzify(new CNormalMembershipFunction(0,2),-10,10); + if(MathAbs(actual-expected)>=delta) + { + Print("Expected: ",expected," +/- ",delta," ; But was: ",actual); + result=false; + } +//--- + system.DefuzzificationMethod(AverageMaximumDef); + actual=system.Defuzzify(new CNormalMembershipFunction(0,2),-10,10); + if(MathAbs(actual-expected)>=delta) + { + Print("Expected: ",expected," +/- ",delta," ; But was: ",actual); + result=false; + } +//--- + system.DefuzzificationMethod(SmallestMaximumDef); + actual=system.Defuzzify(new CNormalMembershipFunction(0,2),-10,10); + if(MathAbs(actual-expected)>=delta) + { + Print("Expected: ",expected," +/- ",delta," ; But was: ",actual); + result=false; + } +//--- + system.DefuzzificationMethod(LargestMaximumDef); + actual=system.Defuzzify(new CNormalMembershipFunction(0,2),-10,10); + if(MathAbs(actual-expected)>=delta) + { + Print("Expected: ",expected," +/- ",delta," ; But was: ",actual); + result=false; + } + return (result); + } +//+------------------------------------------------------------------+ +//| Test_TipingProblem() | +//+------------------------------------------------------------------+ +bool Test_TipingProblem() + { +//--- Mamdani Fuzzy System + CMamdaniFuzzySystem *fsTips=new CMamdaniFuzzySystem(); +//--- Create first input variables for the system + CFuzzyVariable *fvService=new CFuzzyVariable("service",0.0,10.0); + fvService.Terms().Add(new CFuzzyTerm("poor", new CTriangularMembershipFunction(-5.0, 0.0, 5.0))); + fvService.Terms().Add(new CFuzzyTerm("good", new CTriangularMembershipFunction(0.0, 5.0, 10.0))); + fvService.Terms().Add(new CFuzzyTerm("excellent", new CTriangularMembershipFunction(5.0, 10.0, 15.0))); + fsTips.Input().Add(fvService); +//--- Create second input variables for the system + CFuzzyVariable *fvFood=new CFuzzyVariable("food",0.0,10.0); + fvFood.Terms().Add(new CFuzzyTerm("rancid", new CTrapezoidMembershipFunction(0.0, 0.0, 1.0, 3.0))); + fvFood.Terms().Add(new CFuzzyTerm("delicious", new CTrapezoidMembershipFunction(7.0, 9.0, 10.0, 10.0))); + fsTips.Input().Add(fvFood); +//--- Create Output + CFuzzyVariable *fvTips=new CFuzzyVariable("tips",0.0,30.0); + fvTips.Terms().Add(new CFuzzyTerm("cheap", new CTriangularMembershipFunction(0.0, 5.0, 10.0))); + fvTips.Terms().Add(new CFuzzyTerm("average", new CTriangularMembershipFunction(10.0, 15.0, 20.0))); + fvTips.Terms().Add(new CFuzzyTerm("generous", new CTriangularMembershipFunction(20.0, 25.0, 30.0))); + fsTips.Output().Add(fvTips); +//--- Create three Mamdani fuzzy rule + CMamdaniFuzzyRule *rule1 = fsTips.ParseRule("if (service is poor ) or (food is rancid) then tips is cheap"); + CMamdaniFuzzyRule *rule2 = fsTips.ParseRule("if ((service is good)) then tips is average"); + CMamdaniFuzzyRule *rule3 = fsTips.ParseRule("if (service is excellent) or (food is delicious) then (tips is generous)"); +//--- Add three Mamdani fuzzy rule in system + fsTips.Rules().Add(rule1); + fsTips.Rules().Add(rule2); + fsTips.Rules().Add(rule3); +//--- Set input value + CList *in=new CList; + CDictionary_Obj_Double *p_od_Service=new CDictionary_Obj_Double; + CDictionary_Obj_Double *p_od_Food=new CDictionary_Obj_Double; +//--- Testing values + double Food=6.5; + double Service=9.8; + double expected=24.3; + p_od_Service.SetAll(fvService,Service); + p_od_Food.SetAll(fvFood,Food); + in.Add(p_od_Service); + in.Add(p_od_Food); +//--- Get result + CList *result; + CDictionary_Obj_Double *p_od_Tips; + result=fsTips.Calculate(in); + p_od_Tips=result.GetNodeAtIndex(0); + double actual=NormalizeDouble(p_od_Tips.Value(),1); + delete in; + delete result; + delete fsTips; + if(expected!=actual) + { + Print("Expected: ",expected," ; But was: ",actual); + //--- failed + return (false); + } + else + { + //--- success + return (true); + } + } +//+------------------------------------------------------------------+ +//| Test_TypicalFuzzyControlSystem() | +//+------------------------------------------------------------------+ +bool Test_TypicalFuzzyControlSystem() + { +//--- Sugeno Fuzzy System + CSugenoFuzzySystem *fsCruiseControl=new CSugenoFuzzySystem(); +//--- Create first input variables for the system + CFuzzyVariable *fvSpeedError=new CFuzzyVariable("SpeedError",-20.0,20.0); + fvSpeedError.Terms().Add(new CFuzzyTerm("slower",new CTriangularMembershipFunction(-35.0,-20.0,-5.0))); + fvSpeedError.Terms().Add(new CFuzzyTerm("zero", new CTriangularMembershipFunction(-15.0, -0.0, 15.0))); + fvSpeedError.Terms().Add(new CFuzzyTerm("faster", new CTriangularMembershipFunction(5.0, 20.0, 35.0))); + fsCruiseControl.Input().Add(fvSpeedError); +//--- Create second input variables for the system + CFuzzyVariable *fvSpeedErrorDot=new CFuzzyVariable("SpeedErrorDot",-5.0,5.0); + fvSpeedErrorDot.Terms().Add(new CFuzzyTerm("slower", new CTriangularMembershipFunction(-9.0, -5.0, -1.0))); + fvSpeedErrorDot.Terms().Add(new CFuzzyTerm("zero", new CTriangularMembershipFunction(-4.0, -0.0, 4.0))); + fvSpeedErrorDot.Terms().Add(new CFuzzyTerm("faster", new CTriangularMembershipFunction(1.0, 5.0, 9.0))); + fsCruiseControl.Input().Add(fvSpeedErrorDot); +//--- Create Output + CSugenoVariable *svAccelerate=new CSugenoVariable("Accelerate"); + double coeff1[3]={0.0,0.0,0.0}; + svAccelerate.Functions().Add(fsCruiseControl.CreateSugenoFunction("zero",coeff1)); + double coeff2[3]={0.0,0.0,1.0}; + svAccelerate.Functions().Add(fsCruiseControl.CreateSugenoFunction("faster",coeff2)); + double coeff3[3]={0.0,0.0,-1.0}; + svAccelerate.Functions().Add(fsCruiseControl.CreateSugenoFunction("slower",coeff3)); + double coeff4[3]={-0.04,-0.1,0.0}; + svAccelerate.Functions().Add(fsCruiseControl.CreateSugenoFunction("func",coeff4)); + fsCruiseControl.Output().Add(svAccelerate); +//--- Craete Sugeno fuzzy rules + AddSugenoFuzzyRule(fsCruiseControl,fvSpeedError,fvSpeedErrorDot,svAccelerate,"slower","slower","faster"); + AddSugenoFuzzyRule(fsCruiseControl,fvSpeedError,fvSpeedErrorDot,svAccelerate,"slower","zero","faster"); + AddSugenoFuzzyRule(fsCruiseControl,fvSpeedError,fvSpeedErrorDot,svAccelerate,"slower","faster","zero"); + AddSugenoFuzzyRule(fsCruiseControl,fvSpeedError,fvSpeedErrorDot,svAccelerate,"zero","slower","faster"); + AddSugenoFuzzyRule(fsCruiseControl,fvSpeedError,fvSpeedErrorDot,svAccelerate,"zero","zero","func"); + AddSugenoFuzzyRule(fsCruiseControl,fvSpeedError,fvSpeedErrorDot,svAccelerate,"zero","faster","slower"); + AddSugenoFuzzyRule(fsCruiseControl,fvSpeedError,fvSpeedErrorDot,svAccelerate,"faster","slower","zero"); + AddSugenoFuzzyRule(fsCruiseControl,fvSpeedError,fvSpeedErrorDot,svAccelerate,"faster","zero","slower"); + AddSugenoFuzzyRule(fsCruiseControl,fvSpeedError,fvSpeedErrorDot,svAccelerate,"faster","faster","slower"); +//--- Set input value and get result + CList *in=new CList; + CDictionary_Obj_Double *p_od_Error=new CDictionary_Obj_Double; + CDictionary_Obj_Double *p_od_ErrorDot=new CDictionary_Obj_Double; + double Speed_Error=18.3; + double Speed_ErrorDot=-3.5; + double expected=-16.7; + p_od_Error.SetAll(fvSpeedError,Speed_Error); + p_od_ErrorDot.SetAll(fvSpeedErrorDot,Speed_ErrorDot); + in.Add(p_od_Error); + in.Add(p_od_ErrorDot); +//--- Get result + CList *result; + CDictionary_Obj_Double *p_od_Accelerate; + result=fsCruiseControl.Calculate(in); + p_od_Accelerate=result.GetNodeAtIndex(0); + double actual=NormalizeDouble(p_od_Accelerate.Value()*100,1); + delete in; + delete result; + delete fsCruiseControl; + if(expected!=actual) + { + Print("Expected: ",expected," ; But was: ",actual); + //--- failed + return (false); + } + else + { + //--- success + return (true); + } + } +//+------------------------------------------------------------------+ +//| AddSugenoFuzzyRule() | +//+------------------------------------------------------------------+ +void AddSugenoFuzzyRule(CSugenoFuzzySystem *fs,CFuzzyVariable *fv1,CFuzzyVariable *fv2,CSugenoVariable *sv, + const string value1,const string value2,const string result) + { + CSugenoFuzzyRule *rule=fs.EmptyRule(); + rule.Conclusion(new CSingleCondition()); + rule.Condition().Op(OperatorType::And); + rule.Condition().ConditionsList().Add(rule.CreateCondition(fv1, fv1.GetTermByName(value1))); + rule.Condition().ConditionsList().Add(rule.CreateCondition(fv2, fv2.GetTermByName(value2))); + rule.Conclusion().Var(sv); + INamedValue *sf=sv.GetFuncByName(result); + rule.Conclusion().Term(sf); + fs.Rules().Add(rule); + } +//+------------------------------------------------------------------+ +//| TestMembersipFunctions | +//+------------------------------------------------------------------+ +bool TestMembersipFunctions(const string test_name) + { + PrintFormat("%s started",test_name); +//--- test 1 + PrintFormat("%s: Test 1: calculation of the values for combination two normal membership function",test_name); + if(!Test_NormalCombinationMembershipFunction()) + return (false); +//--- test 2 + PrintFormat("%s: Test 2: calculation of the values for generalized bell-shaped membership function",test_name); + if(!Test_GeneralizedBellShapedMembershipFunction()) + return (false); +//--- test 3 + PrintFormat("%s: Test 3: calculation of the values for sigmoidal membership function",test_name); + if(!Test_SigmoidalMembershipFunction()) + return (false); +//--- test 4 + PrintFormat("%s: Test 4: calculation of the values for product two sigmoidal membership function",test_name); + if(!Test_ProductTwoSigmoidalMembershipFunctions()) + return (false); +//--- test 5 + PrintFormat("%s: Test 5: calculation of the values for trapezoid membership function",test_name); + if(!Test_TrapezoidMembershipFunction()) + return (false); +//--- test 6 + PrintFormat("%s: Test 6: calculation of the values for normal membership function",test_name); + if(!Test_NormalMembershipFunction()) + return (false); +//--- test 7 + PrintFormat("%s: Test 7: calculation of the values for triangular membership function",test_name); + if(!Test_TriangularMembershipFunction()) + return (false); +//--- test 8 + PrintFormat("%s: Test 8: calculation of the values for constant membership function",test_name); + if(!Test_ConstantMembershipFunction()) + return (false); +//--- test 9 + PrintFormat("%s: Test 9: comparing the results of calculations 'P' shaped function and product 'S' and 'Z' shaped function",test_name); + if(!Test_P_S_Z_ShapedMembershipFunction()) + return (false); +//--- successful + PrintFormat("%s passed",test_name); + return (true); + } +//+------------------------------------------------------------------+ +//| TestDefuzzificationMethods | +//+------------------------------------------------------------------+ +bool TestDefuzzificationMethods(const string test_name) + { + PrintFormat("%s started",test_name); +//--- test 1 + PrintFormat("%s: Test 1: application of the Bisector defuzzification for a triangular membership function",test_name); + if(!Test_Bisector()) + return (false); +//--- test 2 + PrintFormat("%s: Test 2: application of the Centroid defuzzification for a normal membership function",test_name); + if(!Test_Centroid()) + return (false); +//--- test 3 + PrintFormat("%s: Test 3: application of the Bisector, Centroid, Middle, Smallest, and Largest of Maximum defuzzification for a normal membership function",test_name); + if(!Test_Defuzzification()) + return (false); +//--- successful + PrintFormat("%s passed",test_name); + return (true); + } +//+------------------------------------------------------------------+ +//| TestFuzzySystems | +//+------------------------------------------------------------------+ +bool TestFuzzySystems(const string test_name) + { + PrintFormat("%s started",test_name); +//--- test 1 + PrintFormat("%s: Test 1: calculate result for Mamdani fuzzy system",test_name); + if(!Test_TipingProblem()) + return (false); +//--- test 2 + PrintFormat("%s: Test 2: calculate result for Sugeno fuzzy system",test_name); + if(!Test_TypicalFuzzyControlSystem()) + return (false); +//--- successful + PrintFormat("%s passed",test_name); + return (true); + } +//+------------------------------------------------------------------+ +//| TestFuzzy | +//+------------------------------------------------------------------+ +void TestFuzzy(int &tests_performed,int &tests_passed) + { +//--- Membersip functions + tests_performed++; + string test_name="Membersip functions test"; + if(TestMembersipFunctions(test_name)) + tests_passed++; + else + PrintFormat("%s failed",test_name); + +//--- Defuzzification methods + tests_performed++; + test_name="Defuzzification methods test"; + if(TestDefuzzificationMethods(test_name)) + tests_passed++; + else + PrintFormat("%s failed",test_name); + +//--- Fuzzy systems + tests_performed++; + test_name="Fuzzy systems test"; + if(TestFuzzySystems(test_name)) + tests_passed++; + else + PrintFormat("%s failed",test_name); + return; + } +//+------------------------------------------------------------------+ +//| UnitTests() | +//+------------------------------------------------------------------+ +void UnitTests(const string package_name) + { + PrintFormat("Unit tests for Package %s\n",package_name); +//--- initial values + int tests_performed=0; + int tests_passed=0; +//--- test distributions + TestFuzzy(tests_performed,tests_passed); +//--- print statistics + PrintFormat("\n%d of %d passed",tests_passed,tests_performed); + } +//+------------------------------------------------------------------+ +//| Script program start function | +//+------------------------------------------------------------------+ +void OnStart() + { + UnitTests("Fuzzy"); + } +//+------------------------------------------------------------------+ diff --git a/Scripts/UnitTests/Generic/TestArrayList.mq5 b/Scripts/UnitTests/Generic/TestArrayList.mq5 new file mode 100644 index 0000000..f8325da --- /dev/null +++ b/Scripts/UnitTests/Generic/TestArrayList.mq5 @@ -0,0 +1,987 @@ +//+------------------------------------------------------------------+ +//| TestArrayList.mq5 | +//| Copyright 2017, MetaQuotes Software Corp. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include +//+------------------------------------------------------------------+ +//| TestAddRange_AsArrayList. | +//+------------------------------------------------------------------+ +bool TestAddRange_AsArrayList(const int count,const int add_length) + { +//--- create source list + CArrayListlist_test(count); + for(int i=0; ilist_clone(GetPointer(list_test)); +//--- crete added list + CArrayListlist_added(add_length); + for(int i=0; ilist_test(count); + for(int i=0; ilist_clone(GetPointer(list_test)); +//--- crete added array + int array_added[]; + ArrayResize(array_added,add_length); + for(int i=0; ilist_test(count); + for(int i=0; ilist_clone(GetPointer(list_test)); +//--- crete added collection + ICollection*null=NULL; +//--- add range + list_test.AddRange(null); +//--- check first path + for(int i=0; ilist_test(count); + for(int i=0; iset(); + for(int i=0; ilist_test(GetPointer(set)); +//--- sort list + list_test.Sort(); +//--- find all elements + for(int i=0; ilist_test(count); + for(int i=0; ilist_test(count); + for(int i=0; i=0) + return(false); + if(list_test.LastIndexOf(value)>=0) + return(false); +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestIndexOf_OrderIsCorrect. | +//+------------------------------------------------------------------+ +bool TestIndexOf_OrderIsCorrect(const int count) + { +//--- create source list + CArrayListlist_test(count); + for(int i=0; ilist_clone(GetPointer(list_test)); +//--- add duplicates + list_test.AddRange(GetPointer(list_test)); + list_test.AddRange(GetPointer(list_test)); + list_test.AddRange(GetPointer(list_test)); +//--- find values + for(int i=0; ilist_test(count); + for(int i=0; ilist_test(count); + for(int i=0; ilist_clone(GetPointer(list_test)); +//--- create random array + int element=MathRand(); +//--- insert + int index=count/2; + for(int i=0; ilist_x(count); + for(int i=0; ilist_y(count); + for(int i=0; ilist(GetPointer(list_y)); + list.InsertRange(index,GetPointer(list)); +//--- check elements + for(int i=0; ilist_new_x(array_x); +//--- insert array + list_new_x.InsertRange(index,array_y); +//--- check elements + for(int i=0; ilist_test(array); +//--- check elements + for(int i=0; ilist_test(array); + list_test.Sort(); +//--- remove elements + for(int i=0; i0) + return(false); +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestMisc_Clear. | +//+------------------------------------------------------------------+ +bool TestMisc_Clear(const int count) + { +//--- create source list + CArrayListlist_test(count); +//--- check + if(list_test.Count()!=0) + return(false); + if(list_test.Capacity()!=count) + return(false); +//--- fill list + for(int i=0; ilist_test(count); + for(int i=0; ilist_clone(GetPointer(list_test)); +//--- create paremeters + int values[9][2]= + { + {3, 3}, + {0, 10}, + {10, 0}, + {5, 5}, + {0, 5}, + {1, 9}, + {9, 1}, + {2, 8}, + {8, 2} + }; +//--- remove range + for(int j=0; j<9; j++) + { + CArrayListlist_actual(GetPointer(list_test)); + int rindex = values[j][0]; + int rcount = values[j][1]; + if(!list_actual.RemoveRange(rindex,rcount)) + return(false); + if(list_actual.Count()!=count-rcount) + return(false); + for(int i=0; ilist_test(count); + for(int i=0; ilist_test(count); + for(int i=0; ilist_clone(GetPointer(list_test)); +//--- create paremeters + int values[9][2]= + { + {3, 3}, + {0, 10}, + {10, 0}, + {5, 5}, + {0, 5}, + {1, 9}, + {9, 1}, + {2, 8}, + {8, 2} + }; +//--- reverse list + for(int j=0; j<9; j++) + { + int rindex = values[j][0]; + int rcount = values[j][1]; + CArrayListlist_actual(GetPointer(list_test)); + list_actual.Reverse(rindex,rcount); + for(int i=0; ilist_test(count); + for(int i=0; ilist_test(count); + for(int i=0; icomaprer; +//--- sort list + list_test.Sort(); +//--- check + for(int i=0; i0) + return(false); + } +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestSort_Invalid. | +//+------------------------------------------------------------------+ +bool TestSort_Invalid(const int count) + { +//--- create source list + CArrayListlist_test(count); + for(int i=0; i +#include +//+------------------------------------------------------------------+ +//| TestMisc_Constructor. | +//+------------------------------------------------------------------+ +bool TestMisc_Constructor(const int count) + { +//--- create arrays + int keys[]; + string values[]; + ArrayResize(keys,count); + ArrayResize(values,count); + for(int i=0; icomparer(); + CHashMapmap_test(GetPointer(comparer)); + for(int i=0; imap_copy(GetPointer(map_test)); +//--- check + if(map_copy.Count()!=map_test.Count()) + return(false); + if(map_test.Comparer()!=GetPointer(comparer)) + return(false); + if(map_copy.Comparer()==GetPointer(comparer)) + return(false); +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestMisc_Contains. | +//+------------------------------------------------------------------+ +bool TestMisc_Contains(const int count) + { +//--- create arrays + int keys[]; + string values[]; + ArrayResize(keys,count); + ArrayResize(values,count); + for(int i=0; imap_test(); + for(int i=0; imap_test(); + for(int i=0; ipair(keys[i],values[i]); + if(!map_test.Remove(GetPointer(pair))) + return(false); + } +//--- check + if(map_test.Count()!=0) + return(false); +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestMisc. | +//+------------------------------------------------------------------+ +bool TestMisc(const string test_name) + { + PrintFormat("%s started",test_name); +//--- test 1 + PrintFormat("%s: Test 1: Testing Constructor of map based on another map.",test_name); + if(!TestMisc_Constructor(16)) + return(false); +//--- test 2 + PrintFormat("%s: Test 2: Complex validation of Contains, ContainsKey and ContainsValues methods.",test_name); + if(!TestMisc_Contains(16)) + return(false); +//--- test 3 + PrintFormat("%s: Test 3: Complex validation of Remove method for elements which contains and does not conatains in the map.",test_name); + if(!TestMisc_Remove(16)) + return(false); +//--- successful + PrintFormat("%s passed",test_name); + return(true); + } +//+------------------------------------------------------------------+ +//| TestHashMap. | +//+------------------------------------------------------------------+ +void TestHashMap(int &tests_performed,int &tests_passed) + { + string test_name=""; +//--- Misc functions + tests_performed++; + test_name="Misc functions test"; + if(TestMisc(test_name)) + tests_passed++; + else + PrintFormat("%s failed",test_name); + } +//+------------------------------------------------------------------+ +//| Script program start function | +//+------------------------------------------------------------------+ +void OnStart() + { + MathSrand(0); + string package_name="Generic"; + PrintFormat("Unit tests for Package %s\n",package_name); +//--- initial values + int tests_performed=0; + int tests_passed=0; +//--- test distributions + TestHashMap(tests_performed,tests_passed); +//--- print statistics + PrintFormat("\n%d of %d passed",tests_passed,tests_performed); + } +//+------------------------------------------------------------------+ diff --git a/Scripts/UnitTests/Generic/TestHashSet.mq5 b/Scripts/UnitTests/Generic/TestHashSet.mq5 new file mode 100644 index 0000000..7e08bb4 --- /dev/null +++ b/Scripts/UnitTests/Generic/TestHashSet.mq5 @@ -0,0 +1,147 @@ +//+------------------------------------------------------------------+ +//| TestHashSet.mq5 | +//| Copyright 2017, MetaQuotes Software Corp. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include +//+------------------------------------------------------------------+ +//| TestMisc_Constructor. | +//+------------------------------------------------------------------+ +bool TestMisc_Constructor(const int count) + { +//--- create array + int array[]; + ArrayResize(array,count); + for(int i=0; icomparer(); + CHashSetset_test1(array); + CHashSetset_test2(array_duplicates,GetPointer(comparer)); +//--- check + if(set_test1.Count()!=set_test2.Count()) + return(false); + if(GetPointer(comparer)==set_test1.Comparer()) + return(false); + if(GetPointer(comparer)!=set_test2.Comparer()) + return(false); +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestMisc_TrimExpress. | +//+------------------------------------------------------------------+ +bool TestMisc_TrimExpress(const int count) + { +//--- create array + int array[]; + ArrayResize(array,count); + for(int i=0; iset_test(); + for(int i=0; i +#include +//+------------------------------------------------------------------+ +//| TestAddAfter_Node. | +//+------------------------------------------------------------------+ +bool TestAddAfter_Node(const int count) + { + CLinkedListlist_test(); +//--- create test arrays + int check_array[]; + int temp_items[]; + int head_items[]; + int head_reverse_items[]; + int tail_items[]; + ArrayResize(temp_items,count); + ArrayResize(head_items,count); + ArrayResize(head_reverse_items,count); + ArrayResize(tail_items,count); + for(int i=0; i*node=list_test.AddFirst(head_items[0]); + list_test.AddAfter(node,-1); +//--- check + list_test.CopyTo(check_array); + if(check_array[0]!=head_items[0] && check_array[1]!=-1) + return(false); +//--- clear + list_test.Clear(); + +//--- test node in the head +//--- add values + list_test.AddFirst(head_items[0]); + ArrayCopy(temp_items,head_items); + ArrayReverse(temp_items,1,count-1); + for(int i=1; ilist_test(); + CLinkedListlist_temp(); + +//--- test verify null node +//--- check + if(list_test.AddAfter(NULL,0)!=NULL) + return(false); + if(list_test.Count()!=0) + return(false); + +//--- test verify Node that is a new Node +//--- add values + list_test.AddLast(0); + CLinkedListNodenode(1); +//--- check + if(list_test.AddAfter(GetPointer(node),-1)!=NULL) + return(false); + if(list_test.Count()!=1) + return(false); +//--- clear + list_test.Clear(); + +//--- test verify Node that already exists in another collection +//--- add values + list_test.AddLast(MathRand()); + list_test.AddLast(MathRand()); + list_temp.AddLast(MathRand()); + list_temp.AddLast(MathRand()); +//--- check + if(list_test.AddAfter(list_temp.Last(),MathRand())!=NULL) + return(false); + if(list_test.Count()!=2) + return(false); + +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestAddAfter. | +//+------------------------------------------------------------------+ +bool TestAddAfter(const string test_name) + { + PrintFormat("%s started",test_name); +//--- test 1 + PrintFormat("%s: Test 1: Complex validation of AddAfter method for head node, tail node, some node in the middle, "+ + "also testing after remove several element, remove all element and cleaning of list.",test_name); + if(!TestAddAfter_Node(16)) + return(false); +//--- test 2 + PrintFormat("%s: Test 2: Validation of AddAfter method for incorrect node.",test_name); + if(!TestAddAfter_Node_Negative(16)) + return(false); +//--- successful + PrintFormat("%s passed",test_name); + return(true); + } +//+------------------------------------------------------------------+ +//| TestAddBefore_Node. | +//+------------------------------------------------------------------+ +bool TestAddBefore_Node(const int count) + { + CLinkedListlist_test(); +//--- create test arrays + int check_array[]; + int temp_items[]; + int head_items[]; + int head_reverse_items[]; + int tail_items[]; + int tail_reverse_items[]; + ArrayResize(temp_items,count); + ArrayResize(head_items,count); + ArrayResize(head_reverse_items,count); + ArrayResize(tail_items,count); + ArrayResize(tail_reverse_items,count); + for(int i=0; ilist_test(); + CLinkedListlist_temp(); + +//--- test verify null node +//--- check + if(list_test.AddBefore(NULL,0)!=NULL) + return(false); + if(list_test.Count()!=0) + return(false); + +//--- test verify Node that is a new Node +//--- add values + list_test.AddLast(0); + CLinkedListNodenode(1); +//--- check + if(list_test.AddBefore(GetPointer(node),-1)!=NULL) + return(false); + if(list_test.Count()!=1) + return(false); +//--- clear + list_test.Clear(); + +//--- test verify Node that already exists in another collection +//--- add values + list_test.AddLast(MathRand()); + list_test.AddLast(MathRand()); + list_temp.AddLast(MathRand()); + list_temp.AddLast(MathRand()); +//--- check + if(list_test.AddBefore(list_temp.Last(),MathRand())!=NULL) + return(false); + if(list_test.Count()!=2) + return(false); + +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestAddBefore. | +//+------------------------------------------------------------------+ +bool TestAddBefore(const string test_name) + { + PrintFormat("%s started",test_name); +//--- test 1 + PrintFormat("%s: Test 1: Complex validation of AddBefore method for head node, tail node, some node in the middle, "+ + "also testing after remove several element, remove all element and cleaning of list.",test_name); + if(!TestAddBefore_Node(16)) + return(false); +//--- test 2 + PrintFormat("%s: Test 2: Validation of AddBefore method for incorrect node.",test_name); + if(!TestAddBefore_Node_Negative(16)) + return(false); +//--- successful + PrintFormat("%s passed",test_name); + return(true); + } +//+------------------------------------------------------------------+ +//| TestAddFirst_Node. | +//+------------------------------------------------------------------+ +bool TestAddFirst_Node(const int count) + { + CLinkedListlist_test(); +//--- create test arrays + int check_array[]; + int temp_items[]; + int head_items[]; + int head_reverse_items[]; + int tail_items[]; + int tail_reverse_items[]; + ArrayResize(temp_items,count); + ArrayResize(head_items,count); + ArrayResize(head_reverse_items,count); + ArrayResize(tail_items,count); + ArrayResize(tail_reverse_items,count); + for(int i=0; ilist_test(); + CLinkedListlist_temp(); + +//--- test verify null node +//--- check + if(list_test.AddFirst((CLinkedListNode*)NULL)==true) + return(false); + if(list_test.Count()!=0) + return(false); + +//--- test verify Node that is a new Node +//--- add values + list_test.AddLast(0); + CLinkedListNodenode(1); +//--- check + if(list_test.AddFirst(list_test.First())==true) + return(false); + if(list_test.Count()!=1) + return(false); +//--- clear + list_test.Clear(); + +//--- test verify Node that already exists in another collection +//--- add values + list_test.AddLast(MathRand()); + list_test.AddLast(MathRand()); +//--- check + if(list_test.AddFirst(list_test.Last())==true) + return(false); + if(list_test.Count()!=2) + return(false); +//--- clear + list_test.Clear(); + +//--- test verify Node that already exists in another collection +//--- add values + list_test.AddLast(MathRand()); + list_test.AddLast(MathRand()); + list_temp.AddLast(MathRand()); + list_temp.AddLast(MathRand()); +//--- check + if(list_test.AddFirst(list_temp.Last())==true) + return(false); + if(list_test.Count()!=2) + return(false); + +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestAddFirst. | +//+------------------------------------------------------------------+ +bool TestAddFirst(const string test_name) + { + PrintFormat("%s started",test_name); +//--- test 1 + PrintFormat("%s: Test 1: Complex validation of AddFirst method after remove several element, remove all, several calling method of clearing.",test_name); + if(!TestAddFirst_Node(16)) + return(false); +//--- test 2 + PrintFormat("%s: Test 2: Validation of AddFirst method for incorrect node.",test_name); + if(!TestAddFirst_Node_Negative(16)) + return(false); +//--- successful + PrintFormat("%s passed",test_name); + return(true); + } +//+------------------------------------------------------------------+ +//| TestAddLast_Node. | +//+------------------------------------------------------------------+ +bool TestAddLast_Node(const int count) + { + CLinkedListlist_test(); +//--- create test arrays + int check_array[]; + int temp_items[]; + int head_items[]; + int head_reverse_items[]; + int tail_items[]; + int tail_reverse_items[]; + ArrayResize(temp_items,count); + ArrayResize(head_items,count); + ArrayResize(head_reverse_items,count); + ArrayResize(tail_items,count); + ArrayResize(tail_reverse_items,count); + for(int i=0; ilist_test(); + CLinkedListlist_temp(); + +//--- test verify null node +//--- check + if(list_test.AddLast((CLinkedListNode*)NULL)==true) + return(false); + if(list_test.Count()!=0) + return(false); + +//--- test verify Node that is a new Node +//--- add values + list_test.AddLast(0); + CLinkedListNodenode(1); +//--- check + if(list_test.AddLast(list_test.First())==true) + return(false); + if(list_test.Count()!=1) + return(false); +//--- clear + list_test.Clear(); + +//--- test verify Node that already exists in another collection +//--- add values + list_test.AddLast(MathRand()); + list_test.AddLast(MathRand()); +//--- check + if(list_test.AddLast(list_test.Last())==true) + return(false); + if(list_test.Count()!=2) + return(false); +//--- clear + list_test.Clear(); + +//--- test verify Node that already exists in another collection +//--- add values + list_test.AddLast(MathRand()); + list_test.AddLast(MathRand()); + list_temp.AddLast(MathRand()); + list_temp.AddLast(MathRand()); +//--- check + if(list_test.AddLast(list_temp.Last())==true) + return(false); + if(list_test.Count()!=2) + return(false); + +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestAddLast. | +//+------------------------------------------------------------------+ +bool TestAddLast(const string test_name) + { + PrintFormat("%s started",test_name); +//--- test 1 + PrintFormat("%s: Test 1: Complex validation of AddLast method after remove several element, remove all, several calling method of clearing.",test_name); + if(!TestAddLast_Node(16)) + return(false); +//--- test 2 + PrintFormat("%s: Test 2: Validation of AddLast method for incorrect node.",test_name); + if(!TestAddLast_Node_Negative(16)) + return(false); +//--- successful + PrintFormat("%s passed",test_name); + return(true); + } +//+------------------------------------------------------------------+ +//| TestConstructor_Complex. | +//+------------------------------------------------------------------+ +bool TestConstructor_Complex(const int count) + { +//--- create source array and list + int array[]; + ArrayResize(array,count); + for(int i=0; ilist(array); +//--- crete linked list + CLinkedListllist1(array); + CLinkedListllist2(GetPointer(list)); + CLinkedListllist3(GetPointer(llist1)); + CLinkedListllist4(NULL); +//--- check + int check_array1[]; + llist1.CopyTo(check_array1); + if(ArrayCompare(check_array1,array)!=0) + return(false); + int check_array2[]; + llist1.CopyTo(check_array2); + if(ArrayCompare(check_array2,array)!=0) + return(false); + int check_array3[]; + llist1.CopyTo(check_array3); + if(ArrayCompare(check_array3,array)!=0) + return(false); + if(llist4.Count()!=0) + return(false); + +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestConstructor. | +//+------------------------------------------------------------------+ +bool TestConstructor(const string test_name) + { + PrintFormat("%s started",test_name); +//--- test 1 + PrintFormat("%s: Test 1: Complex validation constructor of linked list dased on array, several ICollection objects and NULL object.",test_name); + if(!TestConstructor_Complex(16)) + return(false); +//--- successful + PrintFormat("%s passed",test_name); + return(true); + } +//+------------------------------------------------------------------+ +//| TestMisc_Find. | +//+------------------------------------------------------------------+ +bool TestMisc_Find(const int count) + { + CLinkedListlist_test(); +//--- create test arrays + int check_array[]; + int head_items[]; + int tail_items[]; + int head_prepend_items[]; + int tail_prepend_items[]; + ArrayResize(head_items,count); + ArrayResize(tail_items,count); + ArrayResize(head_prepend_items,count+1); + ArrayResize(tail_prepend_items,count+1); + head_prepend_items[0]=-1; + tail_prepend_items[0]=-1; + for(int i=0; ilist_test(); +//--- create test arrays + int check_array[]; + int head_items[]; + int tail_items[]; + int head_prepend_items[]; + int tail_prepend_items[]; + ArrayResize(head_items,count); + ArrayResize(tail_items,count); + ArrayResize(head_prepend_items,count+1); + ArrayResize(tail_prepend_items,count+1); + head_prepend_items[0]=-1; + tail_prepend_items[0]=-1; + for(int i=0; ilist_test(); + int temp_value1; + int temp_value2; + int temp_value3; +//--- create test arrays + int check_array[]; + int head_items[]; + int tail_items[]; + int temp_items[]; + ArrayResize(head_items,count); + ArrayResize(tail_items,count); + for(int i=0; i*nodes[]; + CLinkedListNode*current_node=list_test.First(); + int index=0; + ArrayResize(nodes,count*2); + while(index*)NULL) && list_test.Remove(0)) + return(false); + +//--- test verify Node that is a new Node +//--- add values + list_test.AddLast(0); + CLinkedListNodenode(1); +//--- check + if(list_test.Remove(GetPointer(node))) + return(false); +//--- clear + list_test.Clear(); + +//--- test verify Node that already exists in another collection + list_test.AddLast(MathRand()); + list_test.AddLast(MathRand()); + CLinkedListother(); + other.AddLast(MathRand()); + other.AddLast(MathRand()); + if(list_test.Remove(other.Last())) + return(false); + +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestMisc_RemoveFirst. | +//+------------------------------------------------------------------+ +bool TestMisc_RemoveFirst(const int count) + { + CLinkedListlist_test(); + int temp_value1; + int temp_value2; + int temp_value3; +//--- create test arrays + int check_array[]; + int head_items[]; + int tail_items[]; + int temp_items[]; + ArrayResize(head_items,count); + ArrayResize(tail_items,count); + ArrayResize(temp_items,count); + for(int i=0; ilist_test(); + int temp_value1; + int temp_value2; + int temp_value3; +//--- create test arrays + int check_array[]; + int head_items[]; + int tail_items[]; + int temp_items[]; + ArrayResize(head_items,count); + ArrayResize(tail_items,count); + ArrayResize(temp_items,count); + for(int i=0; i +#include +//+------------------------------------------------------------------+ +//| TestConstructor_Valid. | +//+------------------------------------------------------------------+ +bool TestConstructor_Valid(const int count) + { +//--- create random array + int array[]; + ArrayResize(array,count); + for(int i=0; ilist(array); +//--- create source queue + CQueuequeue_test1(array); + CQueuequeue_test2(GetPointer(list)); + CQueuequeue_test3(count); + for(int i=0; iqueue_test1(-1); + CQueuequeue_test2(INT_MIN); +//--- check + if(queue_test1.Count()!=0) + return(false); + if(queue_test2.Count()!=0) + return(false); +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestConstructor. | +//+------------------------------------------------------------------+ +bool TestConstructor(const string test_name) + { + PrintFormat("%s started",test_name); +//--- test 1 + PrintFormat("%s: Test 1: Testing Constructor of queue with array, ICollection object and correct capacity.",test_name); + if(!TestConstructor_Valid(10)) + return(false); +//--- test 2 + PrintFormat("%s: Test 2: Testing Constructor of queue with incorrect capacity.",test_name); + if(!TestConstructor_Invalid(10)) + return(false); +//--- successful + PrintFormat("%s passed",test_name); + return(true); + } +//+------------------------------------------------------------------+ +//| TestMisc_Dequeue. | +//+------------------------------------------------------------------+ +bool TestMisc_Dequeue(const int count) + { +//--- create random array + int array[]; + ArrayResize(array,count); + for(int i=0; iqueue_test(array); +//--- check elements + for(int i=0; iqueue_test(array); +//--- check element + if(queue_test.Peek()!=array[0]) + return(false); +//--- check count + if(queue_test.Count()!=count) + return(false); +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestMisc_Complex. | +//+------------------------------------------------------------------+ +bool TestMisc_Complex(const int count) + { +//--- create random array + int array[]; + ArrayResize(array,count); + for(int i=0; iqueue_test(count); +//--- enqueue values + for(int i=0; iqueue_test(array); +//--- trim + queue_test.TrimExcess(); + int removed=queue_test.Dequeue(); + queue_test.TrimExcess(); +//--- check element + if(queue_test.Peek()!=array[1]) + return(false); +//--- check count + if(queue_test.Count()!=count-1) + return(false); +//--- trim and clear + queue_test.TrimExcess(); + queue_test.Clear(); + queue_test.TrimExcess(); +//--- check count + if(queue_test.Count()!=0) + return(false); +//--- add elemnt and trim + queue_test.Add(0); + queue_test.TrimExcess(); +//--- check count + if(queue_test.Count()!=1) + return(false); +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestMisc. | +//+------------------------------------------------------------------+ +bool TestMisc(const string test_name) + { + PrintFormat("%s started",test_name); +//--- test 1 + PrintFormat("%s: Test 1: Validation of Dequeue method for all element of the queue and check count after.",test_name); + if(!TestMisc_Dequeue(10)) + return(false); +//--- test 2 + PrintFormat("%s: Test 2: Validation of Peek method for all element of the queue and check count after.",test_name); + if(!TestMisc_Peek(10)) + return(false); +//--- test 3 + PrintFormat("%s: Test 3: Complex validation of Enqueue and Dequeue methods.",test_name); + if(!TestMisc_Complex(10)) + return(false); +//--- test 4 + PrintFormat("%s: Test 4: Testing TrimExcess method on the queue after filling, clearing and adding elements.",test_name); + if(!TestMisc_TrimExcess(10)) + return(false); +//--- successful + PrintFormat("%s passed",test_name); + return(true); + } +//+------------------------------------------------------------------+ +//| TestQueue. | +//+------------------------------------------------------------------+ +void TestQueue(int &tests_performed,int &tests_passed) + { + string test_name=""; +//--- Constructor functions + tests_performed++; + test_name="TestConstructor functions test"; + if(TestConstructor(test_name)) + tests_passed++; + else + PrintFormat("%s failed",test_name); + +//--- AddRange functions + tests_performed++; + test_name="TestMisc functions test"; + if(TestMisc(test_name)) + tests_passed++; + else + PrintFormat("%s failed",test_name); + } +//+------------------------------------------------------------------+ +//| Script program start function | +//+------------------------------------------------------------------+ +void OnStart() + { + MathSrand(0); + string package_name="Generic"; + PrintFormat("Unit tests for Package %s\n",package_name); +//--- initial values + int tests_performed=0; + int tests_passed=0; +//--- test distributions + TestQueue(tests_performed,tests_passed); +//--- print statistics + PrintFormat("\n%d of %d passed",tests_passed,tests_performed); + } +//+------------------------------------------------------------------+ diff --git a/Scripts/UnitTests/Generic/TestRedBlackTree.mq5 b/Scripts/UnitTests/Generic/TestRedBlackTree.mq5 new file mode 100644 index 0000000..53d5cb0 --- /dev/null +++ b/Scripts/UnitTests/Generic/TestRedBlackTree.mq5 @@ -0,0 +1,361 @@ +//+------------------------------------------------------------------+ +//| TestRedBlackTree.mq5 | +//| Copyright 2017, MetaQuotes Software Corp. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include +#include +//+------------------------------------------------------------------+ +//| TestMisc_Constructor. | +//+------------------------------------------------------------------+ +bool TestMisc_Constructor(const int count) + { +//--- create list + CArrayListlist(count); + for(int i=0; icomparer(); + CRedBlackTreetree_test1(GetPointer(list),GetPointer(comparer)); + CRedBlackTreetree_test2(GetPointer(tree_test1)); +//--- check + if(tree_test1.Count()!=tree_test2.Count()) + return(false); + if(tree_test1.Comparer()!=GetPointer(comparer)) + return(false); + if(tree_test2.Comparer()==GetPointer(comparer)) + return(false); +//--- get unique sorted values + CHashSetset(GetPointer(list)); + int expected[]; + set.CopyTo(expected); + ArraySort(expected); +//--- check + int actual1[]; + int actual2[]; + tree_test1.CopyTo(actual1); + tree_test1.CopyTo(actual2); + for(int i=0; ilist(count); + for(int i=0; itree_test(GetPointer(list)); +//--- check + for(int i=0; ilist(count); + for(int i=0; itree_test(GetPointer(list)); +//--- check + if(tree_test.Count()>count) + return(false); +//--- create new unique element + int element=MathRand(); + while(tree_test.Contains(element)) + element=MathRand(); +//--- add new unique element + if(!tree_test.Add(element)) + return(false); + if(tree_test.Add(element)) + return(false); +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestMisc. | +//+------------------------------------------------------------------+ +bool TestMisc(const string test_name) + { + PrintFormat("%s started",test_name); +//--- test 1 + PrintFormat("%s: Test 1: Testing Constructor of map based on several different ICollection objects with and without comparer.",test_name); + if(!TestMisc_Constructor(16)) + return(false); +//--- test 2 + PrintFormat("%s: Test 2: Validation of Contains method before and after cleaning the tree.",test_name); + if(!TestMisc_Contains(16)) + return(false); +//--- test 3 + PrintFormat("%s: Test 3: Simple validation of Add method.",test_name); + if(!TestMisc_Add(16)) + return(false); +//--- successful + PrintFormat("%s passed",test_name); + return(true); + } +//+------------------------------------------------------------------+ +//| TestFind_Max. | +//+------------------------------------------------------------------+ +bool TestFind_Max(const int count) + { +//--- create list + CArrayListlist(count); + for(int i=0; itree_test(GetPointer(list)); +//--- get max + list.Sort(); + CRedBlackTreeNode*max_node=tree_test.FindMax(); + int expected; + list.TryGetValue(count-1,expected); + int actual=max_node.Value(); +//--- check + if(expected!=actual) + return(false); + if(tree_test.Find(expected)!=max_node) + return(false); +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestFind_Min. | +//+------------------------------------------------------------------+ +bool TestFind_Min(const int count) + { +//--- create list + CArrayListlist(count); + for(int i=0; itree_test(GetPointer(list)); +//--- get max + list.Sort(); + CRedBlackTreeNode*min_node=tree_test.FindMin(); + int expected; + list.TryGetValue(0, expected); + int actual=min_node.Value(); +//--- check + if(expected!=actual) + return(false); + if(tree_test.Find(expected)!=min_node) + return(false); +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestFind. | +//+------------------------------------------------------------------+ +bool TestFind(const string test_name) + { + PrintFormat("%s started",test_name); +//--- test 1 + PrintFormat("%s: Test 1: Simple validation of FindMax method for tree.",test_name); + if(!TestFind_Max(16)) + return(false); +//--- test 2 + PrintFormat("%s: Test 2: Simple validation of FindMin method for tree.",test_name); + if(!TestFind_Min(16)) + return(false); +//--- successful + PrintFormat("%s passed",test_name); + return(true); + } +//+------------------------------------------------------------------+ +//| TestRemove_Node. | +//+------------------------------------------------------------------+ +bool TestRemove_Node(const int count) + { +//--- create list + CArrayListlist(count); + for(int i=0; itree_test(GetPointer(list)); +//--- get max and min + list.Sort(); + int min; + int max; + list.TryGetValue(0, min); + list.TryGetValue(count-1, max); +//--- check + if(tree_test.Count()>0) + { + //--- remove min value + if(!tree_test.Remove(min)) + return(false); + } + if(tree_test.Count()>0) + { + //--- remove max node + CRedBlackTreeNode*node=tree_test.FindMax(); + if(!tree_test.Remove(node)) + return(false); + } +//--- get unique sorted values + CHashSetset(GetPointer(list)); + set.Remove(min); + set.Remove(max); + int expected[]; + set.CopyTo(expected); + ArraySort(expected); +//--- check + int actual[]; + tree_test.CopyTo(actual); + if(ArrayCompare(expected,actual)!=0) + return(false); +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestRemove_Max. | +//+------------------------------------------------------------------+ +bool TestRemove_Max(const int count) + { +//--- create list + CArrayListlist(count); + for(int i=0; itree_test(GetPointer(list)); +//--- get unique sorted values + CHashSetset(GetPointer(list)); + int expected[]; + set.CopyTo(expected); + ArraySort(expected); +//--- check + for(int i=0; ilist(count); + for(int i=0; itree_test(GetPointer(list)); +//--- get unique sorted values + CHashSetset(GetPointer(list)); + int expected[]; + set.CopyTo(expected); + ArraySort(expected); +//--- check + for(int i=0; i +#include +//+------------------------------------------------------------------+ +//| TestMisc_Constructor. | +//+------------------------------------------------------------------+ +bool TestMisc_Constructor(const int count) + { +//--- create arrays + int keys[]; + string values[]; + ArrayResize(keys,count); + ArrayResize(values,count); + for(int i=0; icomparer(); + CSortedMapmap_test(GetPointer(comparer)); + for(int i=0; imap_copy(GetPointer(map_test)); +//--- check + if(map_copy.Count()!=map_test.Count()) + return(false); + if(map_test.Comparer()!=GetPointer(comparer)) + return(false); + if(map_copy.Comparer()==GetPointer(comparer)) + return(false); +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestMisc_Contains. | +//+------------------------------------------------------------------+ +bool TestMisc_Contains(const int count) + { +//--- create arrays + int keys[]; + string values[]; + ArrayResize(keys,count); + ArrayResize(values,count); + for(int i=0; imap_test(); + for(int i=0; imap_test(); + for(int i=0; i*pairs[]; + int size=map_test.CopyTo(pairs); +//--- check + CDefaultComparer*>comparer(); + CArrayList*>expected(pairs); + expected.Sort(GetPointer(comparer)); + int actual_keys[]; + string actual_values[]; + map_test.CopyTo(actual_keys,actual_values); + for(int i=0; i*pair; + expected.TryGetValue(i,pair); + if(pair.Key()!=actual_keys[i] || pair.Value()!=actual_values[i]) + return(false); + //--- check TryGetValue + string value; + if(!map_test.TryGetValue(pair.Key(),value)) + return(false); + if(pair.Value()!=value) + return(false); + } +//--- delete pairs + for(int i=0; i*pair; + expected.TryGetValue(i,pair); + delete pair; + } +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestMisc. | +//+------------------------------------------------------------------+ +bool TestMisc(const string test_name) + { + PrintFormat("%s started",test_name); +//--- test 1 + PrintFormat("%s: Test 1: Testing Constructor of map based on another map.",test_name); + if(!TestMisc_Constructor(16)) + return(false); +//--- test 2 + PrintFormat("%s: Test 2: Complex validation of Contains, ContainsKey and ContainsValues methods.",test_name); + if(!TestMisc_Contains(16)) + return(false); +//--- test 3 + PrintFormat("%s: Test 3: Testing the ordering of elements in the map.",test_name); + if(!TestMisc_Ordering(16)) + return(false); +//--- successful + PrintFormat("%s passed",test_name); + return(true); + } +//+------------------------------------------------------------------+ +//| TestSortedMap. | +//+------------------------------------------------------------------+ +void TestSortedMap(int &tests_performed,int &tests_passed) + { + string test_name=""; +//--- Misc functions + tests_performed++; + test_name="Misc functions test"; + if(TestMisc(test_name)) + tests_passed++; + else + PrintFormat("%s failed",test_name); + } +//+------------------------------------------------------------------+ +//| Script program start function | +//+------------------------------------------------------------------+ +void OnStart() + { + MathSrand(0); + string package_name="Generic"; + PrintFormat("Unit tests for Package %s\n",package_name); +//--- initial values + int tests_performed=0; + int tests_passed=0; +//--- test distributions + TestSortedMap(tests_performed,tests_passed); +//--- print statistics + PrintFormat("\n%d of %d passed",tests_passed,tests_performed); + } +//+------------------------------------------------------------------+ diff --git a/Scripts/UnitTests/Generic/TestSortedSet.mq5 b/Scripts/UnitTests/Generic/TestSortedSet.mq5 new file mode 100644 index 0000000..8744e0d --- /dev/null +++ b/Scripts/UnitTests/Generic/TestSortedSet.mq5 @@ -0,0 +1,147 @@ +//+------------------------------------------------------------------+ +//| TestSortedSet.mq5 | +//| Copyright 2017, MetaQuotes Software Corp. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include +//+------------------------------------------------------------------+ +//| TestMisc_Constructor. | +//+------------------------------------------------------------------+ +bool TestMisc_Constructor(const int count) + { +//--- create array + int array[]; + ArrayResize(array,count); + for(int i=0; icomparer(); + CSortedSetset_test1(array); + CSortedSetset_test2(array_duplicates,GetPointer(comparer)); +//--- check + if(set_test1.Count()!=set_test2.Count()) + return(false); + if(GetPointer(comparer)==set_test1.Comparer()) + return(false); + if(GetPointer(comparer)!=set_test2.Comparer()) + return(false); +//--- check ordering of the first set + int check_array[]; + set_test1.CopyTo(check_array); + for(int i=0; i0 && check_array[i]>check_array[i+1]) + return(false); +//--- check ordering of the second set + ArrayFree(check_array); + set_test2.CopyTo(check_array); + for(int i=0; i0 && check_array[i]>check_array[i+1]) + return(false); +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestMisc_GetViewBetween. | +//+------------------------------------------------------------------+ +bool TestMisc_GetViewBetween(const int count) + { + int view[]; + int check_array[]; +//--- create array + int array[]; + ArrayResize(array,count); + for(int i=0; iset_test(array); +//--- calculate max and min + int min = array[ArrayMinimum(array)]; + int max = array[ArrayMaximum(array)]; + if(!set_test.GetViewBetween(view,min,max)) + return(false); +//--- get view + set_test.GetViewBetween(view,min,max); +//--- check + set_test.CopyTo(check_array); + if(ArrayCompare(check_array,view)!=0) + return(false); +//--- lower value greater than upper value + min=array[ArrayMaximum(array)]; + max=array[ArrayMinimum(array)]; +//--- get view + ArrayFree(view); + if(set_test.GetViewBetween(view,min,max)) + return(false); +//--- check + if(ArraySize(view)!=0) + return(false); +//--- minimum lower value and maximum upper value + min=INT_MIN; + max=INT_MAX; +//--- get view + ArrayFree(view); + if(!set_test.GetViewBetween(view,min,max)) + return(false); +//--- check + if(ArrayCompare(check_array,view)!=0) + return(false); +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestMisc. | +//+------------------------------------------------------------------+ +bool TestMisc(const string test_name) + { + PrintFormat("%s started",test_name); +//--- test 1 + PrintFormat("%s: Test 1: Testing Constructor of set based of array with and without duplicates.",test_name); + if(!TestMisc_Constructor(16)) + return(false); +//--- test 2 + PrintFormat("%s: Test 2: Complex validation of GetViewBetween method with correct and incorrect input parameters.",test_name); + if(!TestMisc_GetViewBetween(16)) + return(false); +//--- successful + PrintFormat("%s passed",test_name); + return(true); + } +//+------------------------------------------------------------------+ +//| TestSortedSet. | +//+------------------------------------------------------------------+ +void TestSortedSet(int &tests_performed,int &tests_passed) + { + string test_name=""; +//--- Misc functions + tests_performed++; + test_name="Misc functions test"; + if(TestMisc(test_name)) + tests_passed++; + else + PrintFormat("%s failed",test_name); + } +//+------------------------------------------------------------------+ +//| Script program start function | +//+------------------------------------------------------------------+ +void OnStart() + { + MathSrand(0); + string package_name="Generic"; + PrintFormat("Unit tests for Package %s\n",package_name); +//--- initial values + int tests_performed=0; + int tests_passed=0; +//--- test distributions + TestSortedSet(tests_performed,tests_passed); +//--- print statistics + PrintFormat("\n%d of %d passed",tests_passed,tests_performed); + } +//+------------------------------------------------------------------+ diff --git a/Scripts/UnitTests/Generic/TestStack.mq5 b/Scripts/UnitTests/Generic/TestStack.mq5 new file mode 100644 index 0000000..b6ed045 --- /dev/null +++ b/Scripts/UnitTests/Generic/TestStack.mq5 @@ -0,0 +1,259 @@ +//+------------------------------------------------------------------+ +//| TestStack.mq5 | +//| Copyright 2017, MetaQuotes Software Corp. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include +//+------------------------------------------------------------------+ +//| TestConstructor_Valid. | +//+------------------------------------------------------------------+ +bool TestConstructor_Valid(const int count) + { +//--- create random array + int array[]; + ArrayResize(array,count); + for(int i=0; ilist(array); +//--- create source stack + CStackstack_test1(array); + CStackstack_test2(GetPointer(list)); + CStackstack_test3(count); + for(int i=0; istack_test1(-1); + CStackstack_test2(INT_MIN); +//--- check + if(stack_test1.Count()!=0) + return(false); + if(stack_test2.Count()!=0) + return(false); +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestConstructor. | +//+------------------------------------------------------------------+ +bool TestConstructor(const string test_name) + { + PrintFormat("%s started",test_name); +//--- test 1 + PrintFormat("%s: Test 1: Testing Constructor of stack with array, ICollection object and correct capacity.",test_name); + if(!TestConstructor_Valid(10)) + return(false); +//--- test 2 + PrintFormat("%s: Test 2: Testing Constructor of stack with incorrect capacity.",test_name); + if(!TestConstructor_Invalid(10)) + return(false); +//--- successful + PrintFormat("%s passed",test_name); + return(true); + } +//+------------------------------------------------------------------+ +//| TestMisc_Pop. | +//+------------------------------------------------------------------+ +bool TestMisc_Pop(const int count) + { +//--- create random array + int array[]; + ArrayResize(array,count); + for(int i=0; istack_test(array); +//--- check elements + for(int i=0; istack_test(array); +//--- check element + if(stack_test.Peek()!=array[count-1]) + return(false); +//--- check count + if(stack_test.Count()!=count) + return(false); +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestMisc_Complex. | +//+------------------------------------------------------------------+ +bool TestMisc_Complex(const int count) + { +//--- create random array + int array[]; + ArrayResize(array,count); + for(int i=0; istack_test(count); +//--- push values + for(int i=0; istack_test(array); +//--- trim + stack_test.TrimExcess(); + int removed=stack_test.Pop(); + stack_test.TrimExcess(); +//--- check element + if(stack_test.Peek()!=array[count-2]) + return(false); +//--- check count + if(stack_test.Count()!=count-1) + return(false); +//--- trim and clear + stack_test.TrimExcess(); + stack_test.Clear(); + stack_test.TrimExcess(); +//--- check count + if(stack_test.Count()!=0) + return(false); +//--- add elemnt and trim + stack_test.Add(0); + stack_test.TrimExcess(); +//--- check count + if(stack_test.Count()!=1) + return(false); +//--- successful + return(true); + } +//+------------------------------------------------------------------+ +//| TestMisc. | +//+------------------------------------------------------------------+ +bool TestMisc(const string test_name) + { + PrintFormat("%s started",test_name); +//--- test 1 + PrintFormat("%s: Test 1: Validation of Pop method for all element of the stack and check count after.",test_name); + if(!TestMisc_Pop(10)) + return(false); +//--- test 2 + PrintFormat("%s: Test 2: Validation of Peek method for all element of the stack and check count after.",test_name); + if(!TestMisc_Peek(10)) + return(false); +//--- test 3 + PrintFormat("%s: Test 3: Complex validation of Push and Pop methods.",test_name); + if(!TestMisc_Complex(10)) + return(false); +//--- test 4 + PrintFormat("%s: Test 4: Testing TrimExcess method on the stack after filling, clearing and adding elements.",test_name); + if(!TestMisc_TrimExcess(10)) + return(false); +//--- successful + PrintFormat("%s passed",test_name); + return(true); + } +//+------------------------------------------------------------------+ +//| TestStack. | +//+------------------------------------------------------------------+ +void TestStack(int &tests_performed,int &tests_passed) + { + string test_name=""; +//--- Constructor functions + tests_performed++; + test_name="TestConstructor functions test"; + if(TestConstructor(test_name)) + tests_passed++; + else + PrintFormat("%s failed",test_name); + +//--- AddRange functions + tests_performed++; + test_name="TestMisc functions test"; + if(TestMisc(test_name)) + tests_passed++; + else + PrintFormat("%s failed",test_name); + } +//+------------------------------------------------------------------+ +//| Script program start function | +//+------------------------------------------------------------------+ +void OnStart() + { + MathSrand(0); + string package_name="Generic"; + PrintFormat("Unit tests for Package %s\n",package_name); +//--- initial values + int tests_performed=0; + int tests_passed=0; +//--- test distributions + TestStack(tests_performed,tests_passed); +//--- print statistics + PrintFormat("\n%d of %d passed",tests_passed,tests_performed); + } +//+------------------------------------------------------------------+ diff --git a/Scripts/UnitTests/Stat/TestStat.mq5 b/Scripts/UnitTests/Stat/TestStat.mq5 new file mode 100644 index 0000000..319e34f --- /dev/null +++ b/Scripts/UnitTests/Stat/TestStat.mq5 @@ -0,0 +1,4855 @@ +//+------------------------------------------------------------------+ +//| TestStat.mq5 | +//| Copyright 2016-2017, MetaQuotes Software Corp. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2016-2017, MetaQuotes Software Corp." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//--- precision +double calc_precision_pdf=10E-15; +double calc_precision_cdf=10E-15; +double calc_precision_quantile=10E-14; + +//--- test values (x,pdf,cdf) for Binomial distribution +const double binomial_x_values[]={0,1,2,3,4,5,6,7,8,9}; + +const double binomial_pdf_values[]= + { + 0.000104857600000000000000000000000, //N[PDF[BinomialDistribution[10,0.6],0],30] + 0.00157286400000000000000000000000, //N[PDF[BinomialDistribution[10,0.6],1],30] + 0.0106168320000000000000000000000, //N[PDF[BinomialDistribution[10,0.6],2],30] + 0.0424673280000000000000000000000, //N[PDF[BinomialDistribution[10,0.6],3],30] + 0.111476736000000000000000000000, //N[PDF[BinomialDistribution[10,0.6],4],30] + 0.200658124800000000000000000000, //N[PDF[BinomialDistribution[10,0.6],5],30] + 0.250822656000000000000000000000, //N[PDF[BinomialDistribution[10,0.6],6],30] + 0.214990848000000000000000000000, //N[PDF[BinomialDistribution[10,0.6],7],30] + 0.120932352000000000000000000000, //N[PDF[BinomialDistribution[10,0.6],8],30] + 0.0403107840000000000000000000000, //N[PDF[BinomialDistribution[10,0.6],9],30] + 0.00604661760000000000000000000000 //N[PDF[BinomialDistribution[10,0.6],10],30] + }; +const double binomial_cdf_values[]= + { + 0.000104857600000000000000000000000, //N[CDF[BinomialDistribution[10,0.6],0],30] + 0.00167772160000000000000000000000, //N[CDF[BinomialDistribution[10,0.6],1],30] + 0.0122945536000000000000000000000, //N[CDF[BinomialDistribution[10,0.6],2],30] + 0.0547618816000000000000000000000, //N[CDF[BinomialDistribution[10,0.6],3],30] + 0.166238617600000000000000000000, //N[CDF[BinomialDistribution[10,0.6],4],30] + 0.366896742400000000000000000000, //N[CDF[BinomialDistribution[10,0.6],5],30] + 0.617719398400000000000000000000, //N[CDF[BinomialDistribution[10,0.6],6],30] + 0.832710246400000000000000000000, //N[CDF[BinomialDistribution[10,0.6],7],30] + 0.953642598400000000000000000000, //N[CDF[BinomialDistribution[10,0.6],8],30] + 0.993953382400000000000000000000, //N[CDF[BinomialDistribution[10,0.6],9],30] + 1.00000000000000000000000000000 //N[CDF[BinomialDistribution[10,0.6],10],30] + }; + +//--- test values (x,pdf,cdf) for Beta distribution +const double beta_x_values[]={0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0}; +const double beta_pdf_values[]= + { + 0, //N[PDF[BetaDistribution[2,4],0.0],30] + 1.458, //N[PDF[BetaDistribution[2,4],0.1],30] + 2.048, //N[PDF[BetaDistribution[2,4],0.2],30] + 2.058, //N[PDF[BetaDistribution[2,4],0.3],30] + 1.728, //N[PDF[BetaDistribution[2,4],0.4],30] + 1.25, //N[PDF[BetaDistribution[2,4],0.5],30] + 0.768, //N[PDF[BetaDistribution[2,4],0.6],30] + 0.378, //N[PDF[BetaDistribution[2,4],0.7],30] + 0.128, //N[PDF[BetaDistribution[2,4],0.8],30] + 0.018, //N[PDF[BetaDistribution[2,4],0.9],30] + 0 //N[PDF[BetaDistribution[2,4],1.0],30] + }; +const double beta_cdf_values[]= + { + 0, //N[PDF[BetaDistribution[2,4],0.0],30] + 0.08146, //N[PDF[BetaDistribution[2,4],0.1],30] + 0.26272, //N[PDF[BetaDistribution[2,4],0.2],30] + 0.47178, //N[PDF[BetaDistribution[2,4],0.3],30] + 0.66304, //N[PDF[BetaDistribution[2,4],0.4],30] + 0.8125, //N[PDF[BetaDistribution[2,4],0.5],30] + 0.91296, //N[PDF[BetaDistribution[2,4],0.6],30] + 0.96922, //N[PDF[BetaDistribution[2,4],0.7],30] + 0.99328, //N[PDF[BetaDistribution[2,4],0.8],30] + 0.99954, //N[PDF[BetaDistribution[2,4],0.9],30] + 1 //N[PDF[BetaDistribution[2,4],1.0],30] + }; + +//--- test values (x,pdf,cdf) for Gamma distribution +const double gamma_x_values[]={0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0}; +const double gamma_pdf_values[]= + { + 0, //N[PDF[GammaDistribution[1,1],0.0],30] + 0.904837418035959573164249059446, //N[PDF[GammaDistribution[1,1],0.1],30] + 0.818730753077981858669935508619, //N[PDF[GammaDistribution[1,1],0.2],30] + 0.740818220681717866066873779318, //N[PDF[GammaDistribution[1,1],0.3],30] + 0.670320046035639300744432925148, //N[PDF[GammaDistribution[1,1],0.4],30] + 0.606530659712633423603799534991, //N[PDF[GammaDistribution[1,1],0.5],30] + 0.548811636094026432628458917233, //N[PDF[GammaDistribution[1,1],0.6],30] + 0.496585303791409514704800093398, //N[PDF[GammaDistribution[1,1],0.7],30] + 0.449328964117221591430102385016, //N[PDF[GammaDistribution[1,1],0.8],30] + 0.406569659740599111883454239646, //N[PDF[GammaDistribution[1,1],0.9],30] + 0.367879441171442321595523770161, //N[PDF[GammaDistribution[1,1],1.0],30] + }; +const double gamma_cdf_values[]= + { + 0, //N[CDF[GammaDistribution[1,1],0.0],30] + 0.0951625819640404268357509405536, //N[CDF[GammaDistribution[1,1],0.1],30] + 0.181269246922018141330064491381, //N[CDF[GammaDistribution[1,1],0.2],30] + 0.259181779318282133933126220682, //N[CDF[GammaDistribution[1,1],0.3],30] + 0.329679953964360699255567074852, //N[CDF[GammaDistribution[1,1],0.4],30] + 0.393469340287366576396200465009, //N[CDF[GammaDistribution[1,1],0.5],30] + 0.451188363905973567371541082767, //N[CDF[GammaDistribution[1,1],0.6],30] + 0.503414696208590485295199906602, //N[CDF[GammaDistribution[1,1],0.7],30] + 0.550671035882778408569897614984, //N[CDF[GammaDistribution[1,1],0.8],30] + 0.593430340259400888116545760354, //N[CDF[GammaDistribution[1,1],0.9],30] + 0.632120558828557678404476229839 //N[CDF[GammaDistribution[1,1],1.0],30] + }; + +//--- test values (x,pdf,cdf) for Cauchy distribution +const double cauchy_x_values[]={0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0}; +const double cauchy_pdf_values[]= + { + 0.0636619772367581343075535053490, // N[PDF[CauchyDistribution[2,1],0.0],30] + 0.0690476976537506879691469689252, // N[PDF[CauchyDistribution[2,1],0.1],30] + 0.0750730863641015734758885676285, // N[PDF[CauchyDistribution[2,1],0.2],30] + 0.0818277342374783217320739143303, // N[PDF[CauchyDistribution[2,1],0.3],30] + 0.0894128893774692897577998670632, // N[PDF[CauchyDistribution[2,1],0.4],30] + 0.0979415034411663604731592389985, // N[PDF[CauchyDistribution[2,1],0.5],30] + 0.107537123710740091735732272549, // N[PDF[CauchyDistribution[2,1],0.6],30] + 0.118330812707728874177608746002, // N[PDF[CauchyDistribution[2,1],0.7],30] + 0.130454871386799455548265379814, // N[PDF[CauchyDistribution[2,1],0.8],30] + 0.144031622707597588931116527939, // N[PDF[CauchyDistribution[2,1],0.9],30] + 0.159154943091895335768883763373 // N[PDF[CauchyDistribution[2,1],1.0],30] + }; +const double cauchy_cdf_values[]= + { + 0.147583617650433274175401076225, // N[CDF[CauchyDistribution[2,1],0.0],30] + 0.154214114450333468865873109512, // N[CDF[CauchyDistribution[2,1],0.1],30] + 0.161414467217095251124123947093, // N[CDF[CauchyDistribution[2,1],0.2],30] + 0.169253027330332663755853315960, // N[CDF[CauchyDistribution[2,1],0.3],30] + 0.177807684489352753115503587502, // N[CDF[CauchyDistribution[2,1],0.4],30] + 0.187167041810998816186252747565, // N[CDF[CauchyDistribution[2,1],0.5],30] + 0.197431543288746570049221830324, // N[CDF[CauchyDistribution[2,1],0.6],30] + 0.208714400160152736606325130038, // N[CDF[CauchyDistribution[2,1],0.7],30] + 0.221142061623695522257108276774, // N[CDF[CauchyDistribution[2,1],0.8],30] + 0.234853827811631858353234362662, // N[CDF[CauchyDistribution[2,1],0.9],30] + 0.250000000000000000000000000000 // N[CDF[CauchyDistribution[2,1],1.0],30] + }; + +//--- test values (x,pdf,cdf) for Exponential distribution +const double exponential_x_values[]={0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0}; +const double exponential_pdf_values[]= + { + 0.500000000000000000000000000000, // N[PDF[ExponentialyDistribution[1/2],0.0],30] + 0.475614712250357004545712659890, // N[PDF[ExponentialyDistribution[1/2],0.1],30] + 0.452418709017979786582124529723, // N[PDF[ExponentialyDistribution[1/2],0.2],30] + 0.430353988212528903614516882272, // N[PDF[ExponentialyDistribution[1/2],0.3],30] + 0.409365376538990929334967754310, // N[PDF[ExponentialyDistribution[1/2],0.4],30] + 0.389400391535702434122585133489, // N[PDF[ExponentialyDistribution[1/2],0.5],30] + 0.370409110340858933033436889659, // N[PDF[ExponentialyDistribution[1/2],0.6],30] + 0.352344044859356717177410349515, // N[PDF[ExponentialyDistribution[1/2],0.7],30] + 0.335160023017819650372216462574, // N[PDF[ExponentialyDistribution[1/2],0.8],30] + 0.318814075810886646571871719156, // N[PDF[ExponentialyDistribution[1/2],0.9],30] + 0.303265329856316711801899767496 // N[PDF[ExponentialyDistribution[1/2],1.0],30] + }; +const double exponential_cdf_values[]= + { + 0, // N[CDF[ExponentialyDistribution[1/2],0.0],30] + 0.0487705754992859909085746802203, // N[CDF[ExponentialyDistribution[1/2],0.1],30] + 0.0951625819640404268357509405536, // N[CDF[ExponentialyDistribution[1/2],0.2],30] + 0.139292023574942192770966235457, // N[CDF[ExponentialyDistribution[1/2],0.3],30] + 0.181269246922018141330064491381, // N[CDF[ExponentialyDistribution[1/2],0.4],30] + 0.221199216928595131754829733022, // N[CDF[ExponentialyDistribution[1/2],0.5],30] + 0.259181779318282133933126220682, // N[CDF[ExponentialyDistribution[1/2],0.6],30] + 0.295311910281286565645179300969, // N[CDF[ExponentialyDistribution[1/2],0.7],30] + 0.329679953964360699255567074852, // N[CDF[ExponentialyDistribution[1/2],0.8],30] + 0.362371848378226706856256561688, // N[CDF[ExponentialyDistribution[1/2],0.9],30] + 0.393469340287366576396200465009 // N[CDF[ExponentialyDistribution[1/2],1.0],30] + }; + +//--- test values (x,pdf,cdf) for Uniform distribution +const double uniform_x_values[]={0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0}; +const double uniform_pdf_values[]= + { + 0.100000000000000000000000000000, //N[PDF[UniformDistribution[0,10],0.0],30] + 0.100000000000000000000000000000, //N[PDF[UniformDistribution[0,10],0.1],30] + 0.100000000000000000000000000000, //N[PDF[UniformDistribution[0,10],0.2],30] + 0.100000000000000000000000000000, //N[PDF[UniformDistribution[0,10],0.3],30] + 0.100000000000000000000000000000, //N[PDF[UniformDistribution[0,10],0.4],30] + 0.100000000000000000000000000000, //N[PDF[UniformDistribution[0,10],0.5],30] + 0.100000000000000000000000000000, //N[PDF[UniformDistribution[0,10],0.6],30] + 0.100000000000000000000000000000, //N[PDF[UniformDistribution[0,10],0.7],30] + 0.100000000000000000000000000000, //N[PDF[UniformDistribution[0,10],0.8],30] + 0.100000000000000000000000000000, //N[PDF[UniformDistribution[0,10],0.9],30] + 0.100000000000000000000000000000, //N[PDF[UniformDistribution[0,10],1.0],30] + }; +const double uniform_cdf_values[]= + { + 0, //N[CDF[UniformDistribution[0,10],0.0],30] + 0.0100000000000000000000000000000, //N[CDF[UniformDistribution[0,10],0.1],30] + 0.0200000000000000000000000000000, //N[CDF[UniformDistribution[0,10],0.2],30] + 0.0300000000000000000000000000000, //N[CDF[UniformDistribution[0,10],0.3],30] + 0.0400000000000000000000000000000, //N[CDF[UniformDistribution[0,10],0.4],30] + 0.0500000000000000000000000000000, //N[CDF[UniformDistribution[0,10],0.5],30] + 0.0600000000000000000000000000000, //N[CDF[UniformDistribution[0,10],0.6],30] + 0.0700000000000000000000000000000, //N[CDF[UniformDistribution[0,10],0.7],30] + 0.0800000000000000000000000000000, //N[CDF[UniformDistribution[0,10],0.8],30] + 0.0900000000000000000000000000000, //N[CDF[UniformDistribution[0,10],0.9],30] + 0.100000000000000000000000000000 //N[CDF[UniformDistribution[0,10],1.0],30] + }; + +//--- test values (x,pdf,cdf) for Geometric distribution +const double geometric_x_values[]={0,1,2,3,4,5,6,7,8,9,10}; +const double geometric_pdf_values[]= + { + 0.300000000000000000000000000000, //N[PDF[GeometricDistribution[0.3],0],30] + 0.210000000000000000000000000000, //N[PDF[GeometricDistribution[0.3],1],30] + 0.147000000000000000000000000000, //N[PDF[GeometricDistribution[0.3],2],30] + 0.102900000000000000000000000000, //N[PDF[GeometricDistribution[0.3],3],30] + 0.0720300000000000000000000000000, //N[PDF[GeometricDistribution[0.3],4],30] + 0.0504210000000000000000000000000, //N[PDF[GeometricDistribution[0.3],5],30] + 0.0352947000000000000000000000000, //N[PDF[GeometricDistribution[0.3],6],30] + 0.0247062900000000000000000000000, //N[PDF[GeometricDistribution[0.3],7],30] + 0.0172944030000000000000000000000, //N[PDF[GeometricDistribution[0.3],8],30] + 0.0121060821000000000000000000000, //N[PDF[GeometricDistribution[0.3],9],30] + 0.00847425747000000000000000000000 //N[PDF[GeometricDistribution[0.3],10],30] + }; +const double geometric_cdf_values[]= + { + 0.300000000000000000000000000000, //N[CDF[GeometricDistribution[0.3],0],30] + 0.510000000000000000000000000000, //N[CDF[GeometricDistribution[0.3],1],30] + 0.657000000000000000000000000000, //N[CDF[GeometricDistribution[0.3],2],30] + 0.759900000000000000000000000000, //N[CDF[GeometricDistribution[0.3],3],30] + 0.831930000000000000000000000000, //N[CDF[GeometricDistribution[0.3],4],30] + 0.882351000000000000000000000000, //N[CDF[GeometricDistribution[0.3],5],30] + 0.917645700000000000000000000000, //N[CDF[GeometricDistribution[0.3],6],30] + 0.942351990000000000000000000000, //N[CDF[GeometricDistribution[0.3],7],30] + 0.959646393000000000000000000000, //N[CDF[GeometricDistribution[0.3],8],30] + 0.971752475100000000000000000000, //N[CDF[GeometricDistribution[0.3],9],30] + 0.980226732570000000000000000000, //N[CDF[GeometricDistribution[0.3],10],30] + }; +//--- test values (x,pdf,cdf) for Hypergeometric distribution +const double hypergeometric_x_values[]={0,1,2,3,4,5,6,7,8,9,10}; +const double hypergeometric_pdf_values[]= + { + 0.000582565859927179267509102591561, //N[PDF[HypergeometricDistribution[12,11,30],0],30] + 0.00961233668879845791390019276076, //N[PDF[HypergeometricDistribution[12,11,30],1],30] + 0.0587420575426572428071678446491, //N[PDF[HypergeometricDistribution[12,11,30],2],30] + 0.176226172627971728421503533947, //N[PDF[HypergeometricDistribution[12,11,30],3],30] + 0.288370100663953737417005782823, //N[PDF[HypergeometricDistribution[12,11,30],4],30] + 0.269145427286356821589205397301, //N[PDF[HypergeometricDistribution[12,11,30],5],30] + 0.144924460846499827009572137008, //N[PDF[HypergeometricDistribution[12,11,30],6],30] + 0.0443646308713774980641547358189, //N[PDF[HypergeometricDistribution[12,11,30],7],30] + 0.00739410514522958301069245596982, //N[PDF[HypergeometricDistribution[12,11,30],8],30] + 0.000616175428769131917557704664151, //N[PDF[HypergeometricDistribution[12,11,30],9],30] + 0.0000217473680742046559138013410877 //N[PDF[HypergeometricDistribution[12,11,30],10],30] + }; +const double hypergeometric_cdf_values[]= + { + 0.000582565859927179267509102591561, //N[CDF[HypergeometricDistribution[12,11,30],0],30] + 0.0101949025487256371814092953523, //N[CDF[HypergeometricDistribution[12,11,30],1],30] + 0.0689369600913828799885771400014, //N[CDF[HypergeometricDistribution[12,11,30],2],30] + 0.245163132719354608410080673949, //N[CDF[HypergeometricDistribution[12,11,30],3],30] + 0.533533233383308345827086456772, //N[CDF[HypergeometricDistribution[12,11,30],4],30] + 0.802678660669665167416291854073, //N[CDF[HypergeometricDistribution[12,11,30],5],30] + 0.947603121516164994425863991081, //N[CDF[HypergeometricDistribution[12,11,30],6],30] + 0.991967752387542492490018726900, //N[CDF[HypergeometricDistribution[12,11,30],7],30] + 0.999361857532772075500711182870, //N[CDF[HypergeometricDistribution[12,11,30],8],30] + 0.999978032961541207418268887534, //N[CDF[HypergeometricDistribution[12,11,30],9],30] + 0.999999780329615412074182688875 //N[CDF[HypergeometricDistribution[12,11,30],10],30] + }; + +//--- test values (x,pdf,cdf) for Logistic distribution +const double logistic_x_values[]={0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0}; +const double logistic_pdf_values[]= + { + 0.117501856100797244534651347511, //N[PDF[LogisticDistribution[1,2],0.0],30] + 0.118879479955564662317488644914, //N[PDF[LogisticDistribution[1,2],0.1],30] + 0.120130372870764575214933764554, //N[PDF[LogisticDistribution[1,2],0.2],30] + 0.121248697511250049746521122520, //N[PDF[LogisticDistribution[1,2],0.3],30] + 0.122229155845372934532992984692, //N[PDF[LogisticDistribution[1,2],0.4],30] + 0.123067041368799173792625971279, //N[PDF[LogisticDistribution[1,2],0.5],30] + 0.123758286355929972293475696239, //N[PDF[LogisticDistribution[1,2],0.6],30] + 0.124299503338771495086371350191, //N[PDF[LogisticDistribution[1,2],0.7],30] + 0.124688020096445983910759097800, //N[PDF[LogisticDistribution[1,2],0.8],30] + 0.124921907540558223470736299443, //N[PDF[LogisticDistribution[1,2],0.9],30] + 0.125000000000000000000000000000 //N[PDF[LogisticDistribution[1,2],1.0],30] + }; +const double logistic_cdf_values[]= + { + 0.377540668798145435361099434254, //N[CDF[LogisticDistribution[1,2],0.0],30] + 0.389360766050778011702230766982, //N[CDF[LogisticDistribution[1,2],0.1],30] + 0.401312339887547999630921340594, //N[CDF[LogisticDistribution[1,2],0.2],30] + 0.413382421082669942205822702480, //N[CDF[LogisticDistribution[1,2],0.3],30] + 0.425557483188341012847928734765, //N[CDF[LogisticDistribution[1,2],0.4],30] + 0.437823499114201895972676362097, //N[CDF[LogisticDistribution[1,2],0.5],30] + 0.450166002687522091440847458161, //N[CDF[LogisticDistribution[1,2],0.6],30] + 0.462570154656250450554984306308, //N[CDF[LogisticDistribution[1,2],0.7],30] + 0.475020812521060013900806817396, //N[CDF[LogisticDistribution[1,2],0.8],30] + 0.487502603515789656338498667871, //N[CDF[LogisticDistribution[1,2],0.9],30] + 0.500000000000000000000000000000 //N[CDF[LogisticDistribution[1,2],1.0],30] + }; + +//--- test values (x,pdf,cdf) for Weibull distribution +const double weibull_x_values[]={0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0}; +const double weibull_pdf_values[]= + { + 0, //N[PDF[WeibullDistribution[5,1],0.0],30] + 0.000499995000024999916666874999583, //N[PDF[WeibullDistribution[5,1],0.1],30] + 0.00799744040955631282836298238325, //N[PDF[WeibullDistribution[5,1],0.2],30] + 0.0404017044774286886523536633079, //N[PDF[WeibullDistribution[5,1],0.3],30] + 0.126695968038428483489030385185, //N[PDF[WeibullDistribution[5,1],0.4],30] + 0.302885385773857525577534122889, //N[PDF[WeibullDistribution[5,1],0.5],30] + 0.599520816131266665994128475406, //N[PDF[WeibullDistribution[5,1],0.6],30] + 1.01477624171575290112877265033, //N[PDF[WeibullDistribution[5,1],0.7],30] + 1.47577563700864634999747886575, //N[PDF[WeibullDistribution[5,1],0.8],30] + 1.81757982522109020306078908277, //N[PDF[WeibullDistribution[5,1],0.9],30] + 1.83939720585721160797761885081 //N[PDF[WeibullDistribution[5,1],1.0],30] + }; +const double weibull_cdf_values[]= + { + 0, // N[CDF[WeibullDistribution[5,1],0.0],30] + 9.99995000016666625000083333194e-6, // N[CDF[WeibullDistribution[5,1],0.1],30] + 0.000319948805460896454627202093416, // N[CDF[WeibullDistribution[5,1],0.2],30] + 0.00242704994003237895423053560688, // N[CDF[WeibullDistribution[5,1],0.3],30] + 0.0101877496997774727419501157385, // N[CDF[WeibullDistribution[5,1],0.4],30] + 0.0307667655236559181518908067536, // N[CDF[WeibullDistribution[5,1],0.5],30] + 0.0748135553529835401325177848671, // N[CDF[WeibullDistribution[5,1],0.6],30] + 0.154705338012700623799439691520, // N[CDF[WeibullDistribution[5,1],0.7],30] + 0.279406427241871899415293522582, // N[CDF[WeibullDistribution[5,1],0.8],30] + 0.445944269098890351147450363430, // N[CDF[WeibullDistribution[5,1],0.9],30] + 0.632120558828557678404476229839, // N[CDF[WeibullDistribution[5,1],1.0],30] + }; + +//--- test values (x,pdf,cdf) for Poisson distribution +const double poisson_x_values[]={0,1,2,3,4,5,6,7,8,9,10}; +const double poisson_pdf_values[]= + { + 0.367879441171442321595523770161, //N[PDF[PoissonDistribution[1],0],30] + 0.367879441171442321595523770161, //N[PDF[PoissonDistribution[1],1],30] + 0.183939720585721160797761885081, //N[PDF[PoissonDistribution[1],2],30] + 0.0613132401952403869325872950269, //N[PDF[PoissonDistribution[1],3],30] + 0.0153283100488100967331468237567, //N[PDF[PoissonDistribution[1],4],30] + 0.00306566200976201934662936475135, //N[PDF[PoissonDistribution[1],5],30] + 0.000510943668293669891104894125224, //N[PDF[PoissonDistribution[1],6],30] + 0.0000729919526133814130149848750320, //N[PDF[PoissonDistribution[1],7],30] + 9.12399407667267662687310937900e-6, //N[PDF[PoissonDistribution[1],8],30] + 1.01377711963029740298590104211e-6, //N[PDF[PoissonDistribution[1],9],30] + 1.01377711963029740298590104211e-7 //N[PDF[PoissonDistribution[1],10],30] + }; +const double poisson_cdf_values[]= + { + 0.367879441171442321595523770161, //N[CDF[PoissonDistribution[1],0],30] + 0.735758882342884643191047540323, //N[CDF[PoissonDistribution[1],1],30] + 0.919698602928605803988809425404, //N[CDF[PoissonDistribution[1],2],30] + 0.981011843123846190921396720431, //N[CDF[PoissonDistribution[1],3],30] + 0.996340153172656287654543544187, //N[CDF[PoissonDistribution[1],4],30] + 0.999405815182418307001172908939, //N[CDF[PoissonDistribution[1],5],30] + 0.999916758850711976892277803064, //N[CDF[PoissonDistribution[1],6],30] + 0.999989750803325358305292787939, //N[CDF[PoissonDistribution[1],7],30] + 0.999998874797402030981919661048, //N[CDF[PoissonDistribution[1],8],30] + 0.999999888574521661279322646949, //N[CDF[PoissonDistribution[1],9],30] + 0.999999989952233624309062945539 //N[CDF[PoissonDistribution[1],10],30] + }; + +//--- test values (x,pdf,cdf) for F distribution +const double f_x_values[]={0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0}; +const double f_pdf_values[]= + { + 0, //N[PDF[FRatioDistribution[10,20],0.0],30] + 0.0150468160996581654991613930582, //N[PDF[FRatioDistribution[10,20],0.1],30] + 0.119815720709266406017897451156, //N[PDF[FRatioDistribution[10,20],0.2],30] + 0.311387742341683605571461609007, //N[PDF[FRatioDistribution[10,20],0.3],30] + 0.519763015923146756273840230479, //N[PDF[FRatioDistribution[10,20],0.4],30] + 0.687881962127360000000000000000, //N[PDF[FRatioDistribution[10,20],0.5],30] + 0.792024864914240532846337384641, //N[PDF[FRatioDistribution[10,20],0.6],30] + 0.833047435548323908515813891880, //N[PDF[FRatioDistribution[10,20],0.7],30] + 0.823613604965582842018415096215, //N[PDF[FRatioDistribution[10,20],0.8],30] + 0.779352806006458219546578697713, //N[PDF[FRatioDistribution[10,20],0.9],30] + 0.714356849619277621633480515275, //N[PDF[FRatioDistribution[10,20],1.0],30] + }; +const double f_cdf_values[]= + { + 0, //N[CDF[FRatioDistribution[10,20],0.0],30] + 0.000341097358913110117497388449419, //N[CDF[FRatioDistribution[10,20],0.1],30] + 0.00616151312342342208319391118936, //N[CDF[FRatioDistribution[10,20],0.2],30] + 0.0272692959418046279508386753254, //N[CDF[FRatioDistribution[10,20],0.3],30] + 0.0689751467823785615691843288133, //N[CDF[FRatioDistribution[10,20],0.4],30] + 0.129839625830400000000000000000, //N[CDF[FRatioDistribution[10,20],0.5],30] + 0.204391530518198160782502820427, //N[CDF[FRatioDistribution[10,20],0.6],30] + 0.286128116700867849780999121986, //N[CDF[FRatioDistribution[10,20],0.7],30] + 0.369316442113680173719430076410, //N[CDF[FRatioDistribution[10,20],0.8],30] + 0.449692021734750179793277026872, //N[CDF[FRatioDistribution[10,20],0.9],30] + 0.524499531567108212493118813858, //N[CDF[FRatioDistribution[10,20],1.0],30] + }; + +//--- test values (x,pdf,cdf) for ChiSquare distribution +const double chisquare_x_values[]={0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0}; +const double chisquare_pdf_values[]= + { + 0, //N[PDF[ChiSquareDistribution[2],0.0],30] + 0.475614712250357004545712659890, //N[PDF[ChiSquareDistribution[2],0.1],30] + 0.452418709017979786582124529723, //N[PDF[ChiSquareDistribution[2],0.2],30] + 0.430353988212528903614516882272, //N[PDF[ChiSquareDistribution[2],0.3],30] + 0.409365376538990929334967754310, //N[PDF[ChiSquareDistribution[2],0.4],30] + 0.389400391535702434122585133489, //N[PDF[ChiSquareDistribution[2],0.5],30] + 0.370409110340858933033436889659, //N[PDF[ChiSquareDistribution[2],0.6],30] + 0.352344044859356717177410349515, //N[PDF[ChiSquareDistribution[2],0.7],30] + 0.335160023017819650372216462574, //N[PDF[ChiSquareDistribution[2],0.8],30] + 0.318814075810886646571871719156, //N[PDF[ChiSquareDistribution[2],0.9],30] + 0.303265329856316711801899767496 //N[PDF[ChiSquareDistribution[2],1.0],30] + }; +const double chisquare_cdf_values[]= + { + 0, //N[CDF[ChiSquareDistribution[2],0.0],30] + 0.0487705754992859909085746802203, //N[CDF[ChiSquareDistribution[2],0.1],30] + 0.0951625819640404268357509405536, //N[CDF[ChiSquareDistribution[2],0.2],30] + 0.139292023574942192770966235457, //N[CDF[ChiSquareDistribution[2],0.3],30] + 0.181269246922018141330064491381, //N[CDF[ChiSquareDistribution[2],0.4],30] + 0.221199216928595131754829733022, //N[CDF[ChiSquareDistribution[2],0.5],30] + 0.259181779318282133933126220682, //N[CDF[ChiSquareDistribution[2],0.6],30] + 0.295311910281286565645179300969, //N[CDF[ChiSquareDistribution[2],0.7],30] + 0.329679953964360699255567074852, //N[CDF[ChiSquareDistribution[2],0.8],30] + 0.362371848378226706856256561688, //N[CDF[ChiSquareDistribution[2],0.9],30] + 0.393469340287366576396200465009 //N[CDF[ChiSquareDistribution[2],1.0],30] + }; + +//--- test values (x,pdf,cdf) for Noncentral ChiSquare distribution +const double noncentral_chisquare_x_values[]={0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0}; +const double noncentral_chisquare_pdf_values[]= + { + 0, //N[PDF[NoncentralChiSquareDistribution[2,1],0.0],30] + 0.295731977425887787437413796316, //N[PDF[NoncentralChiSquareDistribution[2,1],0.1],30] + 0.288298568367079542335907975137, //N[PDF[NoncentralChiSquareDistribution[2,1],0.2],30] + 0.280969741689324922569967363843, //N[PDF[NoncentralChiSquareDistribution[2,1],0.3],30] + 0.273749589012391276633623625898, //N[PDF[NoncentralChiSquareDistribution[2,1],0.4],30] + 0.266641691212769080163425079921, //N[PDF[NoncentralChiSquareDistribution[2,1],0.5],30] + 0.259649153022898257071149284675, //N[PDF[NoncentralChiSquareDistribution[2,1],0.6],30] + 0.252774635687007877097528788462, //N[PDF[NoncentralChiSquareDistribution[2,1],0.7],30] + 0.246020387772423593652235077286, //N[PDF[NoncentralChiSquareDistribution[2,1],0.8],30] + 0.239388274230496750878159083137, //N[PDF[NoncentralChiSquareDistribution[2,1],0.9],30] + 0.232879803796820218250950764782 //N[PDF[NoncentralChiSquareDistribution[2,1],1.0],30] + }; +const double noncentral_chisquare_cdf_values[]= + { + 0, + 0.0299490533481423931947523237425, //N[CDF[NoncentralChiSquareDistribution[2,1],0.1],30] + 0.0591497275819226474905426294380, //N[CDF[NoncentralChiSquareDistribution[2,1],0.2],30] + 0.0876122537088524075998281348827, //N[CDF[NoncentralChiSquareDistribution[2,1],0.3],30] + 0.115347298953703510108668127844, //N[CDF[NoncentralChiSquareDistribution[2,1],0.4],30] + 0.142365913869366361026153686445, //N[CDF[NoncentralChiSquareDistribution[2,1],0.5],30] + 0.168679483009103160200853235778, //N[CDF[NoncentralChiSquareDistribution[2,1],0.6],30] + 0.194299678960710479382944892634, //N[CDF[NoncentralChiSquareDistribution[2,1],0.7],30] + 0.219238419553235326130896974995, //N[CDF[NoncentralChiSquareDistribution[2,1],0.8],30] + 0.243507828056537438718158282551, //N[CDF[NoncentralChiSquareDistribution[2,1],0.9],30] + 0.267120196203179781749049235218 //N[CDF[NoncentralChiSquareDistribution[2,1],1.0],30] + }; + +//--- test values (x,pdf,cdf) for Noncentral F distribution +const double noncentral_f_x_values[]={0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0}; +const double noncentral_f_pdf_values[]= + { + 0, //N[PDF[NoncentralFRatioDistribution[10,20,2],0.0],30] + 0.00637838395984413629724843643318, //N[PDF[NoncentralFRatioDistribution[10,20,2],0.1],30] + 0.0576689918386590515337738826738, //N[PDF[NoncentralFRatioDistribution[10,20,2],0.2],30] + 0.168060987055040520728047841242, //N[PDF[NoncentralFRatioDistribution[10,20,2],0.3],30] + 0.311215969391889284563713778298, //N[PDF[NoncentralFRatioDistribution[10,20,2],0.4],30] + 0.452740977234892225466655938323, //N[PDF[NoncentralFRatioDistribution[10,20,2],0.5],30] + 0.568412744474046056099634888126, //N[PDF[NoncentralFRatioDistribution[10,20,2],0.6],30] + 0.647331638965106980807964878289, //N[PDF[NoncentralFRatioDistribution[10,20,2],0.7],30] + 0.688682489027566460038593674890, //N[PDF[NoncentralFRatioDistribution[10,20,2],0.8],30] + 0.697399306416916297988633401289, //N[PDF[NoncentralFRatioDistribution[10,20,2],0.9],30] + 0.680752937956085914123043272777, //N[PDF[NoncentralFRatioDistribution[10,20,2],1.0],30] + }; +const double noncentral_f_cdf_values[]= + { + 0, //N[CDF[NoncentralFRatioDistribution[10,20,2],0.0],30] + 0.000141081926600196286687082764064, //N[CDF[NoncentralFRatioDistribution[10,20,2],0.1],30] + 0.00282513842436593044668501614715, //N[CDF[NoncentralFRatioDistribution[10,20,2],0.2],30] + 0.0136934496440913860234917981138, //N[CDF[NoncentralFRatioDistribution[10,20,2],0.3],30] + 0.0375354305391195137901164221206, //N[CDF[NoncentralFRatioDistribution[10,20,2],0.4],30] + 0.0758689753949193561304449803160, //N[CDF[NoncentralFRatioDistribution[10,20,2],0.5],30] + 0.127206298388221792570648195287, //N[CDF[NoncentralFRatioDistribution[10,20,2],0.6],30] + 0.188315146115626248268193389848, //N[CDF[NoncentralFRatioDistribution[10,20,2],0.7],30] + 0.255414123041890604059805728902, //N[CDF[NoncentralFRatioDistribution[10,20,2],0.8],30] + 0.324961425880008731771812043346, //N[CDF[NoncentralFRatioDistribution[10,20,2],0.9],30] + 0.394048455363096839986479820864, //N[CDF[NoncentralFRatioDistribution[10,20,2],1.0],30] + }; + +//--- test values (x,pdf,cdf) for Noncentral Beta distribution +const double noncentral_beta_x_values[]={0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0}; +const double noncentral_beta_pdf_values[]= + { + 0, //N[PDF[NoncentralBetaDistribution[2,4,1],0.0],30] + 1.02497160055865464633963336051, //N[PDF[NoncentralBetaDistribution[2,4,1],0.1],30] + 1.66133664626858910409449171342, //N[PDF[NoncentralBetaDistribution[2,4,1],0.2],30] + 1.91877498001185552818242810746, //N[PDF[NoncentralBetaDistribution[2,4,1],0.3],30] + 1.84511670851898738523457562051, //N[PDF[NoncentralBetaDistribution[2,4,1],0.4],30] + 1.52366212772038645304752732774, //N[PDF[NoncentralBetaDistribution[2,4,1],0.5],30] + 1.06551899551985128188799944192, //N[PDF[NoncentralBetaDistribution[2,4,1],0.6],30] + 0.595311593728999952808386181057, //N[PDF[NoncentralBetaDistribution[2,4,1],0.7],30] + 0.228265724218715136455418263844, //N[PDF[NoncentralBetaDistribution[2,4,1],0.8],30] + 0.0362651708668906692268756554128, //N[PDF[NoncentralBetaDistribution[2,4,1],0.9],30] + 0, //N[PDF[NoncentralBetaDistribution[2,4,1],1.0],30] + }; +const double noncentral_beta_cdf_values[]= + { + 0, //N[CDF[NoncentralBetaDistribution[2,4,1],0.0],30] + 0.0544271272420940348326261062660, //N[CDF[NoncentralBetaDistribution[2,4,1],0.1],30] + 0.191999109403542743081451188243, //N[CDF[NoncentralBetaDistribution[2,4,1],0.2],30] + 0.374020701059051706320566724831, //N[CDF[NoncentralBetaDistribution[2,4,1],0.3],30] + 0.564677487543142735835339607153, //N[CDF[NoncentralBetaDistribution[2,4,1],0.4],30] + 0.734752398937727590947774975999, //N[CDF[NoncentralBetaDistribution[2,4,1],0.5],30] + 0.864837477189878037683109886395, //N[CDF[NoncentralBetaDistribution[2,4,1],0.6],30] + 0.947463049281498670018890201758, //N[CDF[NoncentralBetaDistribution[2,4,1],0.7],30] + 0.987384842910461036210577979081, //N[CDF[NoncentralBetaDistribution[2,4,1],0.8],30] + 0.999050083746745712534462538929, //N[CDF[NoncentralBetaDistribution[2,4,1],0.9],30] + 1, //N[CDF[NoncentralBetaDistribution[2,4,1],1.0],30] + }; + +//--- test values (x,pdf,cdf) for Negative Binomial distribution +const double negative_binomial_x_values[]={0,1,2,3,4,5,6,7,8,9,10}; +const double negative_binomial_pdf_values[]= + { + 0.250000000000000000000000000000, //N[PDF[NegativeBinomialDistribution[2,0.5],0],30] + 0.250000000000000000000000000000, //N[PDF[NegativeBinomialDistribution[2,0.5],1],30] + 0.187500000000000000000000000000, //N[PDF[NegativeBinomialDistribution[2,0.5],2],30] + 0.125000000000000000000000000000, //N[PDF[NegativeBinomialDistribution[2,0.5],3],30] + 0.0781250000000000000000000000000, //N[PDF[NegativeBinomialDistribution[2,0.5],4],30] + 0.0468750000000000000000000000000, //N[PDF[NegativeBinomialDistribution[2,0.5],5],30] + 0.0273437500000000000000000000000, //N[PDF[NegativeBinomialDistribution[2,0.5],6],30] + 0.0156250000000000000000000000000, //N[PDF[NegativeBinomialDistribution[2,0.5],7],30] + 0.00878906250000000000000000000000, //N[PDF[NegativeBinomialDistribution[2,0.5],8],30] + 0.00488281250000000000000000000000, //N[PDF[NegativeBinomialDistribution[2,0.5],9],30] + 0.00268554687500000000000000000000 //N[PDF[NegativeBinomialDistribution[2,0.5],10],30] + }; +const double negative_binomial_cdf_values[]= + { + 0.250000000000000000000000000000, //N[CDF[NegativeBinomialDistribution[2,0.5],0],30] + 0.500000000000000000000000000000, //N[CDF[NegativeBinomialDistribution[2,0.5],1],30] + 0.687500000000000000000000000000, //N[CDF[NegativeBinomialDistribution[2,0.5],2],30] + 0.812500000000000000000000000000, //N[CDF[NegativeBinomialDistribution[2,0.5],3],30] + 0.890625000000000000000000000000, //N[CDF[NegativeBinomialDistribution[2,0.5],4],30] + 0.937500000000000000000000000000, //N[CDF[NegativeBinomialDistribution[2,0.5],5],30] + 0.964843750000000000000000000000, //N[CDF[NegativeBinomialDistribution[2,0.5],6],30] + 0.980468750000000000000000000000, //N[CDF[NegativeBinomialDistribution[2,0.5],7],30] + 0.989257812500000000000000000000, //N[CDF[NegativeBinomialDistribution[2,0.5],8],30] + 0.994140625000000000000000000000, //N[CDF[NegativeBinomialDistribution[2,0.5],9],30] + 0.996826171875000000000000000000 //N[CDF[NegativeBinomialDistribution[2,0.5],10],30] + }; + +//--- test values (x,pdf,cdf) for T distribution +const double t_x_values[]={0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0}; +const double t_pdf_values[]= + { + 0.386699020961393177406711760526, //N[PDF[TDistribution[8],0.0],30] + 0.384531295953230149911443054954, //N[PDF[TDistribution[8],0.1],30] + 0.378116644001397858209336510749, //N[PDF[TDistribution[8],0.2],30] + 0.367713578039119032335234793984, //N[PDF[TDistribution[8],0.3],30] + 0.353730330292855425371453625491, //N[PDF[TDistribution[8],0.4],30] + 0.336693897928227490108990053105, //N[PDF[TDistribution[8],0.5],30] + 0.317212114954435096838422653364, //N[PDF[TDistribution[8],0.6],30] + 0.295933007571487508535894462780, //N[PDF[TDistribution[8],0.7],30] + 0.273505568477656110583547462302, //N[PDF[TDistribution[8],0.8],30] + 0.250545395739835743338206333915, //N[PDF[TDistribution[8],0.9],30] + 0.227607580145303053396331859981, //N[PDF[TDistribution[8],1.0],30] + }; +const double t_cdf_values[]= + { + 0.500000000000000000000000000000, //N[CDF[TDistribution[8],0.0],30] + 0.538597545284701547838380887211, //N[CDF[TDistribution[8],0.1],30] + 0.576764504299481290107055665260, //N[CDF[TDistribution[8],0.2],30] + 0.6140877591587506564205123360179, //N[CDF[TDistribution[8],0.3],30] + 0.6501877476197896049046234705905, //N[CDF[TDistribution[8],0.4],30] + 0.6847319622215118291913144672012, //N[CDF[TDistribution[8],0.5],30] + 0.717444971062890912217515266940, //N[CDF[TDistribution[8],0.6],30] + 0.748114473990727629636386922326, //N[CDF[TDistribution[8],0.7],30] + 0.7765933329425457124221649477679, //N[CDF[TDistribution[8],0.8],30] + 0.8027978982672077353491118923202, //N[CDF[TDistribution[8],0.9],30] + 0.8267032464563328760859625057156, //N[CDF[TDistribution[8],1.0],30] + }; + +//--- test values (x,pdf,cdf) for Noncentral T distribution +const double noncentral_t_x_values[]={0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0}; +const double noncentral_t_pdf_values[]= + { + 4.92773299108631898092114435293e-15, //N[PDF[Noncentral T Distribution[10,8],0.0],30] + 1.13022616309487993266124014688e-14, //N[PDF[Noncentral T Distribution[10,8],0.1],30] + 2.64161256619123935657695034087e-14, //N[PDF[Noncentral T Distribution[10,8],0.2],30] + 6.28106243570814021661611528450e-14, //N[PDF[Noncentral T Distribution[10,8],0.3],30] + 1.51636983962647220239107618892e-13, //N[PDF[Noncentral T Distribution[10,8],0.4],30] + 3.70864175555732846819012024992e-13, //N[PDF[Noncentral T Distribution[10,8],0.5],30] + 9.16615229573759829315327016195e-13, //N[PDF[Noncentral T Distribution[10,8],0.6],30] + 2.28327725393016095515004668783e-12, //N[PDF[Noncentral T Distribution[10,8],0.7],30] + 5.71609303970754101789636971640e-12, //N[PDF[Noncentral T Distribution[10,8],0.8],30] + 1.43395037240077895541041912481e-11, //N[PDF[Noncentral T Distribution[10,8],0.9],30] + 3.59391445912257844885457911125e-11 //N[PDF[Noncentral T Distribution[10,8],1.0],30] + }; +const double noncentral_t_cdf_values[]= + { + 6.22096057427178412351599517259e-16, //N[CDF[Noncentral T Distribution[10,8],0.0],30] + 1.38876e-15, //N[CDF[Noncentral T Distribution[10,8],0.1],30] + 3.16637e-15, //N[CDF[Noncentral T Distribution[10,8],0.2],30] + 7.36264e-15, //N[CDF[Noncentral T Distribution[10,8],0.3],30] + 1.74292e-14, //N[CDF[Noncentral T Distribution[10,8],0.4],30] + 4.19181e-14, //N[CDF[Noncentral T Distribution[10,8],0.5],30] + 1.02187e-13, //N[CDF[Noncentral T Distribution[10,8],0.6],30] + 2.5185e-13, //N[CDF[Noncentral T Distribution[10,8],0.7],30] + 6.2582e-13, //N[CDF[Noncentral T Distribution[10,8],0.8],30] + 1.56338e-12, //N[CDF[Noncentral T Distribution[10,8],0.9],30] + 3.91469e-12 //N[CDF[Noncentral T Distribution[10,8],1.0],30] + }; + +//--- test values (x,pdf,cdf) for Normal distribution +const double normal_x_values[]={0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0}; +const double normal_pdf_values[]= + { + 0.0000117886135513079732292607502817, //N[PDF[NormalDistribution[21,5],0.0],30] + 0.0000128190726454211985066208612721, //N[PDF[NormalDistribution[21,5],0.1],30] + 0.0000139340308738428775166307149964, //N[PDF[NormalDistribution[21,5],0.2],30] + 0.0000151399071060322261068611049960, //N[PDF[NormalDistribution[21,5],0.3],30] + 0.0000164435633072571929616647120839, //N[PDF[NormalDistribution[21,5],0.4],30] + 0.0000178523314354265729452298914839, //N[PDF[NormalDistribution[21,5],0.5],30] + 0.0000193740416797438510221479365609, //N[PDF[NormalDistribution[21,5],0.6],30] + 0.0000210170520860800478589989753631, //N[PDF[NormalDistribution[21,5],0.7],30] + 0.0000227902796137729222332254497820, //N[PDF[NormalDistribution[21,5],0.8],30] + 0.0000247032326682046814399804038565, //N[PDF[NormalDistribution[21,5],0.9],30] + 0.0000267660451529770703548148976881 //N[PDF[NormalDistribution[21,5],1.0],30] + }; +const double normal_cdf_values[]= + { + 0.0000133457490159063383530921177856, //N[CDF[NormalDistribution[21,5],0.0],30] + 0.0000145754547908670163565982834186, //N[CDF[NormalDistribution[21,5],0.1],30] + 0.0000159123797190821776993361592918, //N[CDF[NormalDistribution[21,5],0.2],30] + 0.0000173652910736040482844247767230, //N[CDF[NormalDistribution[21,5],0.3],30] + 0.0000189436199505532551675070397105, //N[CDF[NormalDistribution[21,5],0.4],30] + 0.0000206575069125467387952544594699, //N[CDF[NormalDistribution[21,5],0.5],30] + 0.0000225178503885254405900409660717, //N[CDF[NormalDistribution[21,5],0.6],30] + 0.0000245363579664097294832709659110, //N[CDF[NormalDistribution[21,5],0.7],30] + 0.0000267256007194920873949071274935, //N[CDF[NormalDistribution[21,5],0.8],30] + 0.0000290990707119309791050371064941, //N[CDF[NormalDistribution[21,5],0.9],30] + 0.0000316712418331199212537707567222, //N[CDF[NormalDistribution[21,5],1.0],30] + }; + +//--- test values (x,pdf,cdf) for Normal distribution +const double lognormal_x_values[]={0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0}; +const double lognormal_pdf_values[]= + { + 0, //N[PDF[LognormalDistribution[0.5,0.6],0.0],30] + 0.000121629348383860528983795462471, //N[PDF[LognormalDistribution[0.5,0.6],0.1],30] + 0.00688195025191558633776856014392, //N[PDF[LognormalDistribution[0.5,0.6],0.2],30] + 0.0392889731874339558688036697379, //N[PDF[LognormalDistribution[0.5,0.6],0.3],30] + 0.102512981429306814499550041149, //N[PDF[LognormalDistribution[0.5,0.6],0.4],30] + 0.184116195903499970110082739057, //N[PDF[LognormalDistribution[0.5,0.6],0.5],30] + 0.268096008671120880492542216599, //N[PDF[LognormalDistribution[0.5,0.6],0.6],30] + 0.342757405791760554961057548001, //N[PDF[LognormalDistribution[0.5,0.6],0.7],30] + 0.402013268119797929735215095564, //N[PDF[LognormalDistribution[0.5,0.6],0.8],30] + 0.444090682986326362528351841435, //N[PDF[LognormalDistribution[0.5,0.6],0.9],30] + 0.469853125683837587733314480501 //N[PDF[LognormalDistribution[0.5,0.6],1.0],30] + }; +const double lognormal_cdf_values[]= + { + 0, //N[CDF[LognormalDistribution[0.5,0.6],0.0],30] + 1.49886599868856419859631258646e-6, //N[CDF[LognormalDistribution[0.5,0.6],0.1],30] + 0.000219273481905296373803502502479, //N[CDF[LognormalDistribution[0.5,0.6],0.2],30] + 0.00225599721794476281427735394792, //N[CDF[LognormalDistribution[0.5,0.6],0.3],30] + 0.00912553919415598265409187391175, //N[CDF[LognormalDistribution[0.5,0.6],0.4],30] + 0.0233738658111863175085305417985, //N[CDF[LognormalDistribution[0.5,0.6],0.5],30] + 0.0460223286277397559159160823805, //N[CDF[LognormalDistribution[0.5,0.6],0.6],30] + 0.0766759295201034859852110590339, //N[CDF[LognormalDistribution[0.5,0.6],0.7],30] + 0.114055476665196548777409987330, //N[CDF[LognormalDistribution[0.5,0.6],0.8],30] + 0.156503097734807967129258608295, //N[CDF[LognormalDistribution[0.5,0.6],0.9],30] + 0.202328380963643025368533599712 //N[CDF[LognormalDistribution[0.5,0.6],1.0],30] + }; +//+------------------------------------------------------------------+ +//| GetCorrectDigits | +//+------------------------------------------------------------------+ +int GetCorrectDigits(const double delta) + { + double d=MathAbs(delta); +//--- check if delta to small + if(d<10E-30) + return(30); +//--- check if delta is large + if(d>=1.0) + return(0); + int correct_digits=0; + while(MathAbs(d)<1.0) + { + d=d*10; + correct_digits++; + } +//--- + return(correct_digits-1); + } +//+------------------------------------------------------------------+ +//| Structure for precision information | +//+------------------------------------------------------------------+ +struct precision_info + { + //--- precision info + double pdf_max_delta; + double cdf_max_delta; + double quantile_max_delta; + }; +//+------------------------------------------------------------------+ +//| Test function for Binomial distribution | +//+------------------------------------------------------------------+ +bool TestBinomialDistribution(string test_name,const double n,const double probability,const double &x_values[],const double &pdf_values[],const double &cdf_values[],precision_info &precision) + { + PrintFormat("%s started",test_name); +//--- + int N=ArraySize(x_values); + int error_code=0; +//--- arrays for calculated values + double binomial_pdf[]; + double binomial_cdf[]; + double binomial_quantile[]; +//--- arrays for differences + double delta_binomial_pdf[]; + double delta_binomial_cdf[]; + double delta_binomial_quantile[]; +//--- prepare arrays + ArrayResize(binomial_pdf,N); + ArrayResize(binomial_cdf,N); + ArrayResize(binomial_quantile,N); + ArrayResize(delta_binomial_pdf,N); + ArrayResize(delta_binomial_cdf,N); + ArrayResize(delta_binomial_quantile,N); +//--- test 1: single values + PrintFormat("%s: Test 1: Calculations for single values",test_name); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_binomial_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_binomial_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 2: calculations on arrays + PrintFormat("%s: Test 2: Calculations on arrays",test_name); +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityBinomial(x_values,n,probability,binomial_pdf)) + return false; + if(!MathCumulativeDistributionBinomial(x_values,n,probability,binomial_cdf)) + return false; + if(!MathQuantileBinomial(binomial_cdf,n,probability,binomial_quantile)) + return false; +//--- calculate differences + ArrayResize(delta_binomial_pdf,N); + ArrayResize(delta_binomial_cdf,N); + ArrayResize(delta_binomial_quantile,N); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_binomial_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_binomial_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 3: calculations on arrays + PrintFormat("%s: Test 3: R-like overloaded functions",test_name); +//--- parameters for R-like overloaded functions + bool tail=true; + bool log_mode=true; +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityBinomial(x_values,n,probability,log_mode,binomial_pdf)) + return false; + if(!MathCumulativeDistributionBinomial(x_values,n,probability,tail,log_mode,binomial_cdf)) + return false; + if(!MathQuantileBinomial(binomial_cdf,n,probability,tail,log_mode,binomial_quantile)) + return false; +//--- calculate differences + if(tail==true) + { + //--- lower tail mode (cdf) + if(log_mode==true) + { + //--- logarithmic values + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_binomial_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_binomial_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 4: test generators + PrintFormat("%s: Test 4: Generators of random values",test_name); +//--- generate random values and calculate 4 moments + int random_data_count=10000; + double values_rnd[]; + if(MathRandomBinomial(n,probability,random_data_count,values_rnd)==true) + { + //--- calculate 4 moments of generated values + double mean=MathMean(values_rnd); + double variance=MathVariance(values_rnd); + double skewness=MathSkewness(values_rnd); + double kurtosis=MathKurtosis(values_rnd); + //--- inital values + double binomial_mean=0; + double binomial_variance=0; + double binomial_skewness=0; + double binomial_kurtosis=0; + //--- calculate theoretical values and compare with generated + if(MathMomentsBinomial(n,probability,binomial_mean,binomial_variance,binomial_skewness,binomial_kurtosis,error_code)) + { + PrintFormat("Mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",mean,mean,skewness,kurtosis); + PrintFormat("Theoretical values: mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",binomial_mean,binomial_variance,binomial_skewness,binomial_kurtosis); + PrintFormat("delta mean=%.4f, delta variance=%.4f delta skewness=%.4f delta kurtosis=%.4f",mean-binomial_mean,variance-binomial_variance,skewness-binomial_skewness,kurtosis-binomial_kurtosis); + } + else + return false; + } + else + return false; +//--- successful + PrintFormat("%s passed",test_name); + return true; + } +//+------------------------------------------------------------------+ +//| Test function for Beta distribution | +//+------------------------------------------------------------------+ +bool TestBetaDistribution(string test_name,const double a,const double b,const double &x_values[],const double &pdf_values[],const double &cdf_values[],precision_info &precision) + { + PrintFormat("%s started",test_name); +//--- + int N=ArraySize(x_values); + int error_code=0; +//--- arrays for calculated values + double beta_pdf[]; + double beta_cdf[]; + double beta_quantile[]; +//--- arrays for differences + double delta_beta_pdf[]; + double delta_beta_cdf[]; + double delta_beta_quantile[]; +//--- prepare arrays + ArrayResize(beta_pdf,N); + ArrayResize(beta_cdf,N); + ArrayResize(beta_quantile,N); + ArrayResize(delta_beta_pdf,N); + ArrayResize(delta_beta_cdf,N); + ArrayResize(delta_beta_quantile,N); +//--- test 1: single values + PrintFormat("%s: Test 1: Calculations for single values",test_name); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_beta_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_beta_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 2: calculations on arrays + PrintFormat("%s: Test 2: Calculations on arrays",test_name); +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityBeta(x_values,a,b,beta_pdf)) + return false; + if(!MathCumulativeDistributionBeta(x_values,a,b,beta_cdf)) + return false; + if(!MathQuantileBeta(beta_cdf,a,b,beta_quantile)) + return false; +//--- calculate differences + ArrayResize(delta_beta_pdf,N); + ArrayResize(delta_beta_cdf,N); + ArrayResize(delta_beta_quantile,N); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_beta_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_beta_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 3: calculations on arrays + PrintFormat("%s: Test 3: R-like overloaded functions",test_name); +//--- parameters for R-like overloaded functions + bool tail=true; + bool log_mode=true; +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityBeta(x_values,a,b,log_mode,beta_pdf)) + return false; + if(!MathCumulativeDistributionBeta(x_values,a,b,tail,log_mode,beta_cdf)) + return false; + if(!MathQuantileBeta(beta_cdf,a,b,tail,log_mode,beta_quantile)) + return false; +//--- calculate differences + if(tail==true) + { + //--- lower tail mode (cdf) + if(log_mode==true) + { + //--- logarithmic values + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_beta_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_beta_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 4: test generators + PrintFormat("%s: Test 4: Generators of random values",test_name); +//--- generate random values and calculate 4 moments + int random_data_count=10000; + double values_rnd[]; + if(MathRandomBeta(a,b,random_data_count,values_rnd)==true) + { + //--- calculate 4 moments of generated values + double mean=MathMean(values_rnd); + double variance=MathVariance(values_rnd); + double skewness=MathSkewness(values_rnd); + double kurtosis=MathKurtosis(values_rnd); + //--- inital values + double beta_mean=0; + double beta_variance=0; + double beta_skewness=0; + double beta_kurtosis=0; + //--- calculate theoretical values and compare with generated + if(MathMomentsBeta(a,b,beta_mean,beta_variance,beta_skewness,beta_kurtosis,error_code)) + { + PrintFormat("Mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",mean,mean,skewness,kurtosis); + PrintFormat("Theoretical values: mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",beta_mean,beta_variance,beta_skewness,beta_kurtosis); + PrintFormat("delta mean=%.4f, delta variance=%.4f delta skewness=%.4f delta kurtosis=%.4f",mean-beta_mean,variance-beta_variance,skewness-beta_skewness,kurtosis-beta_kurtosis); + } + else + return false; + } + else + return false; +//--- successful + PrintFormat("%s passed",test_name); + return true; + } +//+------------------------------------------------------------------+ +//| Test function for Gamma distribution | +//+------------------------------------------------------------------+ +bool TestGammaDistribution(string test_name,const double a,const double b,const double &x_values[],const double &pdf_values[],const double &cdf_values[],precision_info &precision) + { + PrintFormat("%s started",test_name); +//--- + int N=ArraySize(x_values); + int error_code=0; +//--- arrays for calculated values + double gamma_pdf[]; + double gamma_cdf[]; + double gamma_quantile[]; +//--- arrays for differences + double delta_gamma_pdf[]; + double delta_gamma_cdf[]; + double delta_gamma_quantile[]; +//--- prepare arrays + ArrayResize(gamma_pdf,N); + ArrayResize(gamma_cdf,N); + ArrayResize(gamma_quantile,N); + ArrayResize(delta_gamma_pdf,N); + ArrayResize(delta_gamma_cdf,N); + ArrayResize(delta_gamma_quantile,N); +//--- test 1: single values + PrintFormat("%s: Test 1: Calculations for single values",test_name); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_gamma_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_gamma_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 2: calculations on arrays + PrintFormat("%s: Test 2: Calculations on arrays",test_name); +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityGamma(x_values,a,b,gamma_pdf)) + return false; + if(!MathCumulativeDistributionGamma(x_values,a,b,gamma_cdf)) + return false; + if(!MathQuantileGamma(gamma_cdf,a,b,gamma_quantile)) + return false; +//--- calculate differences + ArrayResize(delta_gamma_pdf,N); + ArrayResize(delta_gamma_cdf,N); + ArrayResize(delta_gamma_quantile,N); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_gamma_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_gamma_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 3: calculations on arrays + PrintFormat("%s: Test 3: R-like overloaded functions",test_name); +//--- parameters for R-like overloaded functions + bool tail=true; + bool log_mode=true; +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityGamma(x_values,a,b,log_mode,gamma_pdf)) + return false; + if(!MathCumulativeDistributionGamma(x_values,a,b,tail,log_mode,gamma_cdf)) + return false; + if(!MathQuantileGamma(gamma_cdf,a,b,tail,log_mode,gamma_quantile)) + return false; +//--- calculate differences + if(tail==true) + { + //--- lower tail mode (cdf) + if(log_mode==true) + { + //--- logarithmic values + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_gamma_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_gamma_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 4: test generators + PrintFormat("%s: Test 4: Generators of random values",test_name); +//--- generate random values and calculate 4 moments + int random_data_count=10000; + double values_rnd[]; + if(MathRandomGamma(a,b,random_data_count,values_rnd)==true) + { + //--- calculate 4 moments of generated values + double mean=MathMean(values_rnd); + double variance=MathVariance(values_rnd); + double skewness=MathSkewness(values_rnd); + double kurtosis=MathKurtosis(values_rnd); + //--- inital values + double gamma_mean=0; + double gamma_variance=0; + double gamma_skewness=0; + double gamma_kurtosis=0; + //--- calculate theoretical values and compare with generated + if(MathMomentsGamma(a,b,gamma_mean,gamma_variance,gamma_skewness,gamma_kurtosis,error_code)) + { + PrintFormat("Mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",mean,mean,skewness,kurtosis); + PrintFormat("Theoretical values: mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",gamma_mean,gamma_variance,gamma_skewness,gamma_kurtosis); + PrintFormat("delta mean=%.4f, delta variance=%.4f delta skewness=%.4f delta kurtosis=%.4f",mean-gamma_mean,variance-gamma_variance,skewness-gamma_skewness,kurtosis-gamma_kurtosis); + } + else + return false; + } + else + return false; +//--- successful + PrintFormat("%s passed",test_name); + return true; + } +//+------------------------------------------------------------------+ +//| Test function for Cauchy distribution | +//+------------------------------------------------------------------+ +bool TestCauchyDistribution(string test_name,const double a,const double b,const double &x_values[],const double &pdf_values[],const double &cdf_values[],precision_info &precision) + { + PrintFormat("%s started",test_name); +//--- + int N=ArraySize(x_values); + int error_code=0; +//--- arrays for calculated values + double cauchy_pdf[]; + double cauchy_cdf[]; + double cauchy_quantile[]; +//--- arrays for differences + double delta_cauchy_pdf[]; + double delta_cauchy_cdf[]; + double delta_cauchy_quantile[]; +//--- prepare arrays + ArrayResize(cauchy_pdf,N); + ArrayResize(cauchy_cdf,N); + ArrayResize(cauchy_quantile,N); + ArrayResize(delta_cauchy_pdf,N); + ArrayResize(delta_cauchy_cdf,N); + ArrayResize(delta_cauchy_quantile,N); +//--- test 1: single values + PrintFormat("%s: Test 1: Calculations for single values",test_name); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_cauchy_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_cauchy_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 2: calculations on arrays + PrintFormat("%s: Test 2: Calculations on arrays",test_name); +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityCauchy(x_values,a,b,cauchy_pdf)) + return false; + if(!MathCumulativeDistributionCauchy(x_values,a,b,cauchy_cdf)) + return false; + if(!MathQuantileCauchy(cauchy_cdf,a,b,cauchy_quantile)) + return false; +//--- calculate differences + ArrayResize(delta_cauchy_pdf,N); + ArrayResize(delta_cauchy_cdf,N); + ArrayResize(delta_cauchy_quantile,N); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_cauchy_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_cauchy_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 3: calculations on arrays + PrintFormat("%s: Test 3: R-like overloaded functions",test_name); +//--- parameters for R-like overloaded functions + bool tail=true; + bool log_mode=true; +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityCauchy(x_values,a,b,log_mode,cauchy_pdf)) + return false; + if(!MathCumulativeDistributionCauchy(x_values,a,b,tail,log_mode,cauchy_cdf)) + return false; + if(!MathQuantileCauchy(cauchy_cdf,a,b,tail,log_mode,cauchy_quantile)) + return false; +//--- calculate differences + if(tail==true) + { + //--- lower tail mode (cdf) + if(log_mode==true) + { + //--- logarithmic values + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_cauchy_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_cauchy_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 4: test generators + PrintFormat("%s: Test 4: Generators of random values",test_name); +//--- generate random values and calculate 4 moments + int random_data_count=10000; + double values_rnd[]; + if(MathRandomCauchy(a,b,random_data_count,values_rnd)==true) + { + //--- calculate 4 moments of generated values + double mean=MathMean(values_rnd); + double variance=MathVariance(values_rnd); + double skewness=MathSkewness(values_rnd); + double kurtosis=MathKurtosis(values_rnd); + //--- inital values + double cauchy_mean=0; + double cauchy_variance=0; + double cauchy_skewness=0; + double cauchy_kurtosis=0; + //--- Cauchy distribution has undefined moments, not need to compare + if(!MathMomentsCauchy(a,b,cauchy_mean,cauchy_variance,cauchy_skewness,cauchy_kurtosis,error_code)) + return false; + } + else + return false; +//--- successful + PrintFormat("%s passed",test_name); + return true; + } +//+------------------------------------------------------------------+ +//| Test function for Exponential distribution | +//+------------------------------------------------------------------+ +bool TestExponentialDistribution(string test_name,const double mu,const double &x_values[],const double &pdf_values[],const double &cdf_values[],precision_info &precision) + { + PrintFormat("%s started",test_name); +//--- + int N=ArraySize(x_values); + int error_code=0; +//--- arrays for calculated values + double exponential_pdf[]; + double exponential_cdf[]; + double exponential_quantile[]; +//--- arrays for differences + double delta_exponential_pdf[]; + double delta_exponential_cdf[]; + double delta_exponential_quantile[]; +//--- prepare arrays + ArrayResize(exponential_pdf,N); + ArrayResize(exponential_cdf,N); + ArrayResize(exponential_quantile,N); + ArrayResize(delta_exponential_pdf,N); + ArrayResize(delta_exponential_cdf,N); + ArrayResize(delta_exponential_quantile,N); +//--- test 1: single values + PrintFormat("%s: Test 1: Calculations for single values",test_name); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_exponential_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_exponential_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 2: calculations on arrays + PrintFormat("%s: Test 2: Calculations on arrays",test_name); +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityExponential(x_values,mu,exponential_pdf)) + return false; + if(!MathCumulativeDistributionExponential(x_values,mu,exponential_cdf)) + return false; + if(!MathQuantileExponential(exponential_cdf,mu,exponential_quantile)) + return false; +//--- calculate differences + ArrayResize(delta_exponential_pdf,N); + ArrayResize(delta_exponential_cdf,N); + ArrayResize(delta_exponential_quantile,N); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_exponential_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_exponential_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 3: calculations on arrays + PrintFormat("%s: Test 3: R-like overloaded functions",test_name); +//--- parameters for R-like overloaded functions + bool tail=true; + bool log_mode=true; +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityExponential(x_values,mu,log_mode,exponential_pdf)) + return false; + if(!MathCumulativeDistributionExponential(x_values,mu,tail,log_mode,exponential_cdf)) + return false; + if(!MathQuantileExponential(exponential_cdf,mu,tail,log_mode,exponential_quantile)) + return false; +//--- calculate differences + if(tail==true) + { + //--- lower tail mode (cdf) + if(log_mode==true) + { + //--- logarithmic values + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_exponential_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_exponential_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 4: test generators + PrintFormat("%s: Test 4: Generators of random values",test_name); +//--- generate random values and calculate 4 moments + int random_data_count=10000; + double values_rnd[]; + if(MathRandomExponential(mu,random_data_count,values_rnd)==true) + { + //--- calculate 4 moments of generated values + double mean=MathMean(values_rnd); + double variance=MathVariance(values_rnd); + double skewness=MathSkewness(values_rnd); + double kurtosis=MathKurtosis(values_rnd); + //--- inital values + double exponential_mean=0; + double exponential_variance=0; + double exponential_skewness=0; + double exponential_kurtosis=0; + //--- calculate theoretical values and compare with generated + if(MathMomentsExponential(mu,exponential_mean,exponential_variance,exponential_skewness,exponential_kurtosis,error_code)) + { + PrintFormat("Mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",mean,mean,skewness,kurtosis); + PrintFormat("Theoretical values: mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",exponential_mean,exponential_variance,exponential_skewness,exponential_kurtosis); + PrintFormat("delta mean=%.4f, delta variance=%.4f delta skewness=%.4f delta kurtosis=%.4f",mean-exponential_mean,variance-exponential_variance,skewness-exponential_skewness,kurtosis-exponential_kurtosis); + } + else + return false; + } + else + return false; +//--- successful + PrintFormat("%s passed",test_name); + return true; + } +//+------------------------------------------------------------------+ +//| Test function for Uniform distribution | +//+------------------------------------------------------------------+ +bool TestUnifromDistribution(string test_name,const double a,const double b,const double &x_values[],const double &pdf_values[],const double &cdf_values[],precision_info &precision) + { + PrintFormat("%s started",test_name); +//--- + int N=ArraySize(x_values); + int error_code=0; +//--- arrays for calculated values + double uniform_pdf[]; + double uniform_cdf[]; + double uniform_quantile[]; +//--- arrays for differences + double delta_uniform_pdf[]; + double delta_uniform_cdf[]; + double delta_uniform_quantile[]; +//--- prepare arrays + ArrayResize(uniform_pdf,N); + ArrayResize(uniform_cdf,N); + ArrayResize(uniform_quantile,N); + ArrayResize(delta_uniform_pdf,N); + ArrayResize(delta_uniform_cdf,N); + ArrayResize(delta_uniform_quantile,N); +//--- test 1: single values + PrintFormat("%s: Test 1: Calculations for single values",test_name); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_uniform_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_uniform_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 2: calculations on arrays + PrintFormat("%s: Test 2: Calculations on arrays",test_name); +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityUniform(x_values,a,b,uniform_pdf)) + return false; + if(!MathCumulativeDistributionUniform(x_values,a,b,uniform_cdf)) + return false; + if(!MathQuantileUniform(uniform_cdf,a,b,uniform_quantile)) + return false; +//--- calculate differences + ArrayResize(delta_uniform_pdf,N); + ArrayResize(delta_uniform_cdf,N); + ArrayResize(delta_uniform_quantile,N); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_uniform_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_uniform_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 3: calculations on arrays + PrintFormat("%s: Test 3: R-like overloaded functions",test_name); +//--- parameters for R-like overloaded functions + bool tail=true; + bool log_mode=true; +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityUniform(x_values,a,b,log_mode,uniform_pdf)) + return false; + if(!MathCumulativeDistributionUniform(x_values,a,b,tail,log_mode,uniform_cdf)) + return false; + if(!MathQuantileUniform(uniform_cdf,a,b,tail,log_mode,uniform_quantile)) + return false; +//--- calculate differences + if(tail==true) + { + //--- lower tail mode (cdf) + if(log_mode==true) + { + //--- logarithmic values + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_uniform_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_uniform_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 4: test generators + PrintFormat("%s: Test 4: Generators of random values",test_name); +//--- generate random values and calculate 4 moments + int random_data_count=10000; + double values_rnd[]; + if(MathRandomUniform(a,b,random_data_count,values_rnd)==true) + { + //--- calculate 4 moments of generated values + double mean=MathMean(values_rnd); + double variance=MathVariance(values_rnd); + double skewness=MathSkewness(values_rnd); + double kurtosis=MathKurtosis(values_rnd); + //--- inital values + double uniform_mean=0; + double uniform_variance=0; + double uniform_skewness=0; + double uniform_kurtosis=0; + //--- calculate theoretical values and compare with generated + if(MathMomentsUniform(a,b,uniform_mean,uniform_variance,uniform_skewness,uniform_kurtosis,error_code)) + { + PrintFormat("Mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",mean,mean,skewness,kurtosis); + PrintFormat("Theoretical values: mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",uniform_mean,uniform_variance,uniform_skewness,uniform_kurtosis); + PrintFormat("delta mean=%.4f, delta variance=%.4f delta skewness=%.4f delta kurtosis=%.4f",mean-uniform_mean,variance-uniform_variance,skewness-uniform_skewness,kurtosis-uniform_kurtosis); + } + else + return false; + } + else + return false; +//--- successful + PrintFormat("%s passed",test_name); + return true; + } +//+------------------------------------------------------------------+ +//| Test function for Geometric distribution | +//+------------------------------------------------------------------+ +bool TestGeometricDistribution(string test_name,const double p,const double &x_values[],const double &pdf_values[],const double &cdf_values[],precision_info &precision) + { + PrintFormat("%s started",test_name); +//--- + int N=ArraySize(x_values); + int error_code=0; +//--- arrays for calculated values + double geometric_pdf[]; + double geometric_cdf[]; + double geometric_quantile[]; +//--- arrays for differences + double delta_geometric_pdf[]; + double delta_geometric_cdf[]; + double delta_geometric_quantile[]; +//--- prepare arrays + ArrayResize(geometric_pdf,N); + ArrayResize(geometric_cdf,N); + ArrayResize(geometric_quantile,N); + ArrayResize(delta_geometric_pdf,N); + ArrayResize(delta_geometric_cdf,N); + ArrayResize(delta_geometric_quantile,N); +//--- test 1: single values + PrintFormat("%s: Test 1: Calculations for single values",test_name); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_geometric_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_geometric_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 2: calculations on arrays + PrintFormat("%s: Test 2: Calculations on arrays",test_name); +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityGeometric(x_values,p,geometric_pdf)) + return false; + if(!MathCumulativeDistributionGeometric(x_values,p,geometric_cdf)) + return false; + if(!MathQuantileGeometric(geometric_cdf,p,geometric_quantile)) + return false; +//--- calculate differences + ArrayResize(delta_geometric_pdf,N); + ArrayResize(delta_geometric_cdf,N); + ArrayResize(delta_geometric_quantile,N); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_geometric_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_geometric_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 3: calculations on arrays + PrintFormat("%s: Test 3: R-like overloaded functions",test_name); +//--- parameters for R-like overloaded functions + bool tail=true; + bool log_mode=true; +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityGeometric(x_values,p,log_mode,geometric_pdf)) + return false; + if(!MathCumulativeDistributionGeometric(x_values,p,tail,log_mode,geometric_cdf)) + return false; + if(!MathQuantileGeometric(geometric_cdf,p,tail,log_mode,geometric_quantile)) + return false; +//--- calculate differences + if(tail==true) + { + //--- lower tail mode (cdf) + if(log_mode==true) + { + //--- logarithmic values + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_geometric_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_geometric_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 4: test generators + PrintFormat("%s: Test 4: Generators of random values",test_name); +//--- generate random values and calculate 4 moments + int random_data_count=10000; + double values_rnd[]; + if(MathRandomGeometric(p,random_data_count,values_rnd)==true) + { + //--- calculate 4 moments of generated values + double mean=MathMean(values_rnd); + double variance=MathVariance(values_rnd); + double skewness=MathSkewness(values_rnd); + double kurtosis=MathKurtosis(values_rnd); + //--- inital values + double geometric_mean=0; + double geometric_variance=0; + double geometric_skewness=0; + double geometric_kurtosis=0; + //--- calculate theoretical values and compare with generated + if(MathMomentsGeometric(p,geometric_mean,geometric_variance,geometric_skewness,geometric_kurtosis,error_code)) + { + PrintFormat("Mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",mean,mean,skewness,kurtosis); + PrintFormat("Theoretical values: mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",geometric_mean,geometric_variance,geometric_skewness,geometric_kurtosis); + PrintFormat("delta mean=%.4f, delta variance=%.4f delta skewness=%.4f delta kurtosis=%.4f",mean-geometric_mean,variance-geometric_variance,skewness-geometric_skewness,kurtosis-geometric_kurtosis); + } + else + return false; + } + else + return false; +//--- successful + PrintFormat("%s passed",test_name); + return true; + } +//+------------------------------------------------------------------+ +//| Test function for Hypergeometric distribution | +//+------------------------------------------------------------------+ +bool TestHypergeometricDistribution(string test_name,const double m,const double k,const double n,const double &x_values[],const double &pdf_values[],const double &cdf_values[],precision_info &precision) + { + PrintFormat("%s started",test_name); +//--- + int N=ArraySize(x_values); + int error_code=0; +//--- arrays for calculated values + double hypergeometric_pdf[]; + double hypergeometric_cdf[]; + double hypergeometric_quantile[]; +//--- arrays for differences + double delta_hypergeometric_pdf[]; + double delta_hypergeometric_cdf[]; + double delta_hypergeometric_quantile[]; +//--- prepare arrays + ArrayResize(hypergeometric_pdf,N); + ArrayResize(hypergeometric_cdf,N); + ArrayResize(hypergeometric_quantile,N); + ArrayResize(delta_hypergeometric_pdf,N); + ArrayResize(delta_hypergeometric_cdf,N); + ArrayResize(delta_hypergeometric_quantile,N); +//--- test 1: single values + PrintFormat("%s: Test 1: Calculations for single values",test_name); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_hypergeometric_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_hypergeometric_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 2: calculations on arrays + PrintFormat("%s: Test 2: Calculations on arrays",test_name); +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityHypergeometric(x_values,m,k,n,hypergeometric_pdf)) + return false; + if(!MathCumulativeDistributionHypergeometric(x_values,m,k,n,hypergeometric_cdf)) + return false; + if(!MathQuantileHypergeometric(hypergeometric_cdf,m,k,n,hypergeometric_quantile)) + return false; +//--- calculate differences + ArrayResize(delta_hypergeometric_pdf,N); + ArrayResize(delta_hypergeometric_cdf,N); + ArrayResize(delta_hypergeometric_quantile,N); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_hypergeometric_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_hypergeometric_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 3: calculations on arrays + PrintFormat("%s: Test 3: R-like overloaded functions",test_name); +//--- parameters for R-like overloaded functions + bool tail=true; + bool log_mode=true; +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityHypergeometric(x_values,m,k,n,log_mode,hypergeometric_pdf)) + return false; + if(!MathCumulativeDistributionHypergeometric(x_values,m,k,n,tail,log_mode,hypergeometric_cdf)) + return false; + if(!MathQuantileHypergeometric(hypergeometric_cdf,m,k,n,tail,log_mode,hypergeometric_quantile)) + return false; +//--- calculate differences + if(tail==true) + { + //--- lower tail mode (cdf) + if(log_mode==true) + { + //--- logarithmic values + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_hypergeometric_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_hypergeometric_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 4: test generators + PrintFormat("%s: Test 4: Generators of random values",test_name); +//--- generate random values and calculate 4 moments + int random_data_count=10000; + double values_rnd[]; + if(MathRandomHypergeometric(m,k,n,random_data_count,values_rnd)==true) + { + //--- calculate 4 moments of generated values + double mean=MathMean(values_rnd); + double variance=MathVariance(values_rnd); + double skewness=MathSkewness(values_rnd); + double kurtosis=MathKurtosis(values_rnd); + //--- inital values + double hypergeometric_mean=0; + double hypergeometric_variance=0; + double hypergeometric_skewness=0; + double hypergeometric_kurtosis=0; + //--- calculate theoretical values and compare with generated + if(MathMomentsHypergeometric(m,k,n,hypergeometric_mean,hypergeometric_variance,hypergeometric_skewness,hypergeometric_kurtosis,error_code)) + { + PrintFormat("Mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",mean,mean,skewness,kurtosis); + PrintFormat("Theoretical values: mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",hypergeometric_mean,hypergeometric_variance,hypergeometric_skewness,hypergeometric_kurtosis); + PrintFormat("delta mean=%.4f, delta variance=%.4f delta skewness=%.4f delta kurtosis=%.4f",mean-hypergeometric_mean,variance-hypergeometric_variance,skewness-hypergeometric_skewness,kurtosis-hypergeometric_kurtosis); + } + else + return false; + } + else + return false; +//--- successful + PrintFormat("%s passed",test_name); + return true; + } +//+------------------------------------------------------------------+ +//| Test function for Logistic distribution | +//+------------------------------------------------------------------+ +bool TestLogisticDistribution(string test_name,const double mu,const double sigma,const double &x_values[],const double &pdf_values[],const double &cdf_values[],precision_info &precision) + { + PrintFormat("%s started",test_name); +//--- + int N=ArraySize(x_values); + int error_code=0; +//--- arrays for calculated values + double logistic_pdf[]; + double logistic_cdf[]; + double logistic_quantile[]; +//--- arrays for differences + double delta_logistic_pdf[]; + double delta_logistic_cdf[]; + double delta_logistic_quantile[]; +//--- prepare arrays + ArrayResize(logistic_pdf,N); + ArrayResize(logistic_cdf,N); + ArrayResize(logistic_quantile,N); + ArrayResize(delta_logistic_pdf,N); + ArrayResize(delta_logistic_cdf,N); + ArrayResize(delta_logistic_quantile,N); +//--- test 1: single values + PrintFormat("%s: Test 1: Calculations for single values",test_name); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_logistic_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_logistic_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 2: calculations on arrays + PrintFormat("%s: Test 2: Calculations on arrays",test_name); +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityLogistic(x_values,mu,sigma,logistic_pdf)) + return false; + if(!MathCumulativeDistributionLogistic(x_values,mu,sigma,logistic_cdf)) + return false; + if(!MathQuantileLogistic(logistic_cdf,mu,sigma,logistic_quantile)) + return false; +//--- calculate differences + ArrayResize(delta_logistic_pdf,N); + ArrayResize(delta_logistic_cdf,N); + ArrayResize(delta_logistic_quantile,N); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_logistic_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_logistic_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 3: calculations on arrays + PrintFormat("%s: Test 3: R-like overloaded functions",test_name); +//--- parameters for R-like overloaded functions + bool tail=true; + bool log_mode=true; +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityLogistic(x_values,mu,sigma,log_mode,logistic_pdf)) + return false; + if(!MathCumulativeDistributionLogistic(x_values,mu,sigma,tail,log_mode,logistic_cdf)) + return false; + if(!MathQuantileLogistic(logistic_cdf,mu,sigma,tail,log_mode,logistic_quantile)) + return false; +//--- calculate differences + if(tail==true) + { + //--- lower tail mode (cdf) + if(log_mode==true) + { + //--- logarithmic values + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_logistic_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_logistic_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 4: test generators + PrintFormat("%s: Test 4: Generators of random values",test_name); +//--- generate random values and calculate 4 moments + int random_data_count=10000; + double values_rnd[]; + if(MathRandomLogistic(mu,sigma,random_data_count,values_rnd)==true) + { + //--- calculate 4 moments of generated values + double mean=MathMean(values_rnd); + double variance=MathVariance(values_rnd); + double skewness=MathSkewness(values_rnd); + double kurtosis=MathKurtosis(values_rnd); + //--- inital values + double logistic_mean=0; + double logistic_variance=0; + double logistic_skewness=0; + double logistic_kurtosis=0; + //--- calculate theoretical values and compare with generated + if(MathMomentsLogistic(mu,sigma,logistic_mean,logistic_variance,logistic_skewness,logistic_kurtosis,error_code)) + { + PrintFormat("Mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",mean,mean,skewness,kurtosis); + PrintFormat("Theoretical values: mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",logistic_mean,logistic_variance,logistic_skewness,logistic_kurtosis); + PrintFormat("delta mean=%.4f, delta variance=%.4f delta skewness=%.4f delta kurtosis=%.4f",mean-logistic_mean,variance-logistic_variance,skewness-logistic_skewness,kurtosis-logistic_kurtosis); + } + else + return false; + } + else + return false; +//--- successful + PrintFormat("%s passed",test_name); + return true; + } +//+------------------------------------------------------------------+ +//| Test function for Weibull distribution | +//+------------------------------------------------------------------+ +bool TestWeibullDistribution(string test_name,const double a,const double b,const double &x_values[],const double &pdf_values[],const double &cdf_values[],precision_info &precision) + { + PrintFormat("%s started",test_name); +//--- + int N=ArraySize(x_values); + int error_code=0; +//--- arrays for calculated values + double weibull_pdf[]; + double weibull_cdf[]; + double weibull_quantile[]; +//--- arrays for differences + double delta_weibull_pdf[]; + double delta_weibull_cdf[]; + double delta_weibull_quantile[]; +//--- prepare arrays + ArrayResize(weibull_pdf,N); + ArrayResize(weibull_cdf,N); + ArrayResize(weibull_quantile,N); + ArrayResize(delta_weibull_pdf,N); + ArrayResize(delta_weibull_cdf,N); + ArrayResize(delta_weibull_quantile,N); +//--- test 1: single values + PrintFormat("%s: Test 1: Calculations for single values",test_name); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_weibull_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_weibull_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 2: calculations on arrays + PrintFormat("%s: Test 2: Calculations on arrays",test_name); +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityWeibull(x_values,a,b,weibull_pdf)) + return false; + if(!MathCumulativeDistributionWeibull(x_values,a,b,weibull_cdf)) + return false; + if(!MathQuantileWeibull(weibull_cdf,a,b,weibull_quantile)) + return false; +//--- calculate differences + ArrayResize(delta_weibull_pdf,N); + ArrayResize(delta_weibull_cdf,N); + ArrayResize(delta_weibull_quantile,N); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_weibull_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_weibull_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 3: calculations on arrays + PrintFormat("%s: Test 3: R-like overloaded functions",test_name); +//--- parameters for R-like overloaded functions + bool tail=true; + bool log_mode=true; +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityWeibull(x_values,a,b,log_mode,weibull_pdf)) + return false; + if(!MathCumulativeDistributionWeibull(x_values,a,b,tail,log_mode,weibull_cdf)) + return false; + if(!MathQuantileWeibull(weibull_cdf,a,b,tail,log_mode,weibull_quantile)) + return false; +//--- calculate differences + if(tail==true) + { + //--- lower tail mode (cdf) + if(log_mode==true) + { + //--- logarithmic values + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_weibull_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_weibull_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 4: test generators + PrintFormat("%s: Test 4: Generators of random values",test_name); +//--- generate random values and calculate 4 moments + int random_data_count=10000; + double values_rnd[]; + if(MathRandomWeibull(a,b,random_data_count,values_rnd)==true) + { + //--- calculate 4 moments of generated values + double mean=MathMean(values_rnd); + double variance=MathVariance(values_rnd); + double skewness=MathSkewness(values_rnd); + double kurtosis=MathKurtosis(values_rnd); + //--- inital values + double weibull_mean=0; + double weibull_variance=0; + double weibull_skewness=0; + double weibull_kurtosis=0; + //--- calculate theoretical values and compare with generated + if(MathMomentsWeibull(a,b,weibull_mean,weibull_variance,weibull_skewness,weibull_kurtosis,error_code)) + { + PrintFormat("Mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",mean,mean,skewness,kurtosis); + PrintFormat("Theoretical values: mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",weibull_mean,weibull_variance,weibull_skewness,weibull_kurtosis); + PrintFormat("delta mean=%.4f, delta variance=%.4f delta skewness=%.4f delta kurtosis=%.4f",mean-weibull_mean,variance-weibull_variance,skewness-weibull_skewness,kurtosis-weibull_kurtosis); + } + else + return false; + } + else + return false; +//--- successful + PrintFormat("%s passed",test_name); + return true; + } +//+------------------------------------------------------------------+ +//| Test function for Poisson distribution | +//+------------------------------------------------------------------+ +bool TestPoissonDistribution(string test_name,const double lambda,const double &x_values[],const double &pdf_values[],const double &cdf_values[],precision_info &precision) + { + PrintFormat("%s started",test_name); +//--- + int N=ArraySize(x_values); + int error_code=0; +//--- arrays for calculated values + double poisson_pdf[]; + double poisson_cdf[]; + double poisson_quantile[]; +//--- arrays for differences + double delta_poisson_pdf[]; + double delta_poisson_cdf[]; + double delta_poisson_quantile[]; +//--- prepare arrays + ArrayResize(poisson_pdf,N); + ArrayResize(poisson_cdf,N); + ArrayResize(poisson_quantile,N); + ArrayResize(delta_poisson_pdf,N); + ArrayResize(delta_poisson_cdf,N); + ArrayResize(delta_poisson_quantile,N); +//--- test 1: single values + PrintFormat("%s: Test 1: Calculations for single values",test_name); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_poisson_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_poisson_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 2: calculations on arrays + PrintFormat("%s: Test 2: Calculations on arrays",test_name); +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityPoisson(x_values,lambda,poisson_pdf)) + return false; + if(!MathCumulativeDistributionPoisson(x_values,lambda,poisson_cdf)) + return false; + if(!MathQuantilePoisson(poisson_cdf,lambda,poisson_quantile)) + return false; +//--- calculate differences + ArrayResize(delta_poisson_pdf,N); + ArrayResize(delta_poisson_cdf,N); + ArrayResize(delta_poisson_quantile,N); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_poisson_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_poisson_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 3: calculations on arrays + PrintFormat("%s: Test 3: R-like overloaded functions",test_name); +//--- parameters for R-like overloaded functions + bool tail=true; + bool log_mode=true; +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityPoisson(x_values,lambda,log_mode,poisson_pdf)) + return false; + if(!MathCumulativeDistributionPoisson(x_values,lambda,tail,log_mode,poisson_cdf)) + return false; + if(!MathQuantilePoisson(poisson_cdf,lambda,tail,log_mode,poisson_quantile)) + return false; +//--- calculate differences + if(tail==true) + { + //--- lower tail mode (cdf) + if(log_mode==true) + { + //--- logarithmic values + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_poisson_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_poisson_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 4: test generators + PrintFormat("%s: Test 4: Generators of random values",test_name); +//--- generate random values and calculate 4 moments + int random_data_count=10000; + double values_rnd[]; + if(MathRandomPoisson(lambda,random_data_count,values_rnd)==true) + { + //--- calculate 4 moments of generated values + double mean=MathMean(values_rnd); + double variance=MathVariance(values_rnd); + double skewness=MathSkewness(values_rnd); + double kurtosis=MathKurtosis(values_rnd); + //--- inital values + double poisson_mean=0; + double poisson_variance=0; + double poisson_skewness=0; + double poisson_kurtosis=0; + //--- calculate theoretical values and compare with generated + if(MathMomentsPoisson(lambda,poisson_mean,poisson_variance,poisson_skewness,poisson_kurtosis,error_code)) + { + PrintFormat("Mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",mean,mean,skewness,kurtosis); + PrintFormat("Theoretical values: mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",poisson_mean,poisson_variance,poisson_skewness,poisson_kurtosis); + PrintFormat("delta mean=%.4f, delta variance=%.4f delta skewness=%.4f delta kurtosis=%.4f",mean-poisson_mean,variance-poisson_variance,skewness-poisson_skewness,kurtosis-poisson_kurtosis); + } + else + return false; + } + else + return false; +//--- successful + PrintFormat("%s passed",test_name); + return true; + } +//+------------------------------------------------------------------+ +//| Test function for F distribution | +//+------------------------------------------------------------------+ +bool TestFDistribution(string test_name,const double nu1,const double nu2,const double &x_values[],const double &pdf_values[],const double &cdf_values[],precision_info &precision) + { + PrintFormat("%s started",test_name); +//--- + int N=ArraySize(x_values); + int error_code=0; +//--- arrays for calculated values + double f_pdf[]; + double f_cdf[]; + double f_quantile[]; +//--- arrays for differences + double delta_f_pdf[]; + double delta_f_cdf[]; + double delta_f_quantile[]; +//--- prepare arrays + ArrayResize(f_pdf,N); + ArrayResize(f_cdf,N); + ArrayResize(f_quantile,N); + ArrayResize(delta_f_pdf,N); + ArrayResize(delta_f_cdf,N); + ArrayResize(delta_f_quantile,N); +//--- test 1: single values + PrintFormat("%s: Test 1: Calculations for single values",test_name); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_f_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_f_quantile[i])>calc_precision_quantile) + return false; + } + +//--- test 2: calculations on arrays + PrintFormat("%s: Test 2: Calculations on arrays",test_name); +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityF(x_values,nu1,nu2,f_pdf)) + return false; + if(!MathCumulativeDistributionF(x_values,nu1,nu2,f_cdf)) + return false; + if(!MathQuantileF(f_cdf,nu1,nu2,f_quantile)) + return false; +//--- calculate differences + ArrayResize(delta_f_pdf,N); + ArrayResize(delta_f_cdf,N); + ArrayResize(delta_f_quantile,N); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_f_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_f_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 3: calculations on arrays + PrintFormat("%s: Test 3: R-like overloaded functions",test_name); +//--- parameters for R-like overloaded functions + bool tail=true; + bool log_mode=true; +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityF(x_values,nu1,nu2,log_mode,f_pdf)) + return false; + if(!MathCumulativeDistributionF(x_values,nu1,nu2,tail,log_mode,f_cdf)) + return false; + if(!MathQuantileF(f_cdf,nu1,nu2,tail,log_mode,f_quantile)) + return false; +//--- calculate differences + if(tail==true) + { + //--- lower tail mode (cdf) + if(log_mode==true) + { + //--- logarithmic values + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_f_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_f_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 4: test generators + PrintFormat("%s: Test 4: Generators of random values",test_name); +//--- generate random values and calculate 4 moments + int random_data_count=10000; + double values_rnd[]; + if(MathRandomF(nu1,nu2,random_data_count,values_rnd)==true) + { + //--- calculate 4 moments of generated values + double mean=MathMean(values_rnd); + double variance=MathVariance(values_rnd); + double skewness=MathSkewness(values_rnd); + double kurtosis=MathKurtosis(values_rnd); + //--- inital values + double f_mean=0; + double f_variance=0; + double f_skewness=0; + double f_kurtosis=0; + //--- calculate theoretical values and compare with generated + if(MathMomentsF(nu1,nu2,f_mean,f_variance,f_skewness,f_kurtosis,error_code)) + { + PrintFormat("Mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",mean,mean,skewness,kurtosis); + PrintFormat("Theoretical values: mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",f_mean,f_variance,f_skewness,f_kurtosis); + PrintFormat("delta mean=%.4f, delta variance=%.4f delta skewness=%.4f delta kurtosis=%.4f",mean-f_mean,variance-f_variance,skewness-f_skewness,kurtosis-f_kurtosis); + } + else + return false; + } + else + return false; +//--- successful + PrintFormat("%s passed",test_name); + return true; + } +//+------------------------------------------------------------------+ +//| Test function for ChiSquare distribution | +//+------------------------------------------------------------------+ +bool TestChiSquareDistribution(string test_name,const double nu,const double &x_values[],const double &pdf_values[],const double &cdf_values[],precision_info &precision) + { + PrintFormat("%s started",test_name); +//--- + int N=ArraySize(x_values); + int error_code=0; +//--- arrays for calculated values + double chisquare_pdf[]; + double chisquare_cdf[]; + double chisquare_quantile[]; +//--- arrays for differences + double delta_chisquare_pdf[]; + double delta_chisquare_cdf[]; + double delta_chisquare_quantile[]; +//--- prepare arrays + ArrayResize(chisquare_pdf,N); + ArrayResize(chisquare_cdf,N); + ArrayResize(chisquare_quantile,N); + ArrayResize(delta_chisquare_pdf,N); + ArrayResize(delta_chisquare_cdf,N); + ArrayResize(delta_chisquare_quantile,N); +//--- test 1: single values + PrintFormat("%s: Test 1: Calculations for single values",test_name); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_chisquare_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_chisquare_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 2: calculations on arrays + PrintFormat("%s: Test 2: Calculations on arrays",test_name); +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityChiSquare(x_values,nu,chisquare_pdf)) + return false; + if(!MathCumulativeDistributionChiSquare(x_values,nu,chisquare_cdf)) + return false; + if(!MathQuantileChiSquare(chisquare_cdf,nu,chisquare_quantile)) + return false; +//--- calculate differences + ArrayResize(delta_chisquare_pdf,N); + ArrayResize(delta_chisquare_cdf,N); + ArrayResize(delta_chisquare_quantile,N); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_chisquare_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_chisquare_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 3: calculations on arrays + PrintFormat("%s: Test 3: R-like overloaded functions",test_name); +//--- parameters for R-like overloaded functions + bool tail=true; + bool log_mode=true; +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityChiSquare(x_values,nu,log_mode,chisquare_pdf)) + return false; + if(!MathCumulativeDistributionChiSquare(x_values,nu,tail,log_mode,chisquare_cdf)) + return false; + if(!MathQuantileChiSquare(chisquare_cdf,nu,tail,log_mode,chisquare_quantile)) + return false; +//--- calculate differences + if(tail==true) + { + //--- lower tail mode (cdf) + if(log_mode==true) + { + //--- logarithmic values + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_chisquare_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_chisquare_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 4: test generators + PrintFormat("%s: Test 4: Generators of random values",test_name); +//--- generate random values and calculate 4 moments + int random_data_count=10000; + double values_rnd[]; + if(MathRandomChiSquare(nu,random_data_count,values_rnd)==true) + { + //--- calculate 4 moments of generated values + double mean=MathMean(values_rnd); + double variance=MathVariance(values_rnd); + double skewness=MathSkewness(values_rnd); + double kurtosis=MathKurtosis(values_rnd); + //--- inital values + double chisquare_mean=0; + double chisquare_variance=0; + double chisquare_skewness=0; + double chisquare_kurtosis=0; + //--- calculate theoretical values and compare with generated + if(MathMomentsChiSquare(nu,chisquare_mean,chisquare_variance,chisquare_skewness,chisquare_kurtosis,error_code)) + { + PrintFormat("Mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",mean,mean,skewness,kurtosis); + PrintFormat("Theoretical values: mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",chisquare_mean,chisquare_variance,chisquare_skewness,chisquare_kurtosis); + PrintFormat("delta mean=%.4f, delta variance=%.4f delta skewness=%.4f delta kurtosis=%.4f",mean-chisquare_mean,variance-chisquare_variance,skewness-chisquare_skewness,kurtosis-chisquare_kurtosis); + } + else + return false; + } + else + return false; +//--- successful + PrintFormat("%s passed",test_name); + return true; + } +//+------------------------------------------------------------------+ +//| Test function for NoncentralChiSquare distribution | +//+------------------------------------------------------------------+ +bool TestNoncentralChiSquareDistribution(string test_name,const double nu,const double sigma,const double &x_values[],const double &pdf_values[],const double &cdf_values[],precision_info &precision) + { + PrintFormat("%s started",test_name); +//--- + int N=ArraySize(x_values); + int error_code=0; +//--- arrays for calculated values + double noncentral_chisquare_pdf[]; + double noncentral_chisquare_cdf[]; + double noncentral_chisquare_quantile[]; +//--- arrays for differences + double delta_noncentral_chisquare_pdf[]; + double delta_noncentral_chisquare_cdf[]; + double delta_noncentral_chisquare_quantile[]; +//--- prepare arrays + ArrayResize(noncentral_chisquare_pdf,N); + ArrayResize(noncentral_chisquare_cdf,N); + ArrayResize(noncentral_chisquare_quantile,N); + ArrayResize(delta_noncentral_chisquare_pdf,N); + ArrayResize(delta_noncentral_chisquare_cdf,N); + ArrayResize(delta_noncentral_chisquare_quantile,N); +//--- test 1: single values + PrintFormat("%s: Test 1: Calculations for single values",test_name); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_noncentral_chisquare_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_noncentral_chisquare_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 2: calculations on arrays + PrintFormat("%s: Test 2: Calculations on arrays",test_name); +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityNoncentralChiSquare(x_values,nu,sigma,noncentral_chisquare_pdf)) + return false; + if(!MathCumulativeDistributionNoncentralChiSquare(x_values,nu,sigma,noncentral_chisquare_cdf)) + return false; + if(!MathQuantileNoncentralChiSquare(noncentral_chisquare_cdf,nu,sigma,noncentral_chisquare_quantile)) + return false; +//--- calculate differences + ArrayResize(delta_noncentral_chisquare_pdf,N); + ArrayResize(delta_noncentral_chisquare_cdf,N); + ArrayResize(delta_noncentral_chisquare_quantile,N); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_noncentral_chisquare_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_noncentral_chisquare_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 3: calculations on arrays + PrintFormat("%s: Test 3: R-like overloaded functions",test_name); +//--- parameters for R-like overloaded functions + bool tail=true; + bool log_mode=true; +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityNoncentralChiSquare(x_values,nu,sigma,log_mode,noncentral_chisquare_pdf)) + return false; + if(!MathCumulativeDistributionNoncentralChiSquare(x_values,nu,sigma,tail,log_mode,noncentral_chisquare_cdf)) + return false; + if(!MathQuantileNoncentralChiSquare(noncentral_chisquare_cdf,nu,sigma,tail,log_mode,noncentral_chisquare_quantile)) + return false; +//--- calculate differences + if(tail==true) + { + //--- lower tail mode (cdf) + if(log_mode==true) + { + //--- logarithmic values + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_noncentral_chisquare_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_noncentral_chisquare_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 4: test generators + PrintFormat("%s: Test 4: Generators of random values",test_name); +//--- generate random values and calculate 4 moments + int random_data_count=10000; + double values_rnd[]; + if(MathRandomNoncentralChiSquare(nu,sigma,random_data_count,values_rnd)==true) + { + //--- calculate 4 moments of generated values + double mean=MathMean(values_rnd); + double variance=MathVariance(values_rnd); + double skewness=MathSkewness(values_rnd); + double kurtosis=MathKurtosis(values_rnd); + //--- inital values + double noncentral_chisquare_mean=0; + double noncentral_chisquare_variance=0; + double noncentral_chisquare_skewness=0; + double noncentral_chisquare_kurtosis=0; + //--- calculate theoretical values and compare with generated + if(MathMomentsNoncentralChiSquare(nu,sigma,noncentral_chisquare_mean,noncentral_chisquare_variance,noncentral_chisquare_skewness,noncentral_chisquare_kurtosis,error_code)) + { + PrintFormat("Mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",mean,mean,skewness,kurtosis); + PrintFormat("Theoretical values: mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",noncentral_chisquare_mean,noncentral_chisquare_variance,noncentral_chisquare_skewness,noncentral_chisquare_kurtosis); + PrintFormat("delta mean=%.4f, delta variance=%.4f delta skewness=%.4f delta kurtosis=%.4f",mean-noncentral_chisquare_mean,variance-noncentral_chisquare_variance,skewness-noncentral_chisquare_skewness,kurtosis-noncentral_chisquare_kurtosis); + } + else + return false; + } + else + return false; +//--- successful + PrintFormat("%s passed",test_name); + return true; + } +//+------------------------------------------------------------------+ +//| Test function for NoncentralF distribution | +//+------------------------------------------------------------------+ +bool TestNoncentralFDistribution(string test_name,const double nu1,const double nu2,const double sigma,const double &x_values[],const double &pdf_values[],const double &cdf_values[],precision_info &precision) + { + PrintFormat("%s started",test_name); +//--- + int N=ArraySize(x_values); + int error_code=0; +//--- arrays for calculated values + double noncentral_f_pdf[]; + double noncentral_f_cdf[]; + double noncentral_f_quantile[]; +//--- arrays for differences + double delta_noncentral_f_pdf[]; + double delta_noncentral_f_cdf[]; + double delta_noncentral_f_quantile[]; +//--- prepare arrays + ArrayResize(noncentral_f_pdf,N); + ArrayResize(noncentral_f_cdf,N); + ArrayResize(noncentral_f_quantile,N); + ArrayResize(delta_noncentral_f_pdf,N); + ArrayResize(delta_noncentral_f_cdf,N); + ArrayResize(delta_noncentral_f_quantile,N); +//--- test 1: single values + PrintFormat("%s: Test 1: Calculations for single values",test_name); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_noncentral_f_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_noncentral_f_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 2: calculations on arrays + PrintFormat("%s: Test 2: Calculations on arrays",test_name); +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityNoncentralF(x_values,nu1,nu2,sigma,noncentral_f_pdf)) + return false; + if(!MathCumulativeDistributionNoncentralF(x_values,nu1,nu2,sigma,noncentral_f_cdf)) + return false; + if(!MathQuantileNoncentralF(noncentral_f_cdf,nu1,nu2,sigma,noncentral_f_quantile)) + return false; +//--- calculate differences + ArrayResize(delta_noncentral_f_pdf,N); + ArrayResize(delta_noncentral_f_cdf,N); + ArrayResize(delta_noncentral_f_quantile,N); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_noncentral_f_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_noncentral_f_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 3: calculations on arrays + PrintFormat("%s: Test 3: R-like overloaded functions",test_name); +//--- parameters for R-like overloaded functions + bool tail=true; + bool log_mode=true; +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityNoncentralF(x_values,nu1,nu2,sigma,log_mode,noncentral_f_pdf)) + return false; + if(!MathCumulativeDistributionNoncentralF(x_values,nu1,nu2,sigma,tail,log_mode,noncentral_f_cdf)) + return false; + if(!MathQuantileNoncentralF(noncentral_f_cdf,nu1,nu2,sigma,tail,log_mode,noncentral_f_quantile)) + return false; +//--- calculate differences + if(tail==true) + { + //--- lower tail mode (cdf) + if(log_mode==true) + { + //--- logarithmic values + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_noncentral_f_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_noncentral_f_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 4: test generators + PrintFormat("%s: Test 4: Generators of random values",test_name); +//--- generate random values and calculate 4 moments + int random_data_count=10000; + double values_rnd[]; + if(MathRandomNoncentralF(nu1,nu2,sigma,random_data_count,values_rnd)==true) + { + //--- calculate 4 moments of generated values + double mean=MathMean(values_rnd); + double variance=MathVariance(values_rnd); + double skewness=MathSkewness(values_rnd); + double kurtosis=MathKurtosis(values_rnd); + //--- inital values + double noncentral_f_mean=0; + double noncentral_f_variance=0; + double noncentral_f_skewness=0; + double noncentral_f_kurtosis=0; + //--- calculate theoretical values and compare with generated + if(MathMomentsNoncentralF(nu1,nu2,sigma,noncentral_f_mean,noncentral_f_variance,noncentral_f_skewness,noncentral_f_kurtosis,error_code)) + { + PrintFormat("Mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",mean,mean,skewness,kurtosis); + PrintFormat("Theoretical values: mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",noncentral_f_mean,noncentral_f_variance,noncentral_f_skewness,noncentral_f_kurtosis); + PrintFormat("delta mean=%.4f, delta variance=%.4f delta skewness=%.4f delta kurtosis=%.4f",mean-noncentral_f_mean,variance-noncentral_f_variance,skewness-noncentral_f_skewness,kurtosis-noncentral_f_kurtosis); + } + else + return false; + } + else + return false; +//--- successful + PrintFormat("%s passed",test_name); + return true; + } +//+------------------------------------------------------------------+ +//| Test function for Noncentral Beta distribution | +//+------------------------------------------------------------------+ +bool TestNoncentralBetaDistribution(string test_name,const double a,const double b,const double lambda,const double &x_values[],const double &pdf_values[],const double &cdf_values[],precision_info &precision) + { + PrintFormat("%s started",test_name); +//--- + int N=ArraySize(x_values); + int error_code=0; +//--- arrays for calculated values + double noncentral_beta_pdf[]; + double noncentral_beta_cdf[]; + double noncentral_beta_quantile[]; +//--- arrays for differences + double delta_noncentral_beta_pdf[]; + double delta_noncentral_beta_cdf[]; + double delta_noncentral_beta_quantile[]; +//--- prepare arrays + ArrayResize(noncentral_beta_pdf,N); + ArrayResize(noncentral_beta_cdf,N); + ArrayResize(noncentral_beta_quantile,N); + ArrayResize(delta_noncentral_beta_pdf,N); + ArrayResize(delta_noncentral_beta_cdf,N); + ArrayResize(delta_noncentral_beta_quantile,N); +//--- test 1: single values + PrintFormat("%s: Test 1: Calculations for single values",test_name); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_noncentral_beta_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_noncentral_beta_quantile[i])>calc_precision_quantile) + return false; + } + +//--- test 2: calculations on arrays + PrintFormat("%s: Test 2: Calculations on arrays",test_name); +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityNoncentralBeta(x_values,a,b,lambda,noncentral_beta_pdf)) + return false; + if(!MathCumulativeDistributionNoncentralBeta(x_values,a,b,lambda,noncentral_beta_cdf)) + return false; + if(!MathQuantileNoncentralBeta(noncentral_beta_cdf,a,b,lambda,noncentral_beta_quantile)) + return false; +//--- calculate differences + ArrayResize(delta_noncentral_beta_pdf,N); + ArrayResize(delta_noncentral_beta_cdf,N); + ArrayResize(delta_noncentral_beta_quantile,N); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_noncentral_beta_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_noncentral_beta_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 3: calculations on arrays + PrintFormat("%s: Test 3: R-like overloaded functions",test_name); +//--- parameters for R-like overloaded functions + bool tail=true; + bool log_mode=true; +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityNoncentralBeta(x_values,a,b,lambda,log_mode,noncentral_beta_pdf)) + return false; + if(!MathCumulativeDistributionNoncentralBeta(x_values,a,b,lambda,tail,log_mode,noncentral_beta_cdf)) + return false; + if(!MathQuantileNoncentralBeta(noncentral_beta_cdf,a,b,lambda,tail,log_mode,noncentral_beta_quantile)) + return false; +//--- calculate differences + if(tail==true) + { + //--- lower tail mode (cdf) + if(log_mode==true) + { + //--- logarithmic values + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_noncentral_beta_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_noncentral_beta_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 4: test generators + PrintFormat("%s: Test 4: Generators of random values",test_name); +//--- generate random values and calculate 4 moments + int random_data_count=10000; + double values_rnd[]; + if(MathRandomNoncentralBeta(a,b,lambda,random_data_count,values_rnd)==true) + { + //--- calculate 4 moments of generated values + double mean=MathMean(values_rnd); + double variance=MathVariance(values_rnd); + double skewness=MathSkewness(values_rnd); + double kurtosis=MathKurtosis(values_rnd); + //--- inital values + double noncentral_beta_mean=0; + double noncentral_beta_variance=0; + double noncentral_beta_skewness=0; + double noncentral_beta_kurtosis=0; + //--- calculate theoretical values and compare with generated + if(MathMomentsNoncentralBeta(a,b,lambda,noncentral_beta_mean,noncentral_beta_variance,noncentral_beta_skewness,noncentral_beta_kurtosis,error_code)) + { + PrintFormat("Mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",mean,mean,skewness,kurtosis); + PrintFormat("Theoretical values: mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",noncentral_beta_mean,noncentral_beta_variance,noncentral_beta_skewness,noncentral_beta_kurtosis); + PrintFormat("delta mean=%.4f, delta variance=%.4f delta skewness=%.4f delta kurtosis=%.4f",mean-noncentral_beta_mean,variance-noncentral_beta_variance,skewness-noncentral_beta_skewness,kurtosis-noncentral_beta_kurtosis); + } + else + return false; + } + else + return false; +//--- successful + PrintFormat("%s passed",test_name); + return true; + } +//+------------------------------------------------------------------+ +//| Test function for Negative Binomial distribution | +//+------------------------------------------------------------------+ +bool TestNegativeBinomialDistribution(string test_name,const double r,const double p,const double &x_values[],const double &pdf_values[],const double &cdf_values[],precision_info &precision) + { + PrintFormat("%s started",test_name); +//--- + int N=ArraySize(x_values); + int error_code=0; +//--- arrays for calculated values + double negative_binomial_pdf[]; + double negative_binomial_cdf[]; + double negative_binomial_quantile[]; +//--- arrays for differences + double delta_negative_binomial_pdf[]; + double delta_negative_binomial_cdf[]; + double delta_negative_binomial_quantile[]; +//--- prepare arrays + ArrayResize(negative_binomial_pdf,N); + ArrayResize(negative_binomial_cdf,N); + ArrayResize(negative_binomial_quantile,N); + ArrayResize(delta_negative_binomial_pdf,N); + ArrayResize(delta_negative_binomial_cdf,N); + ArrayResize(delta_negative_binomial_quantile,N); +//--- test 1: single values + PrintFormat("%s: Test 1: Calculations for single values",test_name); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_negative_binomial_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_negative_binomial_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 2: calculations on arrays + PrintFormat("%s: Test 2: Calculations on arrays",test_name); +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityNegativeBinomial(x_values,r,p,negative_binomial_pdf)) + return false; + if(!MathCumulativeDistributionNegativeBinomial(x_values,r,p,negative_binomial_cdf)) + return false; + if(!MathQuantileNegativeBinomial(negative_binomial_cdf,r,p,negative_binomial_quantile)) + return false; +//--- calculate differences + ArrayResize(delta_negative_binomial_pdf,N); + ArrayResize(delta_negative_binomial_cdf,N); + ArrayResize(delta_negative_binomial_quantile,N); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_negative_binomial_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_negative_binomial_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 3: calculations on arrays + PrintFormat("%s: Test 3: R-like overloaded functions",test_name); +//--- parameters for R-like overloaded functions + bool tail=true; + bool log_mode=true; +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityNegativeBinomial(x_values,r,p,log_mode,negative_binomial_pdf)) + return false; + if(!MathCumulativeDistributionNegativeBinomial(x_values,r,p,tail,log_mode,negative_binomial_cdf)) + return false; + if(!MathQuantileNegativeBinomial(negative_binomial_cdf,r,p,tail,log_mode,negative_binomial_quantile)) + return false; +//--- calculate differences + if(tail==true) + { + //--- lower tail mode (cdf) + if(log_mode==true) + { + //--- logarithmic values + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_negative_binomial_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_negative_binomial_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 4: test generators + PrintFormat("%s: Test 4: Generators of random values",test_name); +//--- generate random values and calculate 4 moments + int random_data_count=10000; + double values_rnd[]; + if(MathRandomNegativeBinomial(r,p,random_data_count,values_rnd)==true) + { + //--- calculate 4 moments of generated values + double mean=MathMean(values_rnd); + double variance=MathVariance(values_rnd); + double skewness=MathSkewness(values_rnd); + double kurtosis=MathKurtosis(values_rnd); + //--- inital values + double negative_binomial_mean=0; + double negative_binomial_variance=0; + double negative_binomial_skewness=0; + double negative_binomial_kurtosis=0; + //--- calculate theoretical values and compare with generated + if(MathMomentsNegativeBinomial(r,p,negative_binomial_mean,negative_binomial_variance,negative_binomial_skewness,negative_binomial_kurtosis,error_code)) + { + PrintFormat("Mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",mean,mean,skewness,kurtosis); + PrintFormat("Theoretical values: mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",negative_binomial_mean,negative_binomial_variance,negative_binomial_skewness,negative_binomial_kurtosis); + PrintFormat("delta mean=%.4f, delta variance=%.4f delta skewness=%.4f delta kurtosis=%.4f",mean-negative_binomial_mean,variance-negative_binomial_variance,skewness-negative_binomial_skewness,kurtosis-negative_binomial_kurtosis); + } + else + return false; + } + else + return false; +//--- successful + PrintFormat("%s passed",test_name); + return true; + } +//+------------------------------------------------------------------+ +//| Test function for T distribution | +//+------------------------------------------------------------------+ +bool TestTDistribution(string test_name,const double nu,const double &x_values[],const double &pdf_values[],const double &cdf_values[],precision_info &precision) + { + PrintFormat("%s started",test_name); +//--- + int N=ArraySize(x_values); + int error_code=0; +//--- arrays for calculated values + double t_pdf[]; + double t_cdf[]; + double t_quantile[]; +//--- arrays for differences + double delta_t_pdf[]; + double delta_t_cdf[]; + double delta_t_quantile[]; +//--- prepare arrays + ArrayResize(t_pdf,N); + ArrayResize(t_cdf,N); + ArrayResize(t_quantile,N); + ArrayResize(delta_t_pdf,N); + ArrayResize(delta_t_cdf,N); + ArrayResize(delta_t_quantile,N); +//--- test 1: single values + PrintFormat("%s: Test 1: Calculations for single values",test_name); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_t_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_t_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 2: calculations on arrays + PrintFormat("%s: Test 2: Calculations on arrays",test_name); +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityT(x_values,nu,t_pdf)) + return false; + if(!MathCumulativeDistributionT(x_values,nu,t_cdf)) + return false; + if(!MathQuantileT(t_cdf,nu,t_quantile)) + return false; +//--- calculate differences + ArrayResize(delta_t_pdf,N); + ArrayResize(delta_t_cdf,N); + ArrayResize(delta_t_quantile,N); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_t_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_t_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 3: calculations on arrays + PrintFormat("%s: Test 3: R-like overloaded functions",test_name); +//--- parameters for R-like overloaded functions + bool tail=true; + bool log_mode=true; +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityT(x_values,nu,log_mode,t_pdf)) + return false; + if(!MathCumulativeDistributionT(x_values,nu,tail,log_mode,t_cdf)) + return false; + if(!MathQuantileT(t_cdf,nu,tail,log_mode,t_quantile)) + return false; +//--- calculate differences + if(tail==true) + { + //--- lower tail mode (cdf) + if(log_mode==true) + { + //--- logarithmic values + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_t_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_t_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 4: test generators + PrintFormat("%s: Test 4: Generators of random values",test_name); +//--- generate random values and calculate 4 moments + int random_data_count=10000; + double values_rnd[]; + if(MathRandomT(nu,random_data_count,values_rnd)==true) + { + //--- calculate 4 moments of generated values + double mean=MathMean(values_rnd); + double variance=MathVariance(values_rnd); + double skewness=MathSkewness(values_rnd); + double kurtosis=MathKurtosis(values_rnd); + //--- inital values + double t_mean=0; + double t_variance=0; + double t_skewness=0; + double t_kurtosis=0; + //--- calculate theoretical values and compare with generated + if(MathMomentsT(nu,t_mean,t_variance,t_skewness,t_kurtosis,error_code)) + { + PrintFormat("Mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",mean,mean,skewness,kurtosis); + PrintFormat("Theoretical values: mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",t_mean,t_variance,t_skewness,t_kurtosis); + PrintFormat("delta mean=%.4f, delta variance=%.4f delta skewness=%.4f delta kurtosis=%.4f",mean-t_mean,variance-t_variance,skewness-t_skewness,kurtosis-t_kurtosis); + } + else + return false; + } + else + return false; +//--- successful + PrintFormat("%s passed",test_name); + return true; + } +//+------------------------------------------------------------------+ +//| Test function for Noncentral T distribution | +//+------------------------------------------------------------------+ +bool TestNoncentralTDistribution(string test_name,const double nu,const double delta,const double &x_values[],const double &pdf_values[],const double &cdf_values[],precision_info &precision) + { + PrintFormat("%s started",test_name); +//--- + int N=ArraySize(x_values); + int error_code=0; +//--- arrays for calculated values + double noncentral_t_pdf[]; + double noncentral_t_cdf[]; + double noncentral_t_quantile[]; +//--- arrays for differences + double delta_noncentral_t_pdf[]; + double delta_noncentral_t_cdf[]; + double delta_noncentral_t_quantile[]; +//--- prepare arrays + ArrayResize(noncentral_t_pdf,N); + ArrayResize(noncentral_t_cdf,N); + ArrayResize(noncentral_t_quantile,N); + ArrayResize(delta_noncentral_t_pdf,N); + ArrayResize(delta_noncentral_t_cdf,N); + ArrayResize(delta_noncentral_t_quantile,N); +//--- test 1: single values + PrintFormat("%s: Test 1: Calculations for single values",test_name); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_noncentral_t_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_noncentral_t_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 2: calculations on arrays + PrintFormat("%s: Test 2: Calculations on arrays",test_name); +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityNoncentralT(x_values,nu,delta,noncentral_t_pdf)) + return false; + if(!MathCumulativeDistributionNoncentralT(x_values,nu,delta,noncentral_t_cdf)) + return false; + if(!MathQuantileNoncentralT(noncentral_t_cdf,nu,delta,noncentral_t_quantile)) + return false; +//--- calculate differences + ArrayResize(delta_noncentral_t_pdf,N); + ArrayResize(delta_noncentral_t_cdf,N); + ArrayResize(delta_noncentral_t_quantile,N); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_noncentral_t_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_noncentral_t_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 3: calculations on arrays + PrintFormat("%s: Test 3: R-like overloaded functions",test_name); +//--- parameters for R-like overloaded functions + bool tail=true; + bool log_mode=true; +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityNoncentralT(x_values,nu,delta,log_mode,noncentral_t_pdf)) + return false; + if(!MathCumulativeDistributionNoncentralT(x_values,nu,delta,tail,log_mode,noncentral_t_cdf)) + return false; + if(!MathQuantileNoncentralT(noncentral_t_cdf,nu,delta,tail,log_mode,noncentral_t_quantile)) + return false; +//--- calculate differences + if(tail==true) + { + //--- lower tail mode (cdf) + if(log_mode==true) + { + //--- logarithmic values + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_noncentral_t_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_noncentral_t_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 4: test generators + PrintFormat("%s: Test 4: Generators of random values",test_name); +//--- generate random values and calculate 4 moments + int random_data_count=10000; + double values_rnd[]; + if(MathRandomNoncentralT(nu,delta,random_data_count,values_rnd)==true) + { + //--- calculate 4 moments of generated values + double mean=MathMean(values_rnd); + double variance=MathVariance(values_rnd); + double skewness=MathSkewness(values_rnd); + double kurtosis=MathKurtosis(values_rnd); + //--- inital values + double noncentral_t_mean=0; + double noncentral_t_variance=0; + double noncentral_t_skewness=0; + double noncentral_t_kurtosis=0; + //--- calculate theoretical values and compare with generated + if(MathMomentsNoncentralT(nu,delta,noncentral_t_mean,noncentral_t_variance,noncentral_t_skewness,noncentral_t_kurtosis,error_code)) + { + PrintFormat("Mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",mean,mean,skewness,kurtosis); + PrintFormat("Theoretical values: mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",noncentral_t_mean,noncentral_t_variance,noncentral_t_skewness,noncentral_t_kurtosis); + PrintFormat("delta mean=%.4f, delta variance=%.4f delta skewness=%.4f delta kurtosis=%.4f",mean-noncentral_t_mean,variance-noncentral_t_variance,skewness-noncentral_t_skewness,kurtosis-noncentral_t_kurtosis); + } + else + return false; + } + else + return false; +//--- successful + PrintFormat("%s passed",test_name); + return true; + } +//+------------------------------------------------------------------+ +//| Test function for Normal distribution | +//+------------------------------------------------------------------+ +bool TestNormalDistribution(string test_name,const double mu,const double sigma,const double &x_values[],const double &pdf_values[],const double &cdf_values[],precision_info &precision) + { + PrintFormat("%s started",test_name); +//--- + int N=ArraySize(x_values); + int error_code=0; +//--- arrays for calculated values + double normal_pdf[]; + double normal_cdf[]; + double normal_quantile[]; +//--- arrays for differences + double delta_normal_pdf[]; + double delta_normal_cdf[]; + double delta_normal_quantile[]; +//--- prepare arrays + ArrayResize(normal_pdf,N); + ArrayResize(normal_cdf,N); + ArrayResize(normal_quantile,N); + ArrayResize(delta_normal_pdf,N); + ArrayResize(delta_normal_cdf,N); + ArrayResize(delta_normal_quantile,N); + +//--- test 1: single values + PrintFormat("%s: Test 1: Calculations for single values",test_name); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_normal_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_normal_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 2: calculations on arrays + PrintFormat("%s: Test 2: Calculations on arrays",test_name); +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityNormal(x_values,mu,sigma,normal_pdf)) + return false; + if(!MathCumulativeDistributionNormal(x_values,mu,sigma,normal_cdf)) + return false; + if(!MathQuantileNormal(normal_cdf,mu,sigma,normal_quantile)) + return false; +//--- calculate differences + ArrayResize(delta_normal_pdf,N); + ArrayResize(delta_normal_cdf,N); + ArrayResize(delta_normal_quantile,N); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_normal_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_normal_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 3: calculations on arrays + PrintFormat("%s: Test 3: R-like overloaded functions",test_name); +//--- parameters for R-like overloaded functions + bool tail=true; + bool log_mode=true; +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityNormal(x_values,mu,sigma,log_mode,normal_pdf)) + return false; + if(!MathCumulativeDistributionNormal(x_values,mu,sigma,tail,log_mode,normal_cdf)) + return false; + if(!MathQuantileNormal(normal_cdf,mu,sigma,tail,log_mode,normal_quantile)) + return false; +//--- calculate differences + if(tail==true) + { + //--- lower tail mode (cdf) + if(log_mode==true) + { + //--- logarithmic values + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_normal_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_normal_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 4: test generators + PrintFormat("%s: Test 4: Generators of random values",test_name); +//--- generate random values and calculate 4 moments + int random_data_count=10000; + double values_rnd[]; + if(MathRandomNormal(mu,sigma,random_data_count,values_rnd)==true) + { + //--- calculate 4 moments of generated values + double mean=MathMean(values_rnd); + double variance=MathVariance(values_rnd); + double skewness=MathSkewness(values_rnd); + double kurtosis=MathKurtosis(values_rnd); + //--- inital values + double normal_mean=0; + double normal_variance=0; + double normal_skewness=0; + double normal_kurtosis=0; + //--- calculate theoretical values and compare with generated + if(MathMomentsNormal(mu,sigma,normal_mean,normal_variance,normal_skewness,normal_kurtosis,error_code)) + { + PrintFormat("Mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",mean,mean,skewness,kurtosis); + PrintFormat("Theoretical values: mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",normal_mean,normal_variance,normal_skewness,normal_kurtosis); + PrintFormat("delta mean=%.4f, delta variance=%.4f delta skewness=%.4f delta kurtosis=%.4f",mean-normal_mean,variance-normal_variance,skewness-normal_skewness,kurtosis-normal_kurtosis); + } + else + return false; + } + else + return false; +//--- successful + PrintFormat("%s passed",test_name); + return true; + } +//+------------------------------------------------------------------+ +//| Test function for Lognormal distribution | +//+------------------------------------------------------------------+ +bool TestLognormalDistribution(string test_name,const double mu,const double sigma,const double &x_values[],const double &pdf_values[],const double &cdf_values[],precision_info &precision) + { + PrintFormat("%s started",test_name); +//--- + int N=ArraySize(x_values); + int error_code=0; +//--- arrays for calculated values + double lognormal_pdf[]; + double lognormal_cdf[]; + double lognormal_quantile[]; +//--- arrays for differences + double delta_lognormal_pdf[]; + double delta_lognormal_cdf[]; + double delta_lognormal_quantile[]; +//--- prepare arrays + ArrayResize(lognormal_pdf,N); + ArrayResize(lognormal_cdf,N); + ArrayResize(lognormal_quantile,N); + ArrayResize(delta_lognormal_pdf,N); + ArrayResize(delta_lognormal_cdf,N); + ArrayResize(delta_lognormal_quantile,N); +//--- test 1: single values + PrintFormat("%s: Test 1: Calculations for single values",test_name); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_lognormal_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_lognormal_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 2: calculations on arrays + PrintFormat("%s: Test 2: Calculations on arrays",test_name); +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityLognormal(x_values,mu,sigma,lognormal_pdf)) + return false; + if(!MathCumulativeDistributionLognormal(x_values,mu,sigma,lognormal_cdf)) + return false; + if(!MathQuantileLognormal(lognormal_cdf,mu,sigma,lognormal_quantile)) + return false; +//--- calculate differences + ArrayResize(delta_lognormal_pdf,N); + ArrayResize(delta_lognormal_cdf,N); + ArrayResize(delta_lognormal_quantile,N); + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_lognormal_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_lognormal_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 3: calculations on arrays + PrintFormat("%s: Test 3: R-like overloaded functions",test_name); +//--- parameters for R-like overloaded functions + bool tail=true; + bool log_mode=true; +//--- calculate pdf, cdf and quantiles + if(!MathProbabilityDensityLognormal(x_values,mu,sigma,log_mode,lognormal_pdf)) + return false; + if(!MathCumulativeDistributionLognormal(x_values,mu,sigma,tail,log_mode,lognormal_cdf)) + return false; + if(!MathQuantileLognormal(lognormal_cdf,mu,sigma,tail,log_mode,lognormal_quantile)) + return false; +//--- calculate differences + if(tail==true) + { + //--- lower tail mode (cdf) + if(log_mode==true) + { + //--- logarithmic values + for(int i=0;icalc_precision_pdf) + return false; + if(MathAbs(delta_lognormal_cdf[i])>calc_precision_cdf) + return false; + if(MathAbs(delta_lognormal_quantile[i])>calc_precision_quantile) + return false; + } +//--- test 4: test generators + PrintFormat("%s: Test 4: Generators of random values",test_name); +//--- generate random values and calculate 4 moments + int random_data_count=10000; + double values_rnd[]; + if(MathRandomLognormal(mu,sigma,random_data_count,values_rnd)==true) + { + //--- calculate 4 moments of generated values + double mean=MathMean(values_rnd); + double variance=MathVariance(values_rnd); + double skewness=MathSkewness(values_rnd); + double kurtosis=MathKurtosis(values_rnd); + //--- inital values + double lognormal_mean=0; + double lognormal_variance=0; + double lognormal_skewness=0; + double lognormal_kurtosis=0; + //--- calculate theoretical values and compare with generated + if(MathMomentsLognormal(mu,sigma,lognormal_mean,lognormal_variance,lognormal_skewness,lognormal_kurtosis,error_code)) + { + PrintFormat("Mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",mean,mean,skewness,kurtosis); + PrintFormat("Theoretical values: mean=%.10f, variance=%.10f skewness=%.10f kurtosis=%.10f",lognormal_mean,lognormal_variance,lognormal_skewness,lognormal_kurtosis); + PrintFormat("delta mean=%.4f, delta variance=%.4f delta skewness=%.4f delta kurtosis=%.4f",mean-lognormal_mean,variance-lognormal_variance,skewness-lognormal_skewness,kurtosis-lognormal_kurtosis); + } + else + return false; + } + else + return false; +//--- successful + PrintFormat("%s passed",test_name); + return true; + } +//+------------------------------------------------------------------+ +//| ShowPrecisionInfo | +//+------------------------------------------------------------------+ +void ShowPrecisionInfo(const string distribution,precision_info &precision) + { + PrintFormat("%s: PDF max error : %5.20e",distribution,precision.pdf_max_delta); + PrintFormat("%s: CDF max error : %5.20e",distribution,precision.cdf_max_delta); + PrintFormat("%s: Quantile max error : %5.20e",distribution,precision.quantile_max_delta); + PrintFormat("%s: PDF correct digits : %d",distribution,GetCorrectDigits(precision.pdf_max_delta)); + PrintFormat("%s: CDF correct digits : %d",distribution,GetCorrectDigits(precision.cdf_max_delta)); + PrintFormat("%s: Quantile correct digits: %d",distribution,GetCorrectDigits(precision.quantile_max_delta)); + } +//+------------------------------------------------------------------+ +//| TestDistributions | +//+------------------------------------------------------------------+ +void TestDistributions(int &tests_performed,int &tests_passed) + { + precision_info precision; + + string test_name=""; +//--- Binomial distribution + tests_performed++; + test_name="Binomial distribution test"; + if(TestBinomialDistribution(test_name,10,0.6,binomial_x_values,binomial_pdf_values,binomial_cdf_values,precision)) + { + tests_passed++; + ShowPrecisionInfo(test_name,precision); + } + else + PrintFormat("%s failed",test_name); + +//--- Beta distribution + tests_performed++; + test_name="Beta distribution test"; + if(TestBetaDistribution(test_name,2.0,4.0,beta_x_values,beta_pdf_values,beta_cdf_values,precision)) + { + tests_passed++; + ShowPrecisionInfo(test_name,precision); + } + else + PrintFormat("%s failed",test_name); + +//--- Gamma distribution + tests_performed++; + test_name="Gamma distribution test"; + if(TestGammaDistribution(test_name,1.0,1.0,gamma_x_values,gamma_pdf_values,gamma_cdf_values,precision)) + { + tests_passed++; + ShowPrecisionInfo(test_name,precision); + } + else + PrintFormat("%s failed",test_name); + +//--- Cauchy distribution + tests_performed++; + test_name="Cauchy distribution test"; + if(TestCauchyDistribution(test_name,2.0,1.0,cauchy_x_values,cauchy_pdf_values,cauchy_cdf_values,precision)) + { + tests_passed++; + ShowPrecisionInfo(test_name,precision); + } + else + PrintFormat("%s failed",test_name); + +//--- Exponential distribution + tests_performed++; + test_name="Exponential distribution test"; + if(TestExponentialDistribution(test_name,2.0,exponential_x_values,exponential_pdf_values,exponential_cdf_values,precision)) + { + tests_passed++; + ShowPrecisionInfo(test_name,precision); + } + else + PrintFormat("%s failed",test_name); + +//--- Uniform distribution + tests_performed++; + test_name="Uniform distribution test"; + if(TestUnifromDistribution(test_name,0,10.0,uniform_x_values,uniform_pdf_values,uniform_cdf_values,precision)) + { + tests_passed++; + ShowPrecisionInfo(test_name,precision); + } + else + PrintFormat("%s failed",test_name); + +//--- Geometric distribution + tests_performed++; + test_name="Geometric distribution test"; + if(TestGeometricDistribution(test_name,0.3,geometric_x_values,geometric_pdf_values,geometric_cdf_values,precision)) + { + tests_passed++; + ShowPrecisionInfo(test_name,precision); + } + else + PrintFormat("%s failed",test_name); + +//--- Hypergeometric distribution + tests_performed++; + test_name="Hypergeometric distribution test"; + if(TestHypergeometricDistribution(test_name,30,11,12,hypergeometric_x_values,hypergeometric_pdf_values,hypergeometric_cdf_values,precision)) + { + tests_passed++; + ShowPrecisionInfo(test_name,precision); + } + else + PrintFormat("%s failed",test_name); + +//--- Logistic distribution + tests_performed++; + test_name="Logistic distribution test"; + if(TestLogisticDistribution(test_name,1.0,2.0,logistic_x_values,logistic_pdf_values,logistic_cdf_values,precision)) + { + tests_passed++; + ShowPrecisionInfo(test_name,precision); + } + else + PrintFormat("%s failed",test_name); + +//--- Weibull distribution + tests_performed++; + test_name="Weibull distribution test"; + if(TestWeibullDistribution(test_name,5.0,1.0,weibull_x_values,weibull_pdf_values,weibull_cdf_values,precision)) + { + tests_passed++; + ShowPrecisionInfo(test_name,precision); + } + else + PrintFormat("%s failed",test_name); + +//--- Poisson distribution + tests_performed++; + test_name="Poisson distribution test"; + if(TestPoissonDistribution(test_name,1.0,poisson_x_values,poisson_pdf_values,poisson_cdf_values,precision)) + { + tests_passed++; + ShowPrecisionInfo(test_name,precision); + } + else + PrintFormat("%s failed",test_name); + +//--- F distribution + tests_performed++; + test_name="F distribution test"; + if(TestFDistribution(test_name,10.0,20.0,f_x_values,f_pdf_values,f_cdf_values,precision)) + { + tests_passed++; + ShowPrecisionInfo(test_name,precision); + } + else + PrintFormat("%s failed",test_name); + +//--- ChiSquare distribution + tests_performed++; + test_name="ChiSquare distribution test"; + if(TestChiSquareDistribution(test_name,2.0,chisquare_x_values,chisquare_pdf_values,chisquare_cdf_values,precision)) + { + tests_passed++; + ShowPrecisionInfo(test_name,precision); + } + else + PrintFormat("%s failed",test_name); + +//--- Noncentral ChiSquare distribution + tests_performed++; + test_name="Noncentral ChiSquare distribution test"; + if(TestNoncentralChiSquareDistribution(test_name,2.0,1.0,noncentral_chisquare_x_values,noncentral_chisquare_pdf_values,noncentral_chisquare_cdf_values,precision)) + { + tests_passed++; + ShowPrecisionInfo(test_name,precision); + } + else + PrintFormat("%s failed",test_name); + +//--- Noncentral F distribution + tests_performed++; + test_name="Noncentral F distribution test"; + if(TestNoncentralFDistribution(test_name,10.0,20.0,2.0,noncentral_f_x_values,noncentral_f_pdf_values,noncentral_f_cdf_values,precision)) + { + tests_passed++; + ShowPrecisionInfo(test_name,precision); + } + else + PrintFormat("%s failed",test_name); + +//--- Noncentral Beta Distribution + tests_performed++; + test_name="Noncentral Beta distribution test"; + if(TestNoncentralBetaDistribution(test_name,2.0,4.0,1.0,noncentral_beta_x_values,noncentral_beta_pdf_values,noncentral_beta_cdf_values,precision)) + { + tests_passed++; + ShowPrecisionInfo(test_name,precision); + } + else + PrintFormat("%s failed",test_name); + +//--- Negative Binomial Distribution + tests_performed++; + test_name="Negative Binomial distribution test"; + if(TestNegativeBinomialDistribution(test_name,2.0,0.5,negative_binomial_x_values,negative_binomial_pdf_values,negative_binomial_cdf_values,precision)) + { + tests_passed++; + ShowPrecisionInfo(test_name,precision); + } + else + PrintFormat("%s failed",test_name); + +//--- T Distribution + tests_performed++; + test_name="T distribution test"; + if(TestTDistribution(test_name,8.0,t_x_values,t_pdf_values,t_cdf_values,precision)) + { + tests_passed++; + ShowPrecisionInfo(test_name,precision); + } + else + PrintFormat("%s failed",test_name); + +//--- Noncentral T Distribution + tests_performed++; + test_name="Noncentral T distribution test"; + if(TestNoncentralTDistribution(test_name,10.0,8.0,noncentral_t_x_values,noncentral_t_pdf_values,noncentral_t_cdf_values,precision)) + { + tests_passed++; + ShowPrecisionInfo(test_name,precision); + } + else + PrintFormat("%s failed",test_name); + +//--- Normal Distribution + tests_performed++; + test_name="Normal distribution test"; + if(TestNormalDistribution(test_name,21.0,5.0,normal_x_values,normal_pdf_values,normal_cdf_values,precision)) + { + tests_passed++; + ShowPrecisionInfo(test_name,precision); + } + else + PrintFormat("%s failed",test_name); + +//--- Lognormal Distribution + tests_performed++; + test_name="Lognormal distribution test"; + if(TestLognormalDistribution(test_name,0.5,0.6,lognormal_x_values,lognormal_pdf_values,lognormal_cdf_values,precision)) + { + tests_passed++; + ShowPrecisionInfo(test_name,precision); + } + else + PrintFormat("%s failed",test_name); + + return; + } +//+------------------------------------------------------------------+ +//| UnitTests() | +//+------------------------------------------------------------------+ +void UnitTests(const string package_name) + { + PrintFormat("Unit tests for Package %s\n",package_name); +//--- initial values + int tests_performed=0; + int tests_passed=0; +//--- test distributions + TestDistributions(tests_performed,tests_passed); +//--- print statistics + PrintFormat("\n%d of %d passed",tests_passed,tests_performed); + } +//+------------------------------------------------------------------+ +//| Script program start function | +//+------------------------------------------------------------------+ +void OnStart() + { + UnitTests("Stat"); + } +//+------------------------------------------------------------------+ diff --git a/Scripts/UnitTests/Stat/TestStatBenchmark.mq5 b/Scripts/UnitTests/Stat/TestStatBenchmark.mq5 new file mode 100644 index 0000000..b57573a --- /dev/null +++ b/Scripts/UnitTests/Stat/TestStatBenchmark.mq5 @@ -0,0 +1,1590 @@ +//+------------------------------------------------------------------+ +//| TestStatBenchmark.mq5 | +//| Copyright 2016-2017, MetaQuotes Software Corp. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2016-2017, MetaQuotes Software Corp." +#property link "https://www.mql5.com" +#property version "1.00" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//+------------------------------------------------------------------+ +//| Structure for benchmark information | +//+------------------------------------------------------------------+ +struct benchmark_info + { + //--- propability density calculation times + double pdf_time_min; + double pdf_time_max; + double pdf_time_mean; + double pdf_time_median; + double pdf_time_stddev; + double pdf_time_avgdev; + //--- cumulative distribution calculation times + double cdf_time_min; + double cdf_time_max; + double cdf_time_mean; + double cdf_time_median; + double cdf_time_stddev; + double cdf_time_avgdev; + //--- quantile calculation times + double quantile_time_min; + double quantile_time_max; + double quantile_time_mean; + double quantile_time_median; + double quantile_time_stddev; + double quantile_time_avgdev; + //--- random variable calculation times + double random_time_min; + double random_time_max; + double random_time_mean; + double random_time_median; + double random_time_stddev; + double random_time_avgdev; + }; + +#define AverageCount 1000 +//+------------------------------------------------------------------+ +//| ShowBenchmarkInfo | +//+------------------------------------------------------------------+ +void ShowBenchmarkInfo(const string test_info,benchmark_info &benchmark) + { + PrintFormat("%s time (microseconds): pdf_mean=%4.2f, pdf_median=%4.2f, pdf_min=%4.2f, pdf_max=%4.2f, pdf_stddev=%4.2f, pdf_avgdev=%4.2f", + test_info,benchmark.pdf_time_mean,benchmark.pdf_time_median,benchmark.pdf_time_min,benchmark.pdf_time_max,benchmark.pdf_time_stddev,benchmark.pdf_time_avgdev); + PrintFormat("%s time (microseconds): cdf_mean=%4.2f, cdf_median=%4.2f, cdf_min=%4.2f, cdf_max=%4.2f, cdf_stddev=%4.2f, cdf_avgdev=%4.2f", + test_info,benchmark.cdf_time_mean,benchmark.cdf_time_median,benchmark.cdf_time_min,benchmark.cdf_time_max,benchmark.cdf_time_stddev,benchmark.cdf_time_avgdev); + PrintFormat("%s time (microseconds): quantile_mean=%4.2f, quantile_median=%4.2f, quantile_min=%4.2f, quantile_max=%4.2f, quantile_stddev=%4.2f, quantile_avgdev=%4.2f", + test_info,benchmark.quantile_time_mean,benchmark.quantile_time_median,benchmark.quantile_time_min,benchmark.quantile_time_max,benchmark.quantile_time_stddev,benchmark.quantile_time_avgdev); + PrintFormat("%s time (microseconds): random_mean=%4.2f, random_median=%4.2f, random_min=%4.2f, random_max=%4.2f, random_stddev=%4.2f, random_avgdev=%4.2f", + test_info,benchmark.random_time_mean,benchmark.random_time_median,benchmark.random_time_min,benchmark.random_time_max,benchmark.random_time_stddev,benchmark.random_time_avgdev); + } +//+------------------------------------------------------------------+ +//| CalculateStatisticalProperties | +//+------------------------------------------------------------------+ +void CalculateStatisticalProperties(benchmark_info &benchmark,double &pdf_times[],double &cdf_times[],double &quantile_times[],double &random_times[]) + { +//--- calculate statistical properties for calculation time: min,max,mean,median,standard and average deviations +//--- probability density + benchmark.pdf_time_min=MathMin(pdf_times); + benchmark.pdf_time_max=MathMax(pdf_times); + benchmark.pdf_time_mean=MathMean(pdf_times); + benchmark.pdf_time_median=MathMedian(pdf_times); + benchmark.pdf_time_stddev=MathStandardDeviation(pdf_times); + benchmark.pdf_time_avgdev=MathAverageDeviation(pdf_times); +//--- cumulative distribution + benchmark.cdf_time_min=MathMin(cdf_times); + benchmark.cdf_time_max=MathMax(cdf_times); + benchmark.cdf_time_mean=MathMean(cdf_times); + benchmark.cdf_time_median=MathMedian(cdf_times); + benchmark.cdf_time_stddev=MathStandardDeviation(cdf_times); + benchmark.cdf_time_avgdev=MathAverageDeviation(cdf_times); +//--- quantile + benchmark.quantile_time_min=MathMin(quantile_times); + benchmark.quantile_time_max=MathMax(quantile_times); + benchmark.quantile_time_mean=MathMean(quantile_times); + benchmark.quantile_time_median=MathMedian(quantile_times); + benchmark.quantile_time_stddev=MathStandardDeviation(quantile_times); + benchmark.quantile_time_avgdev=MathAverageDeviation(quantile_times); +//--- random values + benchmark.random_time_min=MathMin(random_times); + benchmark.random_time_max=MathMax(random_times); + benchmark.random_time_mean=MathMean(random_times); + benchmark.random_time_median=MathMedian(random_times); + benchmark.random_time_stddev=MathStandardDeviation(random_times); + benchmark.random_time_avgdev=MathAverageDeviation(random_times); + return; + } +//+------------------------------------------------------------------+ +//| CalculateBenchmarkBinomial | +//+------------------------------------------------------------------+ +bool CalculateBenchmarkBinomial(benchmark_info &benchmark_binomial,int &tests_performed,int &tests_passed) + { + tests_performed++; +//--- Binomial distribution parameters + const int N=50; + const double probability=0.1; +//--- prepare x values + double x_values[]; + ArrayResize(x_values,N); + for(int i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//--- PDF and CDF values calculated with Wolfram Alpha (30 digits) +//--- http://www.wolframalpha.com/input/?i=N%5BPDF%5BBetaDistribution%5B2,4%5D,0.5%5D,30%5D +const double Wolfram_Beta_PDF = 1.25000000000000000000000000000; // N[PDF[BetaDistribution[2,4],0.5],30] +const double Wolfram_Beta_CDF = 0.812500000000000000000000000000; // N[CDF[BetaDistribution[2,4],0.5],30] +const double Wolfram_Binomial_PDF = 0.178863050569879740960000000000; // N[PDF[BinomialDistribution[20,0.3],5],30] +const double Wolfram_Binomial_CDF = 0.416370829447481383720000000000; // N[CDF[BinomialDistribution[20,0.3],5],30] +const double Wolfram_Cauchy_PDF = 0.0783532027529330883785273911988; // N[PDF[CauchyDistribution[2,1],0.25],30] +const double Wolfram_Cauchy_CDF = 0.165249340538567909638346176210; // N[CDF[CauchyDistribution[2,1],0.25],30] +const double Wolfram_ChiSquare_PDF = 0.389400391535702434122585133489; // N[PDF[ChiSquareDistribution[2],0.5],30] +const double Wolfram_ChiSquare_CDF = 0.221199216928595131754829733022; // N[CDF[ChiSquareDistribution[2],0.5],30] +const double Wolfram_Exponential_PDF = 0.441248451292297701432446071615; // N[PDF[ExponentialDistribution[1/2],0.25],30] +const double Wolfram_Exponential_CDF = 0.117503097415404597135107856771; // N[CDF[ExponentialDistribution[1/2],0.25],30] +const double Wolfram_F_PDF = 0.702331961591220850480109739369; // N[PDF[FRatioDistribution[2,4],0.25],30] +const double Wolfram_F_CDF = 0.209876543209876543209876543210; // N[CDF[FRatioDistribution[2,4],0.25],30] +const double Wolfram_Gamma_PDF = 0.606530659712633423603799534991; // N[PDF[GammaDistribution[1,1],0.5],30] +const double Wolfram_Gamma_CDF = 0.393469340287366576396200465009; // N[CDF[GammaDistribution[1,1],0.5],30] +const double Wolfram_Geometric_PDF = 0.0504210000000000000000000000000; // N[PDF[GeometricDistribution[0.3],5],30] +const double Wolfram_Geometric_CDF = 0.882351000000000000000000000000; // N[CDF[GeometricDistribution[0.3],5],30] +const double Wolfram_Hypergeometric_PDF = 0.0366753989045010716837342224339; // N[PDF[HypergeometricDistribution[9,8,20],6],30] +const double Wolfram_Hypergeometric_CDF = 0.996784948797332698261490831150; // N[CDF[HypergeometricDistribution[9,8,20],6],30] +const double Wolfram_Logistic_PDF = 0.235003712201594489069302695021; // N[PDF[LogisticDistribution[1,1],0.5],30] +const double Wolfram_Logistic_CDF = 0.377540668798145435361099434254; // N[CDF[LogisticDistribution[1,1],0.5],30] +const double Wolfram_Lognormal_PDF = 2.47498055546993572014793467512E-7; // N[PDF[LognormalDistribution[10,2],0.5],30] +const double Wolfram_Lognormal_CDF = 4.48174235017131858935036726113E-8; // N[CDF[LognormalDistribution[10,2],0.5],30] +const double Wolfram_NegativeBinomial_PDF = 0.0468750000000000000000000000000; // N[PDF[NegativeBinomialDistribution[2,0.5],5],30] +const double Wolfram_NegativeBinomial_CDF = 0.937500000000000000000000000000; // N[CDF[NegativeBinomialDistribution[2,0.5],5],30] +const double Wolfram_NoncentralBeta_PDF = 1.83531575828435897166952478333; // N[PDF[NoncentralBetaDistribution[2,4,1],0.25],30] +const double Wolfram_NoncentralBeta_CDF = 0.279804451879309969773066407543; // N[CDF[NoncentralBetaDistribution[2,4,1],0.25],30] +const double Wolfram_NoncentralChiSquare_PDF = 0.266641691212769080163425079921; // N[PDF[NoncentralChiSquareDistribution[2,1],0.5],30] +const double Wolfram_NoncentralChiSquare_CDF = 0.142365913869366361026153686445; // N[CDF[NoncentralChiSquareDistribution[2,1],0.5],30] +const double Wolfram_NoncentralF_PDF = 0.354683475208693741397782642610; // N[PDF[NoncentralFRatioDistribution[2,4,2],0.25],30] +const double Wolfram_NoncentralF_CDF = 0.0907943467375269920219944143035; // N[CDF[NoncentralFRatioDistribution[2,4,2],0.25],30] +const double Wolfram_Normal_PDF = 0.0000133655982673381195940786008171; // N[PDF[NormalDistribution[21,5],0.15],30] +const double Wolfram_Normal_CDF = 0.0000152299819479778795518408747262; // N[CDF[NormalDistribution[21,5],0.15],30] +const double Wolfram_Poisson_PDF = 2.81323432020839550168137707324E-13; // N[PDF[PoissonDistribution[1],15],30] +const double Wolfram_Poisson_CDF = 0.99999999999998132236536831934; // N[CDF[PoissonDistribution[1],15],30] +const double Wolfram_Uniform_PDF = 0.00400000000000000000000000000000; // N[PDF[UniformDistribution[0,250],0.125],30] +const double Wolfram_Uniform_CDF = 0.000500000000000000000000000000000; // N[CDF[UniformDistribution[0,250],0.125],30] +const double Wolfram_Weibull_PDF = 0.0195121858238667121530217146408; // N[PDF[WeibullDistribution[5,1],0.25],30] +const double Wolfram_Weibull_CDF = 0.000976085818024337765288210389671; // N[CDF[WeibullDistribution[5,1],0.25],30] +const double Wolfram_T_PDF = 0.319904796224811454367412653512; // N[PDF[TDistribution[4],0.51234567890123456],30] +const double Wolfram_T_CDF = 0.6822990443550955053632292600646; // N[CDF[TDistribution[4],0.51234567890123456],30] +const double Wolfram_NoncentralT_PDF = 4.06507868645014429884902547978E-14; // N[PDF[Noncentral T Distribution[10,8],0.25],30] +const double Wolfram_NoncentralT_CDF = 4.81698E-15; // N[CDF[Noncentral T Distribution[10,8],0.25],30] + +//+------------------------------------------------------------------+ +//| GetCorrectDigits | +//+------------------------------------------------------------------+ +int GetCorrectDigits(const double delta) + { + double d=MathAbs(delta); +//--- check if delta to small + if(d<10E-30) + return(30); +//--- check if delta is large + if(d>=1.0) + return(0); + int correct_digits=0; + while(MathAbs(d)<1.0) + { + d=d*10; + correct_digits++; + } +//--- + return(correct_digits-1); + } +//+------------------------------------------------------------------+ +//| TestPrecision | +//+------------------------------------------------------------------+ +void TestPrecision(const string comment,const double pdf,const double cdf,const double pdf_calculated,const double cdf_calculated) + { + double delta_pdf=pdf-pdf_calculated; + double delta_cdf=cdf-cdf_calculated; +//--- print results + Print("Testing precision for distribution:",comment); +//---- print results + PrintFormat("Distribution: %s, Wolfram PDF=%6.30f, PDF_calculated=%6.30f, deltaPDF=%6.30f",comment,pdf,pdf_calculated,delta_pdf); + PrintFormat("Distribution: %s, Wolfram CDF=%6.30f, CDF_calculated=%6.30f, deltaCDF=%6.30f",comment,cdf,cdf_calculated,delta_cdf); +//--- print correct digits + PrintFormat("Distribution: %s PDF correct digits=%d",comment,GetCorrectDigits(delta_pdf)); + PrintFormat("Distribution: %s CDF correct digits=%d",comment,GetCorrectDigits(delta_cdf)); + Print(""); + return; + } +//+------------------------------------------------------------------+ +//| Script program start function | +//+------------------------------------------------------------------+ +void OnStart() + { + int error_code=0; +//--- Beta distribution parameters + double a=2.0; + double b=4.0; + double x=0.5; + double d_beta = MathProbabilityDensityBeta(x, a, b,error_code); + double p_beta = MathCumulativeDistributionBeta(x, a, b,error_code); + TestPrecision("Beta",Wolfram_Beta_PDF,Wolfram_Beta_CDF,d_beta,p_beta); + +//--- Binomial distribution parameters + x=5; + double n=20; + double prob=0.3; + double d_binomial = MathProbabilityDensityBinomial(x,n,prob,error_code); + double p_binomial = MathCumulativeDistributionBinomial(x,n,prob,error_code); + TestPrecision("Binomial",Wolfram_Binomial_PDF,Wolfram_Binomial_CDF,d_binomial,p_binomial); + +//--- Cauchy distribution parameters + x=0.25; + a=2.0; //mean + b=1.0; //scale + double d_cauchy = MathProbabilityDensityCauchy(x,a,b,error_code); + double p_cauchy = MathCumulativeDistributionCauchy(x,a,b,error_code); + TestPrecision("Cauchy",Wolfram_Cauchy_PDF,Wolfram_Cauchy_CDF,d_cauchy,p_cauchy); + +//--- ChiSquare distribution parameters + double nu=2; + x=0.5; + double d_chisquare = MathProbabilityDensityChiSquare(x,nu,error_code); + double p_chisquare = MathCumulativeDistributionChiSquare(x,nu,error_code); + TestPrecision("ChiSquare",Wolfram_ChiSquare_PDF,Wolfram_ChiSquare_CDF,d_chisquare,p_chisquare); + +//--- Exponential distribution parameters + x=0.25; + double mu=2.0; // scale + double d_exp = MathProbabilityDensityExponential(x,mu,error_code); + double p_exp = MathCumulativeDistributionExponential(x,mu,error_code); + TestPrecision("Exponential",Wolfram_Exponential_PDF,Wolfram_Exponential_CDF,d_exp,p_exp); + +//--- F distribution parameters + x=0.25; + int nu1=2; + int nu2=4; + double d_F = MathProbabilityDensityF(x,nu1,nu2,error_code); + double p_F = MathCumulativeDistributionF(x,nu1,nu2,error_code); + TestPrecision("F",Wolfram_F_PDF,Wolfram_F_CDF,d_F,p_F); + +//--- Gamma distribution parameters + x=0.5; + a=1.0; // shape + b=1.0; // scale + double d_gamma = MathProbabilityDensityGamma(x,a,b,error_code); + double p_gamma = MathCumulativeDistributionGamma(x,a,b,error_code); + TestPrecision("Gamma",Wolfram_Gamma_PDF,Wolfram_Gamma_CDF,d_gamma,p_gamma); + +//--- Geometric distribution parameters + x=5; + prob=0.3; + double d_geometric = MathProbabilityDensityGeometric(x,prob,error_code); + double p_geometric = MathCumulativeDistributionGeometric(x,prob,error_code); + TestPrecision("Geometric",Wolfram_Geometric_PDF,Wolfram_Geometric_CDF,d_geometric,p_geometric); + +//--- Hypergeometric distribution parameters + x=6; + double m=20; + double k=8; + n=9; + double d_hypergeometric = MathProbabilityDensityHypergeometric(x,m,k,n,error_code); + double p_hypergeometric = MathCumulativeDistributionHypergeometric(x,m,k,n,error_code); + TestPrecision("Hypergeometric",Wolfram_Hypergeometric_PDF,Wolfram_Hypergeometric_CDF,d_hypergeometric,p_hypergeometric); + +//--- Logistic distribution parameters + x=0.5; + mu=1.0; // mean + double sigma=1.0; // scale + double d_logistic = MathProbabilityDensityLogistic(x,mu,sigma,error_code); + double p_logistic = MathCumulativeDistributionLogistic(x,mu,sigma,error_code); + TestPrecision("Logistic",Wolfram_Logistic_PDF,Wolfram_Logistic_CDF,d_logistic,p_logistic); + +//--- Lognormal distribution parameters + x=0.5; + mu=10.0; + sigma=2.0; + double d_lognormal = MathProbabilityDensityLognormal(x,mu,sigma,error_code); + double p_lognormal = MathCumulativeDistributionLognormal(x,mu,sigma,error_code); + TestPrecision("Lognormal",Wolfram_Lognormal_PDF,Wolfram_Lognormal_CDF,d_lognormal,p_lognormal); + +//--- Negative Binomial distribution parameters + x=5.0; + double r=2.0; + prob=0.5; + double d_negbinomial = MathProbabilityDensityNegativeBinomial(x,r,prob,error_code); + double p_negbinomial = MathCumulativeDistributionNegativeBinomial(x,r,prob,error_code); + TestPrecision("NegativeBinomial",Wolfram_NegativeBinomial_PDF,Wolfram_NegativeBinomial_CDF,d_negbinomial,p_negbinomial); + +//--- Noncentral Beta distribution parameters + x=0.25; + a=2.0; + b=4.0; + double lambda=1; + double d_noncentralbeta = MathProbabilityDensityNoncentralBeta(x,a,b,lambda,error_code); + double p_noncentralbeta = MathCumulativeDistributionNoncentralBeta(x,a,b,lambda,error_code); + TestPrecision("NoncentralBeta",Wolfram_NoncentralBeta_PDF,Wolfram_NoncentralBeta_CDF,d_noncentralbeta,p_noncentralbeta); + +//--- Noncentral ChiSquare distribution parameters + x=0.5; + nu=2.0; + sigma=1.0; + double d_nchisquare = MathProbabilityDensityNoncentralChiSquare(x,nu,sigma,error_code); + double p_nchisquare = MathCumulativeDistributionNoncentralChiSquare(x,nu,sigma,error_code); + TestPrecision("NoncentralChiSquare",Wolfram_NoncentralChiSquare_PDF,Wolfram_NoncentralChiSquare_CDF,d_nchisquare,p_nchisquare); + +//--- Noncentral F distribution parameters + x=0.25; + nu1=2.0; + nu2=4.0; + sigma=2.0; + double d_noncentralF = MathProbabilityDensityNoncentralF(x,nu1,nu2,sigma,error_code); + double p_noncentralF = MathCumulativeDistributionNoncentralF(x,nu1,nu2,sigma,error_code); + TestPrecision("NoncentralF",Wolfram_NoncentralF_PDF,Wolfram_NoncentralF_CDF,d_noncentralF,p_noncentralF); + +//--- Normal distribution parameters + x=0.15; + mu=21.0; + sigma=5.0; + double d_normal = MathProbabilityDensityNormal(x, mu, sigma,error_code); + double p_normal = MathCumulativeDistributionNormal(x, mu, sigma,error_code); + TestPrecision("Normal",Wolfram_Normal_PDF,Wolfram_Normal_CDF,d_normal,p_normal); + +//--- Poisson distribution parameters + x=15; + lambda=1.0; + double d_poisson = MathProbabilityDensityPoisson(x,lambda,error_code); + double p_poisson = MathCumulativeDistributionPoisson(x,lambda,error_code); + TestPrecision("Poisson",Wolfram_Poisson_PDF,Wolfram_Poisson_CDF,d_poisson,p_poisson); + +//--- Uniform distribution parameters + x=0.125; + a=0.0; // lower + b=250.0; // upper + double d_uniform = MathProbabilityDensityUniform(x,a,b,error_code); + double p_uniform = MathCumulativeDistributionUniform(x,a,b,error_code); + TestPrecision("Uniform",Wolfram_Uniform_PDF,Wolfram_Uniform_CDF,d_uniform,p_uniform); + +//--- Weibull distribution parameters + x=0.25; + a=5.0; // shape + b=1.0; // scale + double d_weibull = MathProbabilityDensityWeibull(x,a,b,error_code); + double p_weibull = MathCumulativeDistributionWeibull(x,a,b,error_code); + TestPrecision("Weibull",Wolfram_Weibull_PDF,Wolfram_Weibull_CDF,d_weibull,p_weibull); + +//--- T distribution parameters + x=0.51234567890123456; + nu=4.0; + double d_T = MathProbabilityDensityT(x,nu,error_code); + double p_T = MathCumulativeDistributionT(x,nu,error_code); + TestPrecision("T",Wolfram_T_PDF,Wolfram_T_CDF,d_T,p_T); + +//--- Noncentral T distribution parameters + x=0.25; + nu=10.0; + double delta=8.0; + double d_NT = MathProbabilityDensityNoncentralT(x,nu,delta,error_code); + double p_NT = MathCumulativeDistributionNoncentralT(x,nu,delta,error_code); + TestPrecision("NoncentralT",Wolfram_NoncentralT_PDF,Wolfram_NoncentralT_CDF,d_NT,p_NT); + } +//+------------------------------------------------------------------+