From 62a14829235c1a0174df2ce4fa93b8a4c1888d0c Mon Sep 17 00:00:00 2001 From: Nkondog Anselme Date: Mon, 15 Nov 2021 02:36:56 +0100 Subject: [PATCH] fix --- .vscode/settings.json | 5 + Experts/Advisors/ExpertMACD.ex5 | Bin 141300 -> 0 bytes Experts/Advisors/ExpertMACD.mq5 | 168 - Experts/Advisors/ExpertMAMA.ex5 | Bin 150820 -> 0 bytes Experts/Advisors/ExpertMAMA.mq5 | 175 - Experts/Advisors/ExpertMAPSAR.ex5 | Bin 147032 -> 0 bytes Experts/Advisors/ExpertMAPSAR.mq5 | 171 - .../Advisors/ExpertMAPSARSizeOptimized.ex5 | Bin 151232 -> 0 bytes .../Advisors/ExpertMAPSARSizeOptimized.mq5 | 176 - .../Examples/ChartInChart/ChartInChart.ex5 | Bin 19684 -> 0 bytes .../Examples/ChartInChart/ChartInChart.mq5 | 353 - Experts/Examples/Controls/Controls.ex5 | Bin 178698 -> 0 bytes Experts/Examples/Controls/Controls.mq5 | 45 - Experts/Examples/Controls/ControlsDialog.mqh | 427 - .../Correlation Matrix 3D.ex5 | Bin 95730 -> 0 bytes .../Correlation Matrix 3D.mq5 | Bin 77290 -> 0 bytes .../Correlation Matrix 3D.mqproj | Bin 8312 -> 0 bytes Experts/Examples/MACD/MACD Sample.ex5 | Bin 48120 -> 0 bytes Experts/Examples/MACD/MACD Sample.mq5 | 451 - .../Examples/Math 3D Morpher/Functions.mqh | 372 - .../Math 3D Morpher/Math 3D Morpher.ex5 | Bin 91672 -> 0 bytes .../Math 3D Morpher/Math 3D Morpher.mq5 | Bin 35786 -> 0 bytes .../Math 3D Morpher/Math 3D Morpher.mqproj | Bin 16052 -> 0 bytes .../Math 3D Morpher/Textures/checker.bmp | Bin 196662 -> 0 bytes Experts/Examples/Math 3D/Functions.mqh | Bin 16008 -> 0 bytes Experts/Examples/Math 3D/Math 3D.ex5 | Bin 14800 -> 0 bytes Experts/Examples/Math 3D/Math 3D.ico | Bin 16958 -> 0 bytes Experts/Examples/Math 3D/Math 3D.mq5 | Bin 6986 -> 0 bytes Experts/Examples/Math 3D/Math 3D.mqproj | Bin 6052 -> 0 bytes Experts/Examples/Math 3D/Sets/Chomolungma.set | Bin 684 -> 0 bytes .../Examples/Math 3D/Sets/ClimberDream.set | Bin 696 -> 0 bytes Experts/Examples/Math 3D/Sets/DoubleScrew.set | Bin 684 -> 0 bytes Experts/Examples/Math 3D/Sets/Granite.set | Bin 684 -> 0 bytes Experts/Examples/Math 3D/Sets/Hedgehog.set | Bin 692 -> 0 bytes Experts/Examples/Math 3D/Sets/Hill.set | Bin 688 -> 0 bytes Experts/Examples/Math 3D/Sets/Josephine.set | Bin 688 -> 0 bytes .../Math 3D/Sets/MultyExtremalScrew.set | Bin 684 -> 0 bytes Experts/Examples/Math 3D/Sets/Screw.set | Bin 684 -> 0 bytes Experts/Examples/Math 3D/Sets/Sink.set | Bin 686 -> 0 bytes Experts/Examples/Math 3D/Sets/Skin.set | Bin 686 -> 0 bytes Experts/Examples/Math 3D/Sets/Trapfall.set | Bin 686 -> 0 bytes .../Moving Average/Moving Average.ex5 | Bin 36848 -> 0 bytes .../Moving Average/Moving Average.mq5 | 233 - Include/A_EntriesManagement.mqh | Bin 19010 -> 0 bytes Include/A_HistoryChecker.mqh | Bin 4692 -> 0 bytes Include/A_LotSizeCal.mqh | 62 - Include/A_Parameters.mqh | 213 - Include/A_PositionsManager.mqh | 123 - Include/A_TradeManager.mqh | 23 - Include/A_TradingHour.mqh | 27 - 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 | 4846 ---- Include/Canvas/Canvas3D.mqh | Bin 34652 -> 0 bytes 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/DX/DXBox.mqh | 77 - Include/Canvas/DX/DXBuffers.mqh | 92 - Include/Canvas/DX/DXData.mqh | Bin 4048 -> 0 bytes Include/Canvas/DX/DXDispatcher.mqh | 373 - Include/Canvas/DX/DXHandle.mqh | Bin 8568 -> 0 bytes Include/Canvas/DX/DXInput.mqh | Bin 4968 -> 0 bytes Include/Canvas/DX/DXMath.mqh | 3352 --- Include/Canvas/DX/DXMesh.mqh | 375 - Include/Canvas/DX/DXObject.mqh | Bin 1744 -> 0 bytes Include/Canvas/DX/DXObjectBase.mqh | Bin 2106 -> 0 bytes Include/Canvas/DX/DXShader.mqh | Bin 16984 -> 0 bytes Include/Canvas/DX/DXSurface.mqh | 162 - Include/Canvas/DX/DXTexture.mqh | Bin 6904 -> 0 bytes Include/Canvas/DX/DXUtils.mqh | 942 - .../Canvas/DX/Shaders/DefaultShaderPixel.hlsl | 71 - .../DX/Shaders/DefaultShaderVertex.hlsl | 72 - Include/Canvas/FlameCanvas.mqh | 751 - Include/ChartObjects/ChartObject.mqh | 1000 - Include/ChartObjects/ChartObjectPanel.mqh | 205 - Include/ChartObjects/ChartObjectSubChart.mqh | 398 - Include/ChartObjects/ChartObjectsArrows.mqh | 479 - .../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 | 895 - 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 | 188 - 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 | 308 - Include/Controls/WndContainer.mqh | 473 - Include/Controls/WndObj.mqh | 262 - Include/Controls/res/CheckBoxOff.bmp | Bin 576 -> 0 bytes Include/Controls/res/CheckBoxOn.bmp | Bin 576 -> 0 bytes Include/Controls/res/Close.bmp | Bin 1080 -> 0 bytes Include/Controls/res/DateDropOff.bmp | Bin 2104 -> 0 bytes Include/Controls/res/DateDropOn.bmp | Bin 2104 -> 0 bytes Include/Controls/res/Down.bmp | Bin 824 -> 0 bytes Include/Controls/res/DownTransp.bmp | Bin 1080 -> 0 bytes Include/Controls/res/DropOff.bmp | Bin 1080 -> 0 bytes Include/Controls/res/DropOn.bmp | Bin 1080 -> 0 bytes Include/Controls/res/Left.bmp | Bin 824 -> 0 bytes Include/Controls/res/LeftTransp.bmp | Bin 1080 -> 0 bytes Include/Controls/res/RadioButtonOff.bmp | Bin 632 -> 0 bytes Include/Controls/res/RadioButtonOn.bmp | Bin 632 -> 0 bytes Include/Controls/res/Restore.bmp | Bin 1080 -> 0 bytes Include/Controls/res/Right.bmp | Bin 824 -> 0 bytes Include/Controls/res/RightTransp.bmp | Bin 1080 -> 0 bytes Include/Controls/res/SpinDec.bmp | Bin 568 -> 0 bytes Include/Controls/res/SpinInc.bmp | Bin 568 -> 0 bytes Include/Controls/res/ThumbHor.bmp | Bin 1144 -> 0 bytes Include/Controls/res/ThumbVert.bmp | Bin 1112 -> 0 bytes Include/Controls/res/Turn.bmp | Bin 1080 -> 0 bytes Include/Controls/res/Up.bmp | Bin 824 -> 0 bytes Include/Controls/res/UpTransp.bmp | Bin 1080 -> 0 bytes Include/E_CheckHistory.mqh | Bin 4886 -> 0 bytes Include/E_ClosePositions.mqh | 81 - Include/E_EntriesManagement.mqh | Bin 20382 -> 0 bytes Include/E_Parameters.mqh | Bin 20632 -> 0 bytes Include/E_ScanPositions.mqh | 49 - Include/E_TradeManagement.mqh | 57 - Include/Expert/Expert.mqh | Bin 122604 -> 0 bytes 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 | 157 - Include/Expert/Trailing/TrailingNone.mqh | 40 - .../Expert/Trailing/TrailingParabolicSAR.mqh | 123 - Include/ExpertBase.mqh | 380 - Include/Framework.mqh | 21 - Include/Generic/ArrayList.mqh | Bin 50304 -> 0 bytes Include/Generic/HashMap.mqh | 617 - Include/Generic/HashSet.mqh | 972 - 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 23370 -> 0 bytes Include/Generic/RedBlackTree.mqh | Bin 74814 -> 0 bytes Include/Generic/SortedMap.mqh | 341 - Include/Generic/SortedSet.mqh | 673 - 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 172800 -> 0 bytes Include/MQLTA ErrorHandling.mqh | 95 - 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 | 156 - Include/Math/Alglib/bitconvert.mqh | 531 - Include/Math/Alglib/complex.mqh | 358 - 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 | Bin 249418 -> 0 bytes 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 | 772 - Include/Math/Stat/Binomial.mqh | 874 - Include/Math/Stat/Cauchy.mqh | 539 - Include/Math/Stat/ChiSquare.mqh | 531 - Include/Math/Stat/Exponential.mqh | 520 - Include/Math/Stat/F.mqh | 563 - Include/Math/Stat/Gamma.mqh | 764 - Include/Math/Stat/Geometric.mqh | 567 - Include/Math/Stat/Hypergeometric.mqh | 754 - Include/Math/Stat/Logistic.mqh | 592 - Include/Math/Stat/Lognormal.mqh | 635 - Include/Math/Stat/Math.mqh | Bin 432856 -> 0 bytes Include/Math/Stat/NegativeBinomial.mqh | 643 - Include/Math/Stat/NoncentralBeta.mqh | 955 - Include/Math/Stat/NoncentralChiSquare.mqh | 912 - Include/Math/Stat/NoncentralF.mqh | 790 - Include/Math/Stat/NoncentralT.mqh | 1192 - Include/Math/Stat/Normal.mqh | 914 - Include/Math/Stat/Poisson.mqh | 791 - Include/Math/Stat/Stat.mqh | 27 - Include/Math/Stat/T.mqh | 654 - Include/Math/Stat/Uniform.mqh | 539 - Include/Math/Stat/Weibull.mqh | 574 - Include/MovingAverages.mqh | 317 - Include/Object.mqh | 33 - Include/OpenCL/OpenCL.mqh | 453 - Include/StdLibErr.mqh | 10 - Include/Strings/String.mqh | 377 - Include/Tools/DateTime.mqh | 581 - Include/Trade/AccountInfo.mqh | 397 - Include/Trade/DealInfo.mqh | 430 - Include/Trade/HistoryOrderInfo.mqh | 472 - Include/Trade/OrderInfo.mqh | 553 - Include/Trade/PositionInfo.mqh | 364 - Include/Trade/SymbolInfo.mqh | 789 - Include/Trade/TerminalInfo.mqh | 225 - Include/Trade/Trade.mqh | 1710 -- Include/VirtualKeys.mqh | 200 - Include/WinAPI/errhandlingapi.mqh | 28 - Include/WinAPI/fileapi.mqh | 146 - Include/WinAPI/handleapi.mqh | 21 - Include/WinAPI/libloaderapi.mqh | 47 - Include/WinAPI/memoryapi.mqh | 85 - Include/WinAPI/processenv.mqh | 27 - Include/WinAPI/processthreadsapi.mqh | 202 - Include/WinAPI/securitybaseapi.mqh | 119 - Include/WinAPI/sysinfoapi.mqh | 95 - Include/WinAPI/winapi.mqh | 21 - Include/WinAPI/winbase.mqh | 814 - Include/WinAPI/windef.mqh | 325 - Include/WinAPI/wingdi.mqh | 2080 -- Include/WinAPI/winnt.mqh | 3642 --- Include/WinAPI/winreg.mqh | 77 - Include/WinAPI/winuser.mqh | 1825 -- Include/stderror.mqh | 99 - Include/variables.mqh | 32 - 304 files changed, 5 insertions(+), 216569 deletions(-) create mode 100644 .vscode/settings.json delete mode 100644 Experts/Advisors/ExpertMACD.ex5 delete mode 100644 Experts/Advisors/ExpertMACD.mq5 delete mode 100644 Experts/Advisors/ExpertMAMA.ex5 delete mode 100644 Experts/Advisors/ExpertMAMA.mq5 delete mode 100644 Experts/Advisors/ExpertMAPSAR.ex5 delete mode 100644 Experts/Advisors/ExpertMAPSAR.mq5 delete mode 100644 Experts/Advisors/ExpertMAPSARSizeOptimized.ex5 delete mode 100644 Experts/Advisors/ExpertMAPSARSizeOptimized.mq5 delete mode 100644 Experts/Examples/ChartInChart/ChartInChart.ex5 delete mode 100644 Experts/Examples/ChartInChart/ChartInChart.mq5 delete mode 100644 Experts/Examples/Controls/Controls.ex5 delete mode 100644 Experts/Examples/Controls/Controls.mq5 delete mode 100644 Experts/Examples/Controls/ControlsDialog.mqh delete mode 100644 Experts/Examples/Correlation Matrix 3D/Correlation Matrix 3D.ex5 delete mode 100644 Experts/Examples/Correlation Matrix 3D/Correlation Matrix 3D.mq5 delete mode 100644 Experts/Examples/Correlation Matrix 3D/Correlation Matrix 3D.mqproj delete mode 100644 Experts/Examples/MACD/MACD Sample.ex5 delete mode 100644 Experts/Examples/MACD/MACD Sample.mq5 delete mode 100644 Experts/Examples/Math 3D Morpher/Functions.mqh delete mode 100644 Experts/Examples/Math 3D Morpher/Math 3D Morpher.ex5 delete mode 100644 Experts/Examples/Math 3D Morpher/Math 3D Morpher.mq5 delete mode 100644 Experts/Examples/Math 3D Morpher/Math 3D Morpher.mqproj delete mode 100644 Experts/Examples/Math 3D Morpher/Textures/checker.bmp delete mode 100644 Experts/Examples/Math 3D/Functions.mqh delete mode 100644 Experts/Examples/Math 3D/Math 3D.ex5 delete mode 100644 Experts/Examples/Math 3D/Math 3D.ico delete mode 100644 Experts/Examples/Math 3D/Math 3D.mq5 delete mode 100644 Experts/Examples/Math 3D/Math 3D.mqproj delete mode 100644 Experts/Examples/Math 3D/Sets/Chomolungma.set delete mode 100644 Experts/Examples/Math 3D/Sets/ClimberDream.set delete mode 100644 Experts/Examples/Math 3D/Sets/DoubleScrew.set delete mode 100644 Experts/Examples/Math 3D/Sets/Granite.set delete mode 100644 Experts/Examples/Math 3D/Sets/Hedgehog.set delete mode 100644 Experts/Examples/Math 3D/Sets/Hill.set delete mode 100644 Experts/Examples/Math 3D/Sets/Josephine.set delete mode 100644 Experts/Examples/Math 3D/Sets/MultyExtremalScrew.set delete mode 100644 Experts/Examples/Math 3D/Sets/Screw.set delete mode 100644 Experts/Examples/Math 3D/Sets/Sink.set delete mode 100644 Experts/Examples/Math 3D/Sets/Skin.set delete mode 100644 Experts/Examples/Math 3D/Sets/Trapfall.set delete mode 100644 Experts/Examples/Moving Average/Moving Average.ex5 delete mode 100644 Experts/Examples/Moving Average/Moving Average.mq5 delete mode 100644 Include/A_EntriesManagement.mqh delete mode 100644 Include/A_HistoryChecker.mqh delete mode 100644 Include/A_LotSizeCal.mqh delete mode 100644 Include/A_Parameters.mqh delete mode 100644 Include/A_PositionsManager.mqh delete mode 100644 Include/A_TradeManager.mqh delete mode 100644 Include/A_TradingHour.mqh delete mode 100644 Include/Arrays/Array.mqh delete mode 100644 Include/Arrays/ArrayChar.mqh delete mode 100644 Include/Arrays/ArrayDouble.mqh delete mode 100644 Include/Arrays/ArrayFloat.mqh delete mode 100644 Include/Arrays/ArrayInt.mqh delete mode 100644 Include/Arrays/ArrayLong.mqh delete mode 100644 Include/Arrays/ArrayObj.mqh delete mode 100644 Include/Arrays/ArrayShort.mqh delete mode 100644 Include/Arrays/ArrayString.mqh delete mode 100644 Include/Arrays/List.mqh delete mode 100644 Include/Arrays/Tree.mqh delete mode 100644 Include/Arrays/TreeNode.mqh delete mode 100644 Include/Canvas/Canvas.mqh delete mode 100644 Include/Canvas/Canvas3D.mqh delete mode 100644 Include/Canvas/Charts/ChartCanvas.mqh delete mode 100644 Include/Canvas/Charts/HistogramChart.mqh delete mode 100644 Include/Canvas/Charts/LineChart.mqh delete mode 100644 Include/Canvas/Charts/PieChart.mqh delete mode 100644 Include/Canvas/DX/DXBox.mqh delete mode 100644 Include/Canvas/DX/DXBuffers.mqh delete mode 100644 Include/Canvas/DX/DXData.mqh delete mode 100644 Include/Canvas/DX/DXDispatcher.mqh delete mode 100644 Include/Canvas/DX/DXHandle.mqh delete mode 100644 Include/Canvas/DX/DXInput.mqh delete mode 100644 Include/Canvas/DX/DXMath.mqh delete mode 100644 Include/Canvas/DX/DXMesh.mqh delete mode 100644 Include/Canvas/DX/DXObject.mqh delete mode 100644 Include/Canvas/DX/DXObjectBase.mqh delete mode 100644 Include/Canvas/DX/DXShader.mqh delete mode 100644 Include/Canvas/DX/DXSurface.mqh delete mode 100644 Include/Canvas/DX/DXTexture.mqh delete mode 100644 Include/Canvas/DX/DXUtils.mqh delete mode 100644 Include/Canvas/DX/Shaders/DefaultShaderPixel.hlsl delete mode 100644 Include/Canvas/DX/Shaders/DefaultShaderVertex.hlsl delete mode 100644 Include/Canvas/FlameCanvas.mqh delete mode 100644 Include/ChartObjects/ChartObject.mqh delete mode 100644 Include/ChartObjects/ChartObjectPanel.mqh delete mode 100644 Include/ChartObjects/ChartObjectSubChart.mqh delete mode 100644 Include/ChartObjects/ChartObjectsArrows.mqh delete mode 100644 Include/ChartObjects/ChartObjectsBmpControls.mqh delete mode 100644 Include/ChartObjects/ChartObjectsChannels.mqh delete mode 100644 Include/ChartObjects/ChartObjectsElliott.mqh delete mode 100644 Include/ChartObjects/ChartObjectsFibo.mqh delete mode 100644 Include/ChartObjects/ChartObjectsGann.mqh delete mode 100644 Include/ChartObjects/ChartObjectsLines.mqh delete mode 100644 Include/ChartObjects/ChartObjectsShapes.mqh delete mode 100644 Include/ChartObjects/ChartObjectsTxtControls.mqh delete mode 100644 Include/Charts/Chart.mqh delete mode 100644 Include/Controls/BmpButton.mqh delete mode 100644 Include/Controls/Button.mqh delete mode 100644 Include/Controls/CheckBox.mqh delete mode 100644 Include/Controls/CheckGroup.mqh delete mode 100644 Include/Controls/ComboBox.mqh delete mode 100644 Include/Controls/DateDropList.mqh delete mode 100644 Include/Controls/DatePicker.mqh delete mode 100644 Include/Controls/Defines.mqh delete mode 100644 Include/Controls/Dialog.mqh delete mode 100644 Include/Controls/Edit.mqh delete mode 100644 Include/Controls/Label.mqh delete mode 100644 Include/Controls/ListView.mqh delete mode 100644 Include/Controls/Panel.mqh delete mode 100644 Include/Controls/Picture.mqh delete mode 100644 Include/Controls/RadioButton.mqh delete mode 100644 Include/Controls/RadioGroup.mqh delete mode 100644 Include/Controls/Rect.mqh delete mode 100644 Include/Controls/Scrolls.mqh delete mode 100644 Include/Controls/SpinEdit.mqh delete mode 100644 Include/Controls/Wnd.mqh delete mode 100644 Include/Controls/WndClient.mqh delete mode 100644 Include/Controls/WndContainer.mqh delete mode 100644 Include/Controls/WndObj.mqh delete mode 100644 Include/Controls/res/CheckBoxOff.bmp delete mode 100644 Include/Controls/res/CheckBoxOn.bmp delete mode 100644 Include/Controls/res/Close.bmp delete mode 100644 Include/Controls/res/DateDropOff.bmp delete mode 100644 Include/Controls/res/DateDropOn.bmp delete mode 100644 Include/Controls/res/Down.bmp delete mode 100644 Include/Controls/res/DownTransp.bmp delete mode 100644 Include/Controls/res/DropOff.bmp delete mode 100644 Include/Controls/res/DropOn.bmp delete mode 100644 Include/Controls/res/Left.bmp delete mode 100644 Include/Controls/res/LeftTransp.bmp delete mode 100644 Include/Controls/res/RadioButtonOff.bmp delete mode 100644 Include/Controls/res/RadioButtonOn.bmp delete mode 100644 Include/Controls/res/Restore.bmp delete mode 100644 Include/Controls/res/Right.bmp delete mode 100644 Include/Controls/res/RightTransp.bmp delete mode 100644 Include/Controls/res/SpinDec.bmp delete mode 100644 Include/Controls/res/SpinInc.bmp delete mode 100644 Include/Controls/res/ThumbHor.bmp delete mode 100644 Include/Controls/res/ThumbVert.bmp delete mode 100644 Include/Controls/res/Turn.bmp delete mode 100644 Include/Controls/res/Up.bmp delete mode 100644 Include/Controls/res/UpTransp.bmp delete mode 100644 Include/E_CheckHistory.mqh delete mode 100644 Include/E_ClosePositions.mqh delete mode 100644 Include/E_EntriesManagement.mqh delete mode 100644 Include/E_Parameters.mqh delete mode 100644 Include/E_ScanPositions.mqh delete mode 100644 Include/E_TradeManagement.mqh delete mode 100644 Include/Expert/Expert.mqh delete mode 100644 Include/Expert/ExpertBase.mqh delete mode 100644 Include/Expert/ExpertMoney.mqh delete mode 100644 Include/Expert/ExpertSignal.mqh delete mode 100644 Include/Expert/ExpertTrade.mqh delete mode 100644 Include/Expert/ExpertTrailing.mqh delete mode 100644 Include/Expert/Money/MoneyFixedLot.mqh delete mode 100644 Include/Expert/Money/MoneyFixedMargin.mqh delete mode 100644 Include/Expert/Money/MoneyFixedRisk.mqh delete mode 100644 Include/Expert/Money/MoneyNone.mqh delete mode 100644 Include/Expert/Money/MoneySizeOptimized.mqh delete mode 100644 Include/Expert/Signal/SignalAC.mqh delete mode 100644 Include/Expert/Signal/SignalAMA.mqh delete mode 100644 Include/Expert/Signal/SignalAO.mqh delete mode 100644 Include/Expert/Signal/SignalBearsPower.mqh delete mode 100644 Include/Expert/Signal/SignalBullsPower.mqh delete mode 100644 Include/Expert/Signal/SignalCCI.mqh delete mode 100644 Include/Expert/Signal/SignalDEMA.mqh delete mode 100644 Include/Expert/Signal/SignalDeMarker.mqh delete mode 100644 Include/Expert/Signal/SignalEnvelopes.mqh delete mode 100644 Include/Expert/Signal/SignalFrAMA.mqh delete mode 100644 Include/Expert/Signal/SignalITF.mqh delete mode 100644 Include/Expert/Signal/SignalMA.mqh delete mode 100644 Include/Expert/Signal/SignalMACD.mqh delete mode 100644 Include/Expert/Signal/SignalRSI.mqh delete mode 100644 Include/Expert/Signal/SignalRVI.mqh delete mode 100644 Include/Expert/Signal/SignalSAR.mqh delete mode 100644 Include/Expert/Signal/SignalStoch.mqh delete mode 100644 Include/Expert/Signal/SignalTEMA.mqh delete mode 100644 Include/Expert/Signal/SignalTRIX.mqh delete mode 100644 Include/Expert/Signal/SignalWPR.mqh delete mode 100644 Include/Expert/Trailing/TrailingFixedPips.mqh delete mode 100644 Include/Expert/Trailing/TrailingMA.mqh delete mode 100644 Include/Expert/Trailing/TrailingNone.mqh delete mode 100644 Include/Expert/Trailing/TrailingParabolicSAR.mqh delete mode 100644 Include/ExpertBase.mqh delete mode 100644 Include/Framework.mqh delete mode 100644 Include/Generic/ArrayList.mqh delete mode 100644 Include/Generic/HashMap.mqh delete mode 100644 Include/Generic/HashSet.mqh delete mode 100644 Include/Generic/Interfaces/ICollection.mqh delete mode 100644 Include/Generic/Interfaces/IComparable.mqh delete mode 100644 Include/Generic/Interfaces/IComparer.mqh delete mode 100644 Include/Generic/Interfaces/IEqualityComparable.mqh delete mode 100644 Include/Generic/Interfaces/IEqualityComparer.mqh delete mode 100644 Include/Generic/Interfaces/IList.mqh delete mode 100644 Include/Generic/Interfaces/IMap.mqh delete mode 100644 Include/Generic/Interfaces/ISet.mqh delete mode 100644 Include/Generic/Internal/ArrayFunction.mqh delete mode 100644 Include/Generic/Internal/CompareFunction.mqh delete mode 100644 Include/Generic/Internal/DefaultComparer.mqh delete mode 100644 Include/Generic/Internal/DefaultEqualityComparer.mqh delete mode 100644 Include/Generic/Internal/EqualFunction.mqh delete mode 100644 Include/Generic/Internal/HashFunction.mqh delete mode 100644 Include/Generic/Internal/Introsort.mqh delete mode 100644 Include/Generic/Internal/PrimeGenerator.mqh delete mode 100644 Include/Generic/LinkedList.mqh delete mode 100644 Include/Generic/Queue.mqh delete mode 100644 Include/Generic/RedBlackTree.mqh delete mode 100644 Include/Generic/SortedMap.mqh delete mode 100644 Include/Generic/SortedSet.mqh delete mode 100644 Include/Generic/Stack.mqh delete mode 100644 Include/Graphics/Axis.mqh delete mode 100644 Include/Graphics/ColorGenerator.mqh delete mode 100644 Include/Graphics/Curve.mqh delete mode 100644 Include/Graphics/Graphic.mqh delete mode 100644 Include/MQLTA ErrorHandling.mqh delete mode 100644 Include/Math/Alglib/alglib.mqh delete mode 100644 Include/Math/Alglib/alglibinternal.mqh delete mode 100644 Include/Math/Alglib/alglibmisc.mqh delete mode 100644 Include/Math/Alglib/ap.mqh delete mode 100644 Include/Math/Alglib/arrayresize.mqh delete mode 100644 Include/Math/Alglib/bitconvert.mqh delete mode 100644 Include/Math/Alglib/complex.mqh delete mode 100644 Include/Math/Alglib/dataanalysis.mqh delete mode 100644 Include/Math/Alglib/delegatefunctions.mqh delete mode 100644 Include/Math/Alglib/diffequations.mqh delete mode 100644 Include/Math/Alglib/fasttransforms.mqh delete mode 100644 Include/Math/Alglib/integration.mqh delete mode 100644 Include/Math/Alglib/interpolation.mqh delete mode 100644 Include/Math/Alglib/linalg.mqh delete mode 100644 Include/Math/Alglib/matrix.mqh delete mode 100644 Include/Math/Alglib/optimization.mqh delete mode 100644 Include/Math/Alglib/solvers.mqh delete mode 100644 Include/Math/Alglib/specialfunctions.mqh delete mode 100644 Include/Math/Alglib/statistics.mqh delete mode 100644 Include/Math/Fuzzy/dictionary.mqh delete mode 100644 Include/Math/Fuzzy/fuzzyrule.mqh delete mode 100644 Include/Math/Fuzzy/fuzzyterm.mqh delete mode 100644 Include/Math/Fuzzy/fuzzyvariable.mqh delete mode 100644 Include/Math/Fuzzy/genericfuzzysystem.mqh delete mode 100644 Include/Math/Fuzzy/helper.mqh delete mode 100644 Include/Math/Fuzzy/inferencemethod.mqh delete mode 100644 Include/Math/Fuzzy/mamdanifuzzysystem.mqh delete mode 100644 Include/Math/Fuzzy/membershipfunction.mqh delete mode 100644 Include/Math/Fuzzy/ruleparser.mqh delete mode 100644 Include/Math/Fuzzy/sugenofuzzysystem.mqh delete mode 100644 Include/Math/Fuzzy/sugenovariable.mqh delete mode 100644 Include/Math/Stat/Beta.mqh delete mode 100644 Include/Math/Stat/Binomial.mqh delete mode 100644 Include/Math/Stat/Cauchy.mqh delete mode 100644 Include/Math/Stat/ChiSquare.mqh delete mode 100644 Include/Math/Stat/Exponential.mqh delete mode 100644 Include/Math/Stat/F.mqh delete mode 100644 Include/Math/Stat/Gamma.mqh delete mode 100644 Include/Math/Stat/Geometric.mqh delete mode 100644 Include/Math/Stat/Hypergeometric.mqh delete mode 100644 Include/Math/Stat/Logistic.mqh delete mode 100644 Include/Math/Stat/Lognormal.mqh delete mode 100644 Include/Math/Stat/Math.mqh delete mode 100644 Include/Math/Stat/NegativeBinomial.mqh delete mode 100644 Include/Math/Stat/NoncentralBeta.mqh delete mode 100644 Include/Math/Stat/NoncentralChiSquare.mqh delete mode 100644 Include/Math/Stat/NoncentralF.mqh delete mode 100644 Include/Math/Stat/NoncentralT.mqh delete mode 100644 Include/Math/Stat/Normal.mqh delete mode 100644 Include/Math/Stat/Poisson.mqh delete mode 100644 Include/Math/Stat/Stat.mqh delete mode 100644 Include/Math/Stat/T.mqh delete mode 100644 Include/Math/Stat/Uniform.mqh delete mode 100644 Include/Math/Stat/Weibull.mqh delete mode 100644 Include/MovingAverages.mqh delete mode 100644 Include/Object.mqh delete mode 100644 Include/OpenCL/OpenCL.mqh delete mode 100644 Include/StdLibErr.mqh delete mode 100644 Include/Strings/String.mqh delete mode 100644 Include/Tools/DateTime.mqh delete mode 100644 Include/Trade/AccountInfo.mqh delete mode 100644 Include/Trade/DealInfo.mqh delete mode 100644 Include/Trade/HistoryOrderInfo.mqh delete mode 100644 Include/Trade/OrderInfo.mqh delete mode 100644 Include/Trade/PositionInfo.mqh delete mode 100644 Include/Trade/SymbolInfo.mqh delete mode 100644 Include/Trade/TerminalInfo.mqh delete mode 100644 Include/Trade/Trade.mqh delete mode 100644 Include/VirtualKeys.mqh delete mode 100644 Include/WinAPI/errhandlingapi.mqh delete mode 100644 Include/WinAPI/fileapi.mqh delete mode 100644 Include/WinAPI/handleapi.mqh delete mode 100644 Include/WinAPI/libloaderapi.mqh delete mode 100644 Include/WinAPI/memoryapi.mqh delete mode 100644 Include/WinAPI/processenv.mqh delete mode 100644 Include/WinAPI/processthreadsapi.mqh delete mode 100644 Include/WinAPI/securitybaseapi.mqh delete mode 100644 Include/WinAPI/sysinfoapi.mqh delete mode 100644 Include/WinAPI/winapi.mqh delete mode 100644 Include/WinAPI/winbase.mqh delete mode 100644 Include/WinAPI/windef.mqh delete mode 100644 Include/WinAPI/wingdi.mqh delete mode 100644 Include/WinAPI/winnt.mqh delete mode 100644 Include/WinAPI/winreg.mqh delete mode 100644 Include/WinAPI/winuser.mqh delete mode 100644 Include/stderror.mqh delete mode 100644 Include/variables.mqh diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5031bff --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "*.mqh": "cpp" + } +} \ No newline at end of file diff --git a/Experts/Advisors/ExpertMACD.ex5 b/Experts/Advisors/ExpertMACD.ex5 deleted file mode 100644 index ff888644424f733eed611c45a4a1d525a44c8455..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 141300 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 diff --git a/Experts/Advisors/ExpertMACD.mq5 b/Experts/Advisors/ExpertMACD.mq5 deleted file mode 100644 index 1968c87..0000000 --- a/Experts/Advisors/ExpertMACD.mq5 +++ /dev/null @@ -1,168 +0,0 @@ -//+------------------------------------------------------------------+ -//| 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.ex5 b/Experts/Advisors/ExpertMAMA.ex5 deleted file mode 100644 index abdbd9d0d825beea7b37b254b7a4e9174aa160bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 150820 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

)vYzWD=R( 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 -#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.ex5 b/Experts/Advisors/ExpertMAPSAR.ex5 deleted file mode 100644 index b95db6d439b04b3333619a00751e5ecfe237f234..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 147032 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%0D22q`yWV8q&b|-X0U!X=azCmMe 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 z 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

K%MA_ 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 G&;J1NgM`!o diff --git a/Experts/Advisors/ExpertMAPSAR.mq5 b/Experts/Advisors/ExpertMAPSAR.mq5 deleted file mode 100644 index 4fb0815..0000000 --- a/Experts/Advisors/ExpertMAPSAR.mq5 +++ /dev/null @@ -1,171 +0,0 @@ -//+------------------------------------------------------------------+ -//| 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.ex5 b/Experts/Advisors/ExpertMAPSARSizeOptimized.ex5 deleted file mode 100644 index a6bc3efe42e86e8648ad741ba7864586c6a539c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 151232 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 diff --git a/Experts/Advisors/ExpertMAPSARSizeOptimized.mq5 b/Experts/Advisors/ExpertMAPSARSizeOptimized.mq5 deleted file mode 100644 index b233fd2..0000000 --- a/Experts/Advisors/ExpertMAPSARSizeOptimized.mq5 +++ /dev/null @@ -1,176 +0,0 @@ -//+------------------------------------------------------------------+ -//| 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.ex5 b/Experts/Examples/ChartInChart/ChartInChart.ex5 deleted file mode 100644 index 8a61e56ff4311bd95176f602a9988c2a35ae36e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19684 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 k448O0) - { - 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.ex5 b/Experts/Examples/Controls/Controls.ex5 deleted file mode 100644 index 00381352279477a44a2a238c169f524febdb3339..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 178698 zcmd40LzFH|ur2tNZQHhO+qP}nwr!oVZS$0kQ?~7@{_mai8+T7$#LCPa5gD;!ugp=V zm?j&r695BN5ESsA00EBvThabQHyOYHTw(w~L$h+L`47l=LOk`)z(k>hHy4J5%U=#}>eauItBYvwjv-uDj2ZB|4^gAoL3QF%A?*Sf&Q~}6 z3EkAfaK$f7PXsMzNS`u~3GTvoBt|#op9b0vbbdd3NB6BhM3vaEp!&O7%Guw1LB}#K z>5^-mLXieQtt<;cw*DaxT}BmT~S@9;|OuJ&xmtB2u&=WOCR#hjocs*YsqL^_0PZkp?h z=B{eY#(gMND9no!iptadPJT`*|S5(+JmURDIv=|pp6UwEUVv31xP*&5J| zIv9*9npO{`7Q6$)s~I+9YPNe#bP%#Gq~M#zWnT2sx{T-f^T+uw(3It#oyl5fH3sFN z-F*m=-h;Wvw0oF6uWYnp$`U1!V}I7%e+ROWD2|H%& zy5JJQ96TQpz2bYmls$&W96%EgTwWp$p0@|O!A0gd^W7osqvH4LBuACB-SUs;QLMI(7y4tUX+05LEd(k zhfp9sE;tZjg5u-ug@!gXR(NA4E{(~+k6D}$Pbo6>(nwlXFfx2XADZ<5*i}^Kz`a;q zqzzRck=9?ba$wv{Vy4DTJmywy)zBvK3RZ5npC$hmZyI_dc6qCBe>E|56@lNd{s0 zY&2Q57B-UPW=KeYq|pmla9Tpi>8-|KNK&UvtX>}hw=Q#8AxTbHK1A(bfKm)}@b452 zGMzS4u@Ci;0eEe9==6#VQ1lv!ud;h6oV2g3a}AIeJ26O_YHo~aSpb{+5?%0DNtQ%O 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

u>=l!MNTo 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

7vzbq&cw}1bC^Yb83AN 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 -#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/Math 3D Morpher/Functions.mqh b/Experts/Examples/Math 3D Morpher/Functions.mqh deleted file mode 100644 index f781078..0000000 --- a/Experts/Examples/Math 3D Morpher/Functions.mqh +++ /dev/null @@ -1,372 +0,0 @@ -//+------------------------------------------------------------------+ -//| Functions.mqh | -//| Copyright 2019,MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ - -//--- custom function y=f(x,y) -typedef double(*MathFunction)(double,double); - -//+------------------------------------------------------------------+ -//| math functions | -//+------------------------------------------------------------------+ -enum EnMathFunction - { - Peaks=0, - Chomolungma=1, - ClimberDream=2, - Granite=3, - Hedgehog=4, - Hill=5, - Josephine=6, - Screw=7, - DoubleScrew=8, - MultiExtremalScrew=9, - Sink=10, - Skin=11, - Trapfall=12, - }; -//+------------------------------------------------------------------+ -//| Names of the math functions | -//+------------------------------------------------------------------+ -const string ExtFunctionsNames[]= - { - "Peaks", - "Chomolungma", - "Climber Dream", - "Granite", - "Hedgehog", - "Hill", - "Josephine", - "Screw", - "Double Screw", - "Multi Extremal Screw", - "Sinc", - "Skin", - "Trapfall" - }; -//+------------------------------------------------------------------+ -//| Function Peaks | -//+------------------------------------------------------------------+ -double PeaksFunction(double x,double y) - { - double res = 3*MathPow((1-x),2)*MathExp(-x*x-(y+1)*(y+1))-10*(0.2*x-MathPow(x,3)-MathPow(y,5))*MathExp(-x*x-y*y)-1/3*MathExp(-(x+1)*(x+1)-y*y); -//--- - return(res); - } -//+------------------------------------------------------------------+ -//| Function Chomolungma | -//+------------------------------------------------------------------+ -double ChomolungmaFunction(double x,double y) - { - double a= MathCos(x*x)+MathCos(y*y); - double b= MathPow(MathCos(5*x*y),5); - double c=1.0/MathPow(2,b); -//--- calculate result - double res=a-c; -//--- - return(res); - } -//+------------------------------------------------------------------+ -//| Function ClimberDream | -//+------------------------------------------------------------------+ -double ClimberDreamFunction(double x,double y) - { - double a= MathSin(MathSqrt(MathAbs(x - 1.3) + MathAbs(y))); - double b= MathCos(MathSqrt(MathAbs(MathSin(x))) + MathSqrt(MathAbs(MathSin(y)))); - double f=a+b; -//--- calculate result - double res=MathPow(f,4); -//--- - return(res); - } -//+------------------------------------------------------------------+ -//| Function Granite | -//+------------------------------------------------------------------+ -double GraniteFunction(double x,double y) - { - double a= MathPow(MathSin(MathSqrt(MathAbs(x)+MathAbs(y))),2); - double b= MathPow(MathCos(MathSqrt(MathAbs(x)+MathAbs(y))),2); -//--- calculate result - double res=a*b; -//--- - return(res); - } -//+------------------------------------------------------------------+ -//| Function Hedgehog | -//+------------------------------------------------------------------+ -double HedgehogFunction(double x,double y) - { - double a1=MathSin(MathSqrt(MathAbs(x-2)+MathAbs(y))); - double a2=MathCos(MathSqrt(MathAbs(MathSin(x)))+MathSqrt(MathAbs(MathSin(y)))); -//--- calculate result - double res=a1+a2; -//--- - return(res); - } -//+------------------------------------------------------------------+ -//| Function Hill | -//+------------------------------------------------------------------+ -double HillFunction(double x,double y) - { -//--- calculate result - double res=MathExp(-x*x-y*y); -//--- - return(res); - } -//+------------------------------------------------------------------+ -//| Function Josephine | -//+------------------------------------------------------------------+ -double JosephineFunction(double x,double y) - { - double a= MathSin(MathPow(MathAbs(x)+MathAbs(y),0.5)); - double b= MathCos(MathPow(MathAbs(x),0.5)+MathPow(MathAbs(y),0.5)); -//--- calculate function - double res=a+b; -//--- - return(res); - } -//+------------------------------------------------------------------+ -//| Function Screw | -//+------------------------------------------------------------------+ -double ScrewFunction(double x,double y) - { - double a=(y==0)?0:((x*y<0)?MathArctan(x/y):MathArctan(x/y)+M_PI); - double b=x*x+y*y; - double f=MathSin(b+a); -//--- calculate result - double res=(f*f); -//--- - return(res); - } -//+------------------------------------------------------------------+ -//| Function DoubleScrew | -//+------------------------------------------------------------------+ -double DoubleScrewFunction(double x,double y) - { - double a=(y==0)?0:((x*y<0)?MathArctan(x/y):MathArctan(x/y)+M_PI); - double b=x*x+y*y; - double res1=MathCos(b/2+a*3); - res1=((res1*res1)/sqrt(b+1)-0.2); - double res2=MathCos(b/2-a*3); - res2=((res2*res2)/sqrt(b+1)-0.2); - double f=fmax(res1,res2); -//--- calculate result - double res=(f>0)?f:0; -//--- - return(res); - } -//+------------------------------------------------------------------+ -//| Function MultiExtremalScrew | -//+------------------------------------------------------------------+ -double MultiExtremalScrewFunction(double x,double y) - { - double a=(y==0)?0:((x*y<0)?MathArctan(x/y):MathArctan(x/y)+M_PI); - double b=x*x+y*y; - double res1=MathCos(b/2+a*3); - res1=((res1*res1)/sqrt(b+1)-0.2); - double res2=MathCos(b/2-a*3); - res2=((res2*res2)/sqrt(b+1)-0.2); -//--- calculate function - double res=fmin(res1,res2); -//--- - return(res); - } -//+------------------------------------------------------------------+ -//| Function Sink | -//+------------------------------------------------------------------+ -double SinkFunction(double x,double y) - { - static double k=5.0; - static double p=6.0; -//--- calculate result - double res=MathSin(x*x+y*y)+k*MathExp(-p*x*x-p*y*y); -//--- - return(res); - } -//+------------------------------------------------------------------+ -//| Function Skin | -//+------------------------------------------------------------------+ -double SkinFunction(double x,double y) - { - double a1=2*x*x; - double a2=2*y*y; - double b1=MathCos(a1)-1.1; - b1=b1*b1; - double c1=MathSin(0.5*x)-1.2; - c1=c1*c1; - double d1=MathCos(a2)-1.1; - d1=d1*d1; - double e1=MathSin(0.5*y)-1.2; - e1=e1*e1; -//--- calculate result - double res=b1+c1-d1+e1; -//--- - return(res); - } -//+------------------------------------------------------------------+ -//| Function Trapfall | -//+------------------------------------------------------------------+ -double TrapfallFunction(double x,double y) - { - double a1=MathSqrt(MathAbs(MathSin(x-1.0))); - double b1=MathSqrt(MathAbs(MathSin(y+2.0))); -//--- calculate result - double res=-MathSqrt(MathAbs(MathSin(MathSin(a1+b1)))); -//--- - return(res); - } -//+------------------------------------------------------------------+ -//| GenerateFunctionData | -//+------------------------------------------------------------------+ -void GenerateFunctionData(double &data[],int &x_size,int &y_size,double x_min,double x_max,double y_min,double y_max,MathFunction function) - { - double dx = 0.1; - double dy = 0.1; -//--- - x_size = (int)((x_max - x_min)/dx) + 1; - y_size = (int)((y_max - y_min)/dy) + 1; - ArrayResize(data,x_size*y_size); -//--- - for(int j = 0; j < y_size; j++) - { - for(int i = 0; i < x_size; i++) - { - double x = x_min + i*dx; - double y = y_min + j*dy; - data[j*x_size + i] = function(x,y); - } - } - } -//+------------------------------------------------------------------+ -//| GenerateData | -//+------------------------------------------------------------------+ -void GenerateData(EnMathFunction function_id,double &data[],int &x_size,int &y_size) - { -//--- - switch(function_id) - { - case Peaks: - GenerateFunctionData(data,x_size,y_size,-3.0,+3.0,-3.0,+3.0,PeaksFunction); - break; - case Chomolungma: - GenerateFunctionData(data,x_size,y_size,-2.0,+2.0,-2.0,+2.0,ChomolungmaFunction); - break; - case ClimberDream: - GenerateFunctionData(data,x_size,y_size,-10.0,+10.0,-10.0,+10.0,ClimberDreamFunction); - break; - case Granite: - GenerateFunctionData(data,x_size,y_size,-4.0,+4.0,-4.0,+4.0,GraniteFunction); - break; - case Hedgehog: - GenerateFunctionData(data,x_size,y_size,-10.0,+10.0,-10.0,+10.0,HedgehogFunction); - break; - case Hill: - GenerateFunctionData(data,x_size,y_size,-1.5,+1.5,-1.5,+1.5,HillFunction); - break; - case Josephine: - GenerateFunctionData(data,x_size,y_size,-200.0,+200.0,-200.0,+200.0,JosephineFunction); - break; - case Screw: - GenerateFunctionData(data,x_size,y_size,-3.0,+3.0,-3.0,+3.0,ScrewFunction); - break; - case DoubleScrew: - GenerateFunctionData(data,x_size,y_size,-3.0,+3.0,-3.0,+3.0,DoubleScrewFunction); - break; - case MultiExtremalScrew: - GenerateFunctionData(data,x_size,y_size,-3.0,+3.0,-3.0,+3.0,MultiExtremalScrewFunction); - break; - case Sink: - GenerateFunctionData(data,x_size,y_size,-3.0,+3.0,-3.0,+3.0,SinkFunction); - break; - case Skin: - GenerateFunctionData(data,x_size,y_size,-5.0,+5.0,-5.0,+5.0,SkinFunction); - break; - case Trapfall: - GenerateFunctionData(data,x_size,y_size,-5.0,+5.0,-5.0,+5.0,TrapfallFunction); - break; - } - } -//+------------------------------------------------------------------+ -//| GenerateFunctionDataFixedSize | -//+------------------------------------------------------------------+ -bool GenerateFunctionDataFixedSize(int x_size,int y_size,double &data[],double x_min,double x_max,double y_min,double y_max,MathFunction function) - { - if(x_size<2 || y_size<2) - { - PrintFormat("Error in data sizes: x_size=%d,y_size=%d",x_size,y_size); - return(false); - } - double dx = (x_max - x_min)/(x_size-1); - double dy = (y_max - y_min)/(y_size-1); - ArrayResize(data,x_size*y_size); -//--- - for(int j = 0; j < y_size; j++) - { - for(int i = 0; i < x_size; i++) - { - double x = x_min + i*dx; - double y = y_min + j*dy; - data[j*x_size + i] = function(x,y); - } - } - return(true); - } -//+------------------------------------------------------------------+ -//| GenerateDataFixedSize | -//+------------------------------------------------------------------+ -bool GenerateDataFixedSize(int x_size,int y_size,EnMathFunction function_id,double &data[]) - { - if(x_size<2 || y_size<2) - { - PrintFormat("Error in data sizes: x_size=%d,y_size=%d",x_size,y_size); - return(false); - } - bool result=false; -//--- - switch(function_id) - { - case Peaks: - result=GenerateFunctionDataFixedSize(x_size,y_size,data,-3.0,+3.0,-3.0,+3.0,PeaksFunction); - break; - case Chomolungma: - result=GenerateFunctionDataFixedSize(x_size,y_size,data,-2.0,+2.0,-2.0,+2.0,ChomolungmaFunction); - break; - case ClimberDream: - result=GenerateFunctionDataFixedSize(x_size,y_size,data,-10.0,+10.0,-10.0,+10.0,ClimberDreamFunction); - break; - case Granite: - result=GenerateFunctionDataFixedSize(x_size,y_size,data,-4.0,+4.0,-4.0,+4.0,GraniteFunction); - break; - case Hedgehog: - result=GenerateFunctionDataFixedSize(x_size,y_size,data,-10.0,+10.0,-10.0,+10.0,HedgehogFunction); - break; - case Hill: - result=GenerateFunctionDataFixedSize(x_size,y_size,data,-1.5,+1.5,-1.5,+1.5,HillFunction); - break; - case Josephine: - result=GenerateFunctionDataFixedSize(x_size,y_size,data,-200.0,+200.0,-200.0,+200.0,JosephineFunction); - break; - case Screw: - result=GenerateFunctionDataFixedSize(x_size,y_size,data,-3.0,+3.0,-3.0,+3.0,ScrewFunction); - break; - case DoubleScrew: - result=GenerateFunctionDataFixedSize(x_size,y_size,data,-3.0,+3.0,-3.0,+3.0,DoubleScrewFunction); - break; - case MultiExtremalScrew: - result=GenerateFunctionDataFixedSize(x_size,y_size,data,-3.0,+3.0,-3.0,+3.0,MultiExtremalScrewFunction); - break; - case Sink: - result=GenerateFunctionDataFixedSize(x_size,y_size,data,-3.0,+3.0,-3.0,+3.0,SinkFunction); - break; - case Skin: - result=GenerateFunctionDataFixedSize(x_size,y_size,data,-5.0,+5.0,-5.0,+5.0,SkinFunction); - break; - case Trapfall: - result=GenerateFunctionDataFixedSize(x_size,y_size,data,-5.0,+5.0,-5.0,+5.0,TrapfallFunction); - break; - } -//--- - return(result); - } -//+------------------------------------------------------------------+ diff --git a/Experts/Examples/Math 3D Morpher/Math 3D Morpher.ex5 b/Experts/Examples/Math 3D Morpher/Math 3D Morpher.ex5 deleted file mode 100644 index 4e97097e0058a367c4c23aad6bbb6601543b0358..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 91672 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ⅆ%Oet~?p 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 diff --git a/Experts/Examples/Math 3D Morpher/Math 3D Morpher.mqproj b/Experts/Examples/Math 3D Morpher/Math 3D Morpher.mqproj deleted file mode 100644 index 843789d6ffac4ed1b093998b1162acbdac4f0f8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16052 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 diff --git a/Experts/Examples/Math 3D/Functions.mqh b/Experts/Examples/Math 3D/Functions.mqh deleted file mode 100644 index bdda4483ad1ff57ac435c1661fbae744f8b50af1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16008 zcmeHO+ioI95bftk`G+o=v>D_bnM2bu-yub#m~m=O>|Wde&CNn9BXf+a9xz=7c(%=c#F`Tz zy~a9b3%rA9uM_M~8~U!9TkOf))a`!Ha5aYR&+s?ED$g+b+H}nbpKGRpo$Em2M-y94 z9j$&}?y~>6ZoXgIlj2iZ31*7zFu{yNi=M3L!#1z2)?ec)p8LZBGkbEU|F$#9p1%ZE z?$;IMagK9bcd+gj)~x+$XPoU4>+HkcURmqw;By;R>-T$$mJXy0p@TkJzYbb|#&>6! zp>O9rNBgs=eTaER`2INf{#T%zV$>MphLBFl&x0PP*h@0v1})zNEw8-&@q2w6^m>Q2 zkAQh@USqdsRu=Uz0_U7$a?|PL)MB~7j4d!XY`L&)Yzg)F!Rlv>{iJNJv=wOZvu6d{ z#v1XuzeCG2XlsIfpik=HZwwuCU%2NJd?ur$CAQlH7Boj2?SrG0O|szVg~@u(y1^I{k?6iMg96HSI6jxeSgGix(1IPr)bdR1dtXE%(Y{ zkzT$xk#Bmi3i6eovi-}6$0Hdd@3FlQcb0!zh1!?bg;n)|=3>Dszb!9A7xDY*evlFODl7Sw1p3Q|^LDMwE>teTo&wlpb3)I(N<$N9D$pjVAllE{-gF zeAy_AL=D9;7m-%>3N(f(j#5XIk3?doyC9JfWh04WwBm^3kq<}q**hnBl4;~sOJxL_ zKk$T;QQMli$6CpY5&W~d-0SU(A^mJHPbabN!kjX(nQE9y2!_Ke8)iY)U>&7kQt{>cTZhpEkxcG1^~i$VTaxo>}EqkCEBY zY`Hvi(yGD8Y@Iw7C*|aI3_3*}a)J}Vee(j=FRV>quL)`k`>4RwakYm(WuEpTd-?LM zI<)?f!RixKPX7F^2de_CpUF%ij^g7L=_;%Pc!mzv*%+jV5FO~I3r_}dSW{a_dl)6 zWpE2;JXh)KVAokJ^+;vervF!i#o0C5`{l!BTBtIK_Yud4eVaDBy~Y2mjCr>$H(j;f ztnF68a??85+^*9o$nrTBV6AXJqFz$}7c!cbm8FzRqU(s?w{#Tc?xF^0kI@qK(%fZ2Kp?pWqB( z1%=ht9~R&08S?`5A6hY=xM80ITai6k#+=#hJ=hdJvl;w?G3{D>>e3t4+n zOzLI2Hcl(bNMV{hgOkTbt=P7))&YvLw#7L`He|E~fkvvu;s&+K!| z&qg&f?80XpS*A8@rP$}VaFV0wf%H>jc~!^Q>9Ph*zPG^0ri~C**O5e4R;DU=n(%0O zcsR=8IYK{`c7HtdUjzHxsd+wg&tIB^XXUz4V~l$4jatVOvECwQ zxw0Xh1%(+D@4j6iV$od5)d5&bzZ=TZo~D z)-=bYBFPn~{P6COjN*F({$!Q>vp~K>&QmT6x%B6I1HWrpCAl9+)*6W-XB|`Ihsb3V z-y1krRel+MOMF|~>U+;>rD<2N=glKb+-yOdWxAMt1df2o^c7ehF0UvV4 AOaK4? diff --git a/Experts/Examples/Math 3D/Math 3D.ex5 b/Experts/Examples/Math 3D/Math 3D.ex5 deleted file mode 100644 index e9d94a91142c95be5fa0d68d9f0943f91f616cb9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14800 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 diff --git a/Experts/Examples/Math 3D/Math 3D.mq5 b/Experts/Examples/Math 3D/Math 3D.mq5 deleted file mode 100644 index 350fb8a71301cc1f92ee2145dd5cffea3d19da1e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6986 zcmd^DYi|=*5S`CR{D+MZQV@`oqJC(RKa`N5NDT>&kw}GPnZ(2v_`&WbaVY)kZO^&m z$$fa2B)qh3WvzVg-QBroX3jkB{{7dwtjk@w-+jWJ zXN!H)`)%-O2#mx@yG+2zF?M_8ucsn*QNNAL<+6Q{9Kku2%;ePRep1OHR;zm5GiXF4Cy2fh z|F1BA1%2(m!e!rpFlGGdmOxDQO)|v*gtd_D8sTp z^MvN?6q^8F0iZ;s3V9%6iFkr6{lv`Gm(Io@4`SD)eP zqK0fi@-~>U39B!^_h-UT&#O9l`|<+XZ$KU;rc%AUCdDZukiB2%VT;#qm9awK_;K^| zSe1=Fozs|O*k{z&P~N$E{mjrMFdmsr*}bx3V)gOdtgfMLdFqf@l%_S7QNfNRU5}$; z4-v%pV+%Wq zSlZDaxk%SMQJ*Qj#nSF;4lS6ya;FPt1vDmxGFoAuN^R|l0p{APD5q1o=aF2_V!5_r za&4ZK$HgRoatPIa)(oIG$9 zPkHom;pHl9T)T>Wsds2!+Qs;xx?cwoPXkq!u{Dp#?Cw2oD~8DCRfsG?w&0_D5!vhn z=F*nih{7!JdbmQ_;heH{uDHLZ)#@;wM+j8^5YuHCX_s$p$23C`UvZIBCWzZH^3fFM zdiF4y1?sb#@hQwVJY^1`$6NS{9c1+>kvUzz7ZiA!CpVsS*`fM~vHmlS0)AIu&0SfF z)5|-}FbB7wrQe&if!{TTwTLY?iGAXFXm{@dZ;O^ExVX?u*NF0EYbom_zdqOC$^>U(b~w4Ro~65 z>hX)HeWg4|a%dQht3lrvW?G+Pn|^M6f?Udq&(l$rT`g9=?te2Q?-Vs<-+q~QPn diff --git a/Experts/Examples/Math 3D/Math 3D.mqproj b/Experts/Examples/Math 3D/Math 3D.mqproj deleted file mode 100644 index 3d82811051c49dc08520358207e247260ed97d85..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6052 zcmeI0TTc@~6vxjqpJKzaLD29ZZ&E-sHeSk`H3WNs%C=p%TW*H0uKxZrJM1h}LyU-Q z%%)X?3`E|z6JZevpFjZdNW2l zw1@OgnaLSTOnh?oS*h)vvggE(84Jk5TM|o_0-71}ckQwJox<}JE@S(GcGhW0e(9#t z!wEa)P>q}Z@-eF-J2(f5AKKmpHBI-^(z*F)v-t&~ysT3>;nd?Xu5XMh0-2@t-g@ zXH4=G?qBT!44UiEl7GljhgdxUop`G6F~qCeZsifHTC`Ght-ULWW$Q8W3UjQ_k+Vu& z_mxjoT&0l}$C?T87CbCO^AHMIX@>M0Wz2pk-$EDSJ|I>6OVdYg{j#%m zmw5AI-kW?J#95%C_HmJwyLxQ0{Tvx8omA`PTfw$Msr(`RWYA3QGb24luJiHe#O3lT z0@b@6njPn<;_D+$KCQ?W<`B=7go_Xj(MRh1ei6mr#ndJXz9uJid0ygOJtUjE*wBa~ zXoCMJO0W0t4|S}+-?inhaqnFDy-r=K&(?hnO0H!zB~<@Y~>cGkgC_hV!sZ#d-2>Rr&s1`-B@G)wG?ac-_wRa z_ddFcBUEc~-FMr1t$yE9Egs*rsyb#-UDt7|EAP^sM)9Uf{*d+oIp*ga@4C+UbI5e( z8Iw0vMQ`!bt!3N@Y+KlC4l>pF9cn*e(@pi^TkQo{RJ-avIcNl;U2yb?s{uJ)Urd@{ zrCsck@-zXMzH|Kmy0~a` diff --git a/Experts/Examples/Math 3D/Sets/Chomolungma.set b/Experts/Examples/Math 3D/Sets/Chomolungma.set deleted file mode 100644 index 09a45991e367d211dec2055272376dd3072d9413..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 684 zcma))PfNp45X9#!_#JZdqSAVmo&-VAtJq_W&l+r#&?KVbXIFo-kJO5XO33>&yE{8O z$=Bz(3f(GcqfV6?)!Z9BvL5M13-x-^1^Y^+238|EuOp+NDuEO_)Pc<9{0g*yqar_X zDucJDwu0X=?=5_;Y{56Y>tM=CT-|_LOB)^6)VxRC5_F%k0+=$@XuM#t#9 zJ#_c0txNXI{@rhV-sfPRv8KlCGp6@995{dQcrLr%Z*K{=#)v)7=M-PCBrh?SIkToq km};gT|Am>RJJCD(O@iS>XR%Lo3NnpzM&>*D^MB=k117(F_5c6? diff --git a/Experts/Examples/Math 3D/Sets/ClimberDream.set b/Experts/Examples/Math 3D/Sets/ClimberDream.set deleted file mode 100644 index 3536542206ad9fcc17dc6d2c2e5fab715cd2ebb9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 696 zcmb7?K}*9>5QOI}_#blfqEZD<(vu(vdKG)D@mYg52~8?0{&w}7eI`~s6e)e#x4Sbt zJIUwAsR~^yX{An;8r9qz-E;2gN^|vk&>7Dsm0EK;llwY43Q&nmpSb0az+IpB4dW}koteN+@m+V+^J`!KT?n!?g{mnY~VU3>Y&1-ZF z&f7yzzZhMzXZG)Q^m&_udB+-z*{5vpceo~g=jXlbdOzM0ZVeTCp5qj6u%s`smpQYh lbC_zj9=?UCjyI||%$o$mfsVeTi4KWQB0J<}8<^R@Fkk1ee9`~_ diff --git a/Experts/Examples/Math 3D/Sets/DoubleScrew.set b/Experts/Examples/Math 3D/Sets/DoubleScrew.set deleted file mode 100644 index 61c3cbc4d1a211fbca79f0e798b0cc108ee6b43c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 684 zcma))PfNp45X9#!_#JZdqEhi9NKb+w=vC~o#%B$+NoW#L@w2PH*+*){LnY+>ncbb8 zo#gBDT!n6xv{t7|jcV?V9$61`qq%xL>4N=Pr3O|bIjm-2!x%vI4GGD$V8|b3N#V>MmG+ zv^KD!ETVuqY=W~iLSdy2R%bZ!$ lB}_F_kN?6{XIs%b`b~o2NT;z+bPRG5=Zws@@@N0b{{|`%d;tIe diff --git a/Experts/Examples/Math 3D/Sets/Granite.set b/Experts/Examples/Math 3D/Sets/Granite.set deleted file mode 100644 index 3356136f09f8e15efa34e38bf530803dbf8d1a99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 684 zcma))PfNp45X9#!_#JZdqEghG^dty^Ud0}3eAZB#geDOcKfC&yeWX@AR6^dL+1=UM zNxnYMRp?epYjvvBsOH}2k@Y|~nyc57F4&({YG5^z^ExsLsuD<{eeKCy&aXfVI4bfJ zr!shZYAg61^WMVe$`*Xhy9%bP#MKR`wY1T3Ma_HEEkJiEE8u#i(roTA*MnZD?t=A4 zYeQ^^8LY{fR+gu*@(#?}dYBe^i%1I8%!k}dW~^A3oUdVbr@xN=W*z;oM)&mOH9AJ; z?V-D0ZCtWv_V0e<^DYPTj5Rf8pEA9_;lTNW$8*{BesfE>HAd`tKBxGCC3%Ut%$YS^ k!c;T$_%BR#x)r^n-y|50bQb$W#~>$h&d6*lfA+8ZZz&gi0ssI2 diff --git a/Experts/Examples/Math 3D/Sets/Hedgehog.set b/Experts/Examples/Math 3D/Sets/Hedgehog.set deleted file mode 100644 index c543a3fbd1081f7a7d24929c8f3f4ad96c0a86ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 692 zcma))K}*9>5QOI}_#blfqEbOm(vu(vdKG)D@mYg52~8?0{&w}7eI`~sR7zj=?e5IZ zPV)J2szTRFTB%c|Mm6_F_ndpW(p_(_xCHYSxCPm5$_lt%K$^`n=DO1}=q^}) zv^Lb%v4b_a)5`J|R^E}bwjQR1UZavCYvz6KB|BD}kHnX-d(vM=f3psLSfgip^BNt4 z^Y+lwFGiQ_nf<#Rect9^-mwN__9@%@9j=Mr`FSt9-jBD0TSLX3=Qzb1Ea^+^WzMYW l9HyGBhi_r3MVB}TVIt)+{OD=_bYTN2%+tbpqkq}kkKp?kf6?t}G5 zYfEm78LY{bR+gu*@}8Kr4KOYB7MT=LGaquVn6YMk;(P_WJN9?xahhs`bF)|9d5`JCblR@5ctGH2Fw l0aL@&)4wp&=~niZeq}Hm=_K}2$3#l1%$sBLEyVnvh;I&Wd|m(m diff --git a/Experts/Examples/Math 3D/Sets/Josephine.set b/Experts/Examples/Math 3D/Sets/Josephine.set deleted file mode 100644 index 8d82f2c93b358d470bbb34c2249e8beeb652b601..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 688 zcma))K}*9>5QOI}_#blfqM#nUNKb+w=vC~o#%B%MBs7Vr_}kTQ_K~#Wp;G#?Z+B;Q zc9QR}a}~N((psG=HLAHcdgMINjTY+lqzj%eDm8FAllwY43Q&nmp?&SiT<)*P7I0Mb zC!#WVd$1M!uKC%*XJku$&3_e4S&7jNS!-!y;tI@1;Fe@}DJ$T518FwTSm;5opu1q* zXlg|GH2Fw j2~*A1tR~xEg~sUGaqsA*XS6X zw}J{Mo?B{G=PGooq_sL#YE*M?^vHUk8_m`0Nf+$TDmAbg$$1?a1yu>8(7yI$F6URE1soOm ziBlQ8J+&45j(Kn4b7c#@=3NC-R^sXg)LPo;xT5Ag>K358lofEjQfW5#nCn3=RCmGp zqqQM6#0=KtOe@P%Sa}C#Z9Pm2y+tGiYUV@kB{Np6OU~D@yVGAsf3uE$SfhJ-@){kZ z^Y+l)uQo2(Gy8YH@p+endB&O=vrn1c-*Djk!Q;8?dcV0P+!`bHJfBm1!IHehT;|N0 lE@7&fdi)orI@^lg(QgtAM>>stqGOPgIA>(Gl|TDe{x>PFd;kCd diff --git a/Experts/Examples/Math 3D/Sets/Sink.set b/Experts/Examples/Math 3D/Sets/Sink.set deleted file mode 100644 index 4da1d77a9126b447ca5d524190c4a4ce72c4591b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 686 zcma))PfNp45X9#!_#JZdqSE3~dJ+UduVRliK5MW|N|T6+pI!aUJ`yV)Dk1OB?C$LB zBwwHBDs-!)ty)!TRC90i$aRFBCyq1iDssvK#PzN%X^DEE-j*9%m zsSMtZ+6sQhyl>!h1X2rP=CbucaU7LgRFnUA@b%viBLbH0Y%o&Gxdn|1KR8r{>A*XS6W zw}QpHqCnlDx!R=FFNd lVXB#W_!nlHYO)i*qvIqvPIMOgM5iFrIA>(OlRy7g{x=hhd@29{ diff --git a/Experts/Examples/Math 3D/Sets/Skin.set b/Experts/Examples/Math 3D/Sets/Skin.set deleted file mode 100644 index 4d2bf73aa7a781c4a88d52b4f57437665b072360..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 686 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

p-!fpbDRi&G`*vlGrlg_ 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 Q^zi0LZurus4R`480QIFboB#j- diff --git a/Experts/Examples/Moving Average/Moving Average.mq5 b/Experts/Examples/Moving Average/Moving Average.mq5 deleted file mode 100644 index 935780a..0000000 --- a/Experts/Examples/Moving Average/Moving Average.mq5 +++ /dev/null @@ -1,233 +0,0 @@ -//+------------------------------------------------------------------+ -//| 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; iiUj;PsPC`@-YZsM{f4?J=MKkeZL<+{pAU-Gx0tR|A@MH z75JD`CgE@TwI`mB8vI-){QN<@pGN5)=>JSQ7(|XsZLEZg*U?HuOpSwy5O*w{=XzL) zxacEmqwChO7QPoECgDuqGa+Ok+Rybp6Fuf^cR&p29_ZRIk0hpQd#G#rL+^V@YAh5E zWEoAWZYi(BYPb^H!uy-^UxP5pXr>XY2jK_twI?*0XFJlbiGGiTB&3#fMPy`VcsTQX%zyW7 z{CpO9f`7N5t5FL0n9*BgOyV32GY8Sjm6%-QX*MKd5VWrk(lyJ*x8{7hpWyyPJzi-Z zU=jTo{!Ew8BaL18E1T)QD8KIIC(=Bb?N8yV(3kF+_O>bZswOZr8TgF-F~jz zWZBs#EHI0`IDhbHF?TA>;iZT^jIuAu56;In36wr@RXxBFe)=r-yV-00xrfN3pnC~s zjjf?6>>+vPlS~H8!n}lgnR!S}G>$|M>Ph0J1+G)_9q`5Sz=@~4IrHuncGV(Oz;4Efr!!T6uCyHx}b-jFaH}2Xo?W@R_l5U=ink9TZRc^3yhoBWe&?5v zxcT0u{+oHG#hE5=<`u|PpXrax8IMAKwkhlo0ds6N`&!nQa@=H7dA4O)4S4WB!$mXp zZ{qPt~4&b{h!_Mg^&f58Pika;Z$y>TdB(C!u86w-1FHp5{&D}F$0(lZ` zk#35h&!gWpUrzhdyX2BjGr+I(&H77QD6^n^MB~4iMZ#5%d3^NQdCc_KW|+eZ4i(wD z+mAGRJozJiPxa~BZ(FhAg{ag1MDYqK*80xVBw5%ZZ6b?fi`{ss9Ea$H%)}}ObPh&Aw)IPL zG2Ux>w{?@5#sc+w($`JVo9chFvZ{~Gh%aO00!2Rho!CErQgTvi9B*Y98=RxeGeU5K zT*(GK_wZbnoawplTK-FnbSmVKVAZKmkIh=zv~0k~c6^f)K-nyoD))gZ%YR8D_eIZY zxBHEeOA572(R9#8l-(~Wl%px2yR87;jeAn@k@LZxc$;iiX#N^uQwx}EO zO{a${Q zU0(C&o_CvTByk#7mdOVDNdT_f{-=JIxWJmzX^c!%M*oh;@Cd-_0_(i9m>sZ+!m5Ek zeJ;;?5+fQ_0xJT~B9GIStlJnER>r+AYMy!5aC2QAA@M`3uHj%_ylKz1Ic9g?eq+~> z>+2_r=RCiEKOQXBBgdntxumbO_E6daxdCfQo6;|lg?$XuS)MUpm))lQ59EKnV%@Z| z%(89W*E?+6CDhhuv$8ge^h`9>#eFMBU*jmfLE8hgXWvzKI8ADRTAp>%S$TNRQX4gE zsbxZ}X6*k~dtBn$qs(DS%ec7w#VP06{BpUAQ*f)z^OlkF;~ni=ve&w7?NQRrbB5pY z?(RCd77LcIm1|UT4YYktSufWpTpVtldYQp4hh3+VXHYqQt;^xwZZzAo%Zon zYdgtu8h3VUXEw&FZaA?4PwC8At&Z_sEB4Ee^sy0Gzk@F@Zl`_NpRhYrvbN4Zt3~@k z?KWgf34QJ7M5FS#oxEdTfw4I~_k-$&vG_|n7VJEw$|bK^9_xhZM7f!tJ=qeC?<9F7 z#3~ljOxNt$ztI}O?W|6(QQ*V{XJtSD6#Tl`A4D)7vSc5gU8sCDfIV+JP3SsfRgK*c zP71M#n<`XBu)3A~2-_Fpw8E}_Pjn|$O12iU8Y$U2-B2fCslmqKGgSl$nPfPLKWlMK zr|*&^t*XrBX?Gm!(DyYDc0F13U>&4f53x#*nGrp}^s8zsud&l?e7viYNuuw$8OXIU zhkDM*le_vxyI)5cVMnuuHjSRu$xYm|PqQiX`F>d`g)Ujx{ceu#=?oOJ1_cM=4ZY_0 zvi^Lx*QVz4=~ePYae6=U`9jvh2}7)c-Jf~a8jN`vNI{H zuHg@uacYZh!5E0Q^*76Y`3;J^CCFN4hut`B`Y-cMzTY(!8k)P=*2laPE3KS=9qB*V z9%!DvQ@9f6(e`wlX?2w3Ys#FTW#;}Y`M>s>Py6&$+P%r^+n17#olNp|dbF6V6?w6D zVzJ6CIGto*$J2Zh>zsH>VuS6@vXVKAC+mm=`3bLlRF78lEhUuNF>h~)KJ6qLJa_N1 z<`Ja3>O(HH%=O7T2+Z}KW`NgRjc+Az=Z<_UXT;h%U`0M3@ruyBlhN(cky*e*^KWJQkCQX3a1 z>)QM+Dl}zD^vZJ}^H%;%6)`=yN(@KO*)lp0^;|BZpedAMc!%oVolK)#lB})UOsV?VNX_-gW%4TI;h1*&g5Q zekbN5oSrqC#?R!Z**H7JIpKBrnTPT;5A^iQN*-O(2h*IC&wYr?cN9l^DGAtniS4Ys zq(+We)}BtSR+lc1`J@ZO*S}d=uQ#idc5{JnEmIHmdz|h#s~5aw!3b*bbAbPda6aLCaTImYFu*Vhq^Np z7VHGnT5JO?-}f$MXn75J7I`gp+N5iDj-wYI#}*cWsMo=duZ&oQvMZ#LJMYDei%3Ol zs#EiyCH+zk=)&FsCeO7uf zzrJmSOwG&YPtX8#UDr3`RT`yyid4vO%lk$hO?Zw|&dbm@Z!Ek7Yc9F(<{a9#Vh?B2 z$WVAQfOi)B%w?0FbH{shQ0mU1p2c}`La6i;dEIUj2e0|r>9kjm_Ak>ryzuj3-T_Zm z*zZ?*2mCV0C#|63MQkOHyapeb>J59p$npCo^L@=V20yDn<>TwTUUO1a)t=weU8)=N zK6oD1gJ(i`okqPyqLQN*|3h_yZ*+d}K3Kwrynvru+LXu3$D_?P{jsj-v-XI@Dgir; zzETVor`UdTDD|$bTe1R!m;9{Y(C+qIt4!XJ6`Mh09_4y0@3f51{ZWov^F>4l^EjV& zM7Uh{dH?yEHTjIio9nvyw)CR&wsoFu{MyKlIUm=rFK*PP)N?HPTERH3dZCd=LLZ0* zhd%$*>V0J5ktNpzzjKdm&r1E~9JkS5&u+SOU$;n?`7f!1`LpzOo(JbX=jYRqtxvW+ zT|$G)E#0{&^p@yI(L2Y=BCUQdoYmVTj!PW15tMu8?ejGf{PSJqG*qPP%Iv>To^wxE z8_ISb>3;5&OS~J>>zpM_e)hq+eeK?u%W_Gu{%;GOwuKs_!yVjTh diff --git a/Include/A_HistoryChecker.mqh b/Include/A_HistoryChecker.mqh deleted file mode 100644 index cce9256868ab3b6bd42f61c4df16378c2c6805cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4692 zcmd5~}Y@fsS5S~t8Erz{iS;TKi>bQRkZ)b8UN4TEgc@6gw z{P*F#i|2Q^o+73$X8Y2?^=9$RjwfS{5ql)hd@a5ThoaJ#r?@*r%!5=scZoj_5&O`i z&uYe~f%6e(t5HGSZ@Wen&zQUj`ryGSY97|1;(0L()@qk*{DPQ!V2uk{n`U!WYCZ~j zy7+VFWCR|Oab%m07?zavv8;ldE5T~=awPBZ4cW+{s2<~+IJ2^YnJ#|433u%-w8w5^ zFC_jWRAvAVXYdiO%tq<(c(8qYPj%aD*N9dpY2wRx%c$PRI;G{jtVI8>- zG1MjzbXQ)66_v{4ra3oc{Ys#){$hI_~Fb(v1EfsOPO8lDG9wLG&eu`ZZ zPrW3TwB3Kj&j~;CraM4y&n!NxT-x)&A!*d_6|QL-J@QWS6%p5#kqJksOPO^pgXvYvW>n&YP1t&i{U<~cB z@?;X960WM>o*W|=<%L-(s^x3=jXhgzWfgX77%zZPq6Nkd{+-TrI^QI>ABdXSGBajj z`pQnYgzrl~OGK`dqk1&v^Jx_sXM43)z+laK!}oj_nnvu?c-7H^P3)_i=*Bksatlw! zFZCT>Lp3T#nmuYtR_w7Q`|$V@YOq=2)s#)M&+paiX1ec{s5sL^CyDrN_-x`d(}wo# zmt-359_3ye=n30-it*inzioMiy0%NahW*Ra75Bid-=(NlWHNmvT^q81jHkZyJ$p9x zU7GDw4(&_!8&kqII*R8%s`E6@_=b9EY(4wK$ zk5W}7;oPd%@~}&kI|tzH9;(R`Cr{$De9=M#n;1?WVVFkfX~D?@?`aWd$09{i9E)^G z-}Vv7Jbrf02zTsR5o!sBu&!euM&34!kYCoLOI!?!>Gik2b z4#kM5pFHtqcUrD_fq62__6cJh5w$t;i_GMIL}Wg@K-qg;ZYD^Z%@!iF6Q5ZPJI>Z6 ze6zk$Td=JoeqP?7O9$ z2YGB*laF4tsBZ(Wc&u-Df>TtBBPd5keSV)hv*^5D^Ux#v%DZ2`y(xNnKFyvF!|1~M cbSLeCQ4tj8e<7ETYIZhx);sP#cj-Uy-(t#m7ytkO diff --git a/Include/A_LotSizeCal.mqh b/Include/A_LotSizeCal.mqh deleted file mode 100644 index 79f5c11..0000000 --- a/Include/A_LotSizeCal.mqh +++ /dev/null @@ -1,62 +0,0 @@ -//+------------------------------------------------------------------+ -//| A_LotSizeCal.mqh | -//| Copyright 2021, Nkondog Anselme Venceslas | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2021, Nkondog Anselme Venceslas" -#property link "https://www.mql5.com" - -//Lot Size Calculator -void LotSizeCalculate(double SL=0) - { -//If the position size is dynamic - if(RiskDefaultSize==RISK_DEFAULT_AUTO) - { - //If the stop loss is not zero then calculate the lot size - if(SL!=0) - { - double RiskBaseAmount=0; - //TickValue is the value of the individual price increment for 1 lot of the instrument, expressed in the account currenty - TickValue=SymbolInfoDouble(Symb,SYMBOL_TRADE_TICK_VALUE); - //Define the base for the risk calculation depending on the parameter chosen - if(RiskBase==RISK_BASE_BALANCE) - RiskBaseAmount=AccountInfoDouble(ACCOUNT_BALANCE); - if(RiskBase==RISK_BASE_EQUITY) - RiskBaseAmount=AccountInfoDouble(ACCOUNT_EQUITY); - if(RiskBase==RISK_BASE_FREEMARGIN) - RiskBaseAmount=AccountInfoDouble(ACCOUNT_FREEMARGIN); - //Calculate the Position Size - Print("Multiplier ", lotMultiplier, "Before lot multiplier ", (RiskBaseAmount*MaxRiskPerTrade/100)/(SL*TickValue)); - Print("RiskBaseAmount ", RiskBaseAmount, " MaxRiskPerTrade ", MaxRiskPerTrade, "Stop loss ", SL, " TickValue ", TickValue); - - LotSize=((RiskBaseAmount*MaxRiskPerTrade/100)/(SL*TickValue)); - - Print("After lot multiplier ", LotSize, " Lot multiplier ", lotMultiplier); - if(ActiveMartingale) - { - LotSize = LotSize * lotMultiplier; - } - } - //If the stop loss is zero then the lot size is the default one - if(SL==0) - { - LotSize=DefaultLotSize; - } - } -//Normalize the Lot Size to satisfy the allowed lot increment and minimum and maximum position size - LotSize=MathFloor(LotSize/SymbolInfoDouble(Symb,SYMBOL_VOLUME_STEP))*SymbolInfoDouble(Symb,SYMBOL_VOLUME_STEP); - -//Limit the lot size in case it is greater than the maximum allowed by the user - if(LotSize>MaxLotSize) - LotSize=MaxLotSize; -//Limit the lot size in case it is greater than the maximum allowed by the broker - if(LotSize>SymbolInfoDouble(Symb,SYMBOL_VOLUME_MAX)) - LotSize=SymbolInfoDouble(Symb,SYMBOL_VOLUME_MAX); - Print("Lot ", LotSize, " Max lot ", SymbolInfoDouble(Symb,SYMBOL_VOLUME_MAX)); -//If the lot size is too small then set it to 0 and don't trade - if(LotSize < SymbolInfoDouble(Symb,SYMBOL_VOLUME_MIN)) - { - LotSize=0; - Print("Lot size too small"); - } - } diff --git a/Include/A_Parameters.mqh b/Include/A_Parameters.mqh deleted file mode 100644 index 42702da..0000000 --- a/Include/A_Parameters.mqh +++ /dev/null @@ -1,213 +0,0 @@ -//+------------------------------------------------------------------+ -//| A_Parameters.mqh | -//| Copyright 2021, Nkondog Anselme Venceslas | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2021, Nkondog Anselme Venceslas" -#property link "https://www.mql5.com" -//+------------------------------------------------------------------+ -//| defines | -//+------------------------------------------------------------------+ - -//-ENUMERATIVE VARIABLES-// -//Enumerative variables are useful to associate numerical values to easy to remember strings -//It is similar to constants but also helps if the variable is set from the input page of the EA -//The text after the // is what you see in the input paramenters when the EA loads -//It is good practice to place all the enumberative at the start - -//Enumerative for the entry signal value -enum ENUM_SIGNAL_ENTRY - { - SIGNAL_ENTRY_NEUTRAL=0, //SIGNAL ENTRY NEUTRAL - SIGNAL_ENTRY_BUY=1, //SIGNAL ENTRY BUY - SIGNAL_ENTRY_SELL=-1, //SIGNAL ENTRY SELL - }; - -//Enumerative for the exit signal value -enum ENUM_SIGNAL_EXIT - { - SIGNAL_EXIT_NEUTRAL=0, //SIGNAL EXIT NEUTRAL - SIGNAL_EXIT_BUY=1, //SIGNAL EXIT BUY - SIGNAL_EXIT_SELL=-1, //SIGNAL EXIT SELL - SIGNAL_EXIT_ALL=2, //SIGNAL EXIT ALL - }; - -//Enumerative for the allowed trading direction -enum ENUM_TRADING_ALLOW_DIRECTION - { - TRADING_ALLOW_BOTH=0, //ALLOW BOTH BUY AND SELL - TRADING_ALLOW_BUY=1, //ALLOW BUY ONLY - TRADING_ALLOW_SELL=-1, //ALLOW SELL ONLY - }; - -//Enumerative for the base used for risk calculation -enum ENUM_RISK_BASE - { - RISK_BASE_EQUITY=1, //EQUITY - RISK_BASE_BALANCE=2, //BALANCE - RISK_BASE_FREEMARGIN=3, //FREE MARGIN - }; - -//Enumerative for the default risk size -enum ENUM_RISK_DEFAULT_SIZE - { - RISK_DEFAULT_FIXED=1, //FIXED SIZE - RISK_DEFAULT_AUTO=2, //AUTOMATIC SIZE BASED ON RISK - }; - -//Enumerative for the Stop Loss mode -enum ENUM_MODE_SL - { - SL_FIXED=0, //FIXED STOP LOSS - SL_AUTO=1, //AUTOMATIC STOP LOSS - }; - -//Enumerative for the Take Profit Mode -enum ENUM_MODE_TP - { - TP_FIXED=0, //FIXED TAKE PROFIT - TP_AUTO=1, //AUTOMATIC TAKE PROFIT - }; - -//Enumerative for the stop loss calculation -enum ENUM_MODE_SL_BY - { - SL_BY_POINTS=0, //STOP LOSS PASSED IN POINTS - SL_BY_PRICE=1, //STOP LOSS PASSED BY PRICE - }; - -//Enumerative for candle type -enum ENUM_CANDLE_TYPE - { - NEUTRAL_CANDLE=0, - BEARISH_CANDLE=1, - BULLISH_CANDLE=2, - }; - -//Enumerative for price momentum -enum ENUM_PRICE_MOMENTUM - { - UP=2, - DOWN=1, - NEUTRAL=0, - }; - -struct LastTransaction - { - string time; - int type; - double profit; - } lt; - -//-INPUT PARAMETERS-// -//The input parameters are the ones that can be set by the user when launching the EA -//If you place a comment following the input variable this will be shown as description of the field - -//This is where you should include the input parameters for your entry and exit signals -input string Comment_strategy="=========="; //Entry And Exit Settings -//Add in this section the parameters for the indicators used in your entry and exit - -//General input parameters -input string Comment_0="=========="; //Risk Management Settings -input ENUM_RISK_DEFAULT_SIZE RiskDefaultSize=RISK_DEFAULT_AUTO; //Position Size Mode -input double DefaultLotSize=1; //Position Size (if fixed or if no stop loss defined) -input ENUM_RISK_BASE RiskBase=RISK_BASE_BALANCE; //Risk Base -input double MaxRiskPerTrade=0.5; //Percentage To Risk Each Trade -input double MinLotSize=0.01; //Minimum Position Size Allowed -input double MaxLotSize=100; //Maximum Position Size Allowed - -input string Comment_1="=========="; //Trading Hours Settings -input bool UseTradingHours=false; //Limit Trading Hours -input string TradingHourStart="01"; //Trading Start Hour (Broker Server Hour) -input string TradingHourEnd="23"; //Trading End Hour (Broker Server Hour) -input string TradingStartMin="30"; //Trading Start minute (Broker Server Hour) -input string TradingEndMin="00"; //Trading End minute - -input string Comment_2="=========="; //Stop Loss And Take Profit Settings -input ENUM_MODE_SL StopLossMode=SL_AUTO; //Stop Loss Mode -input int DefaultStopLoss=0; //Default Stop Loss In Points (0=No Stop Loss) -input int MinStopLoss=0; //Minimum Allowed Stop Loss In Points -input int MaxStopLoss=5000; //Maximum Allowed Stop Loss In Points -input bool AtrStopLoss=false; //Set Stop loss based on ATR -input int atr_sl_factor=3; //Multiplicator for ATR stop loss -input ENUM_MODE_TP TakeProfitMode=TP_AUTO; //Take Profit Mode -input int DefaultTakeProfit=0; //Default Take Profit In Points (0=No Take Profit) -input int MinTakeProfit=0; //Minimum Allowed Take Profit In Points -input int MaxTakeProfit=5000; //Maximum Allowed Take Profit In Points -input double TakeProfitPercent=1.0; //Take Profit percent on risk base -input double Breakevent=1.0; //Minimum Profit to breakeven -input bool ProfitRun=true; -input bool ActiveMartingale=false; - -input string Comment_3="=========="; //Trailing Stop Settings -input bool UseTrailingStop=false; //Use Trailing Stop - -input string Comment_4="=========="; //Additional Settings -input int MagicNumber=0; //Magic Number For The Orders Opened By This EA -input string OrderNote=""; //Comment For The Orders Opened By This EA -input int Slippage=5; //Slippage in points -input double MaxSpread=10.0; //Maximum Allowed Spread To Trade In Points - -input string Comment_5="==========="; //Zigzag indicator setting -input int Depth=5; -input int Deviation=5; -input int Backstep=3; -input int GapPoint=100; //Minimum gap between peaks -input int Sensitivity=2; //Minimum peak at same level -input int LookBack=50; //Maximum peak to consider - -input int NumberOfCandles=3; - -//-GLOBAL VARIABLES-// -//The variables included in this section are global, hence they can be used in any part of the code -string Symb=Symbol(), server_time; - -long current_chart_id = ChartID(); - -bool IsPreChecksOk=false; //Indicates if the pre checks are satisfied -bool IsNewCandle=false; //Indicates if this is a new candle formed -bool IsSpreadOK=false; //Indicates if the spread is low enough to trade -bool IsOperatingHours=false; //Indicates if it is possible to trade at the current time (server time) -bool IsTradedThisBar=false; //Indicates if an order was already executed in the current candle -bool In_Trade = true; //Indicates if trade range has been formed -bool CanBuy = true; -bool CanSell = true; -bool ClosePosition = false; -bool FollowProfit = false; -bool UpTrendingMarket = false; -bool DownTrendingMarket = false; - -double TickValue=0; //Value of a tick in account currency at 1 lot -double LotSize=0; //Lot size for the position -double Tick_Size = SymbolInfoDouble(Symb,SYMBOL_TRADE_TICK_SIZE); //Tick size -double High[]; -double Low[]; -double PositionProfit; - -//Indicators - -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -long Spread = SymbolInfoInteger(Symb,SYMBOL_SPREAD) / 100; //Check the impact. It's originally a double -int OrderOpRetry=10; //Number of attempts to retry the order submission -int TotalOpenOrders=0; //Number of total open orders -int TotalOpenBuy=0; //Number of total open buy orders -int TotalOpenSell=0; //Number of total open sell orders -int StopLossBy=SL_BY_POINTS; //How the stop loss is passed for the lot size calculation -double lotMultiplier =1; //Adust lot size according to loosing trades -int candleCounter =0; -double firstCandleOpen =0; -double lastCandleClose=0; -double ProfitRunTargetPercent=10.0; - -datetime LastBarTraded; - -MqlDateTime dt; -MqlTick last_tick; - -ENUM_SIGNAL_ENTRY SignalEntry=SIGNAL_ENTRY_NEUTRAL; //Entry signal variable -ENUM_SIGNAL_EXIT SignalExit=SIGNAL_EXIT_NEUTRAL; -ENUM_CANDLE_TYPE candleType=NEUTRAL_CANDLE; -ENUM_PRICE_MOMENTUM priceMomentum=NEUTRAL; -//+------------------------------------------------------------------+ diff --git a/Include/A_PositionsManager.mqh b/Include/A_PositionsManager.mqh deleted file mode 100644 index ac8a2b1..0000000 --- a/Include/A_PositionsManager.mqh +++ /dev/null @@ -1,123 +0,0 @@ -//+------------------------------------------------------------------+ -//| A_PositionsManager.mqh | -//| Copyright 2021, Nkondog Anselme Venceslas | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2021, Nkondog Anselme Venceslas" -#property link "https://www.mql5.com" -CTrade trade; - -//Scan all positions to find the ones submitted by the EA -//NOTE This function is defined as bool because we want to return true if it is successful and false if it fails -bool ScanPositions() - { - -//Scan all the orders, retrieving some of the details - TotalOpenOrders = 0; - TotalOpenBuy = 0; - TotalOpenSell = 0; - for(int i=0; iLastBarTraded || LastBarTraded==0) - LastBarTraded=(datetime)PositionGetInteger(POSITION_TIME); - } - Print("Total positions ", TotalOpenOrders, " - Total buys ", TotalOpenBuy, " - Total sells ", TotalOpenSell); - return true; - } - -// We declare a function CloseOpenPositions of type int and we want to return -// the number of positions that are closed. -void CloseOpenPositions() - { - - int TotalClose=0; // We want to count how many orders have been closed. - int c_slippage = Slippage; - Print("Close position status ", ClosePosition); -// Normalization of the slippage. - if(_Digits==3 || _Digits==5) - { - c_slippage=c_slippage*10; - } - -// We scan all the orders backwards. -// This is required as if we start from the first order, we will have problems with the counters and the loop. - for(int i=PositionsTotal()-1; i>=0; i--) - { - - ulong ticket = PositionGetTicket(i); - - Print("Position profit is ", PositionGetDouble(POSITION_PROFIT)); - PositionProfit = PositionGetDouble(POSITION_PROFIT); - /*if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && iClose(Symb, PERIOD_CURRENT, 1) < Senkouspanb && iClose(Symb, PERIOD_CURRENT, 1) < Senkouspana) - { - // We select the order of index i, selecting by position and from the pool of market/pending trades. - //If the selection is successful we try to close the order. - if(trade.PositionClose(ticket, c_slippage)) - { - TotalClose++; - } - else - { - // If the order fails to be closed, we print the error. - Print("Order failed to close with error - ",GetLastError()); - } - } - - if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && iClose(Symb, PERIOD_CURRENT, 1) > Senkouspanb && iClose(Symb, PERIOD_CURRENT, 1) > Senkouspana) - { - // We select the order of index i, selecting by position and from the pool of market/pending trades. - //If the selection is successful we try to close the order. - if(trade.PositionClose(ticket, c_slippage)) - { - TotalClose++; - } - else - { - // If the order fails to be closed, we print the error. - Print("Order failed to close with error - ",GetLastError()); - } - }*/ - - if(ClosePosition) - { - if(trade.PositionClose(ticket, c_slippage)) - { - TotalClose++; - ClosePosition = false; - } - else - { - // If the order fails to be closed, we print the error. - Print("Order failed to close with error - ",GetLastError()); - } - } - // We can use a delay if the execution is too fast. - // Sleep() will wait X milliseconds before proceeding with the code. - // Sleep(300); - } - } -//+------------------------------------------------------------------+ diff --git a/Include/A_TradeManager.mqh b/Include/A_TradeManager.mqh deleted file mode 100644 index fa829a9..0000000 --- a/Include/A_TradeManager.mqh +++ /dev/null @@ -1,23 +0,0 @@ -//+------------------------------------------------------------------+ -//| A_TradeManager.mqh | -//| Copyright 2021, Nkondog Anselme Venceslas | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2021, Nkondog Anselme Venceslas" -#property link "https://www.mql5.com" - -void ProfitRunner() - { - if(ProfitRun) - { - if(iClose(Symb, _Period, 1) < iClose(Symb, _Period, 2) && TotalOpenBuy > 0) - { - ClosePosition = true; - } - if(iClose(Symb, _Period, 1) > iClose(Symb, _Period, 2) && TotalOpenSell > 0) - { - ClosePosition = true; - } - } - Print("Looking to close this position ", ClosePosition); - } \ No newline at end of file diff --git a/Include/A_TradingHour.mqh b/Include/A_TradingHour.mqh deleted file mode 100644 index 72d352a..0000000 --- a/Include/A_TradingHour.mqh +++ /dev/null @@ -1,27 +0,0 @@ -//+------------------------------------------------------------------+ -//| A_TradingHour.mqh | -//| Copyright 2021, Nkondog Anselme Venceslas | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2021, Nkondog Anselme Venceslas" -#property link "https://www.mql5.com" -//+------------------------------------------------------------------+ -//| defines | -//+------------------------------------------------------------------+ -// #define MacrosHello "Hello, world!" -// #define MacrosYear 2010 -//+------------------------------------------------------------------+ -//| DLL imports | -//+------------------------------------------------------------------+ -// #import "user32.dll" -// int SendMessageA(int hWnd,int Msg,int wParam,int lParam); -// #import "my_expert.dll" -// int ExpertRecalculate(int wParam,int lParam); -// #import -//+------------------------------------------------------------------+ -//| EX5 imports | -//+------------------------------------------------------------------+ -// #import "stdlib.ex5" -// string ErrorDescription(int error_code); -// #import -//+------------------------------------------------------------------+ diff --git a/Include/Arrays/Array.mqh b/Include/Arrays/Array.mqh deleted file mode 100644 index b78f528..0000000 --- a/Include/Arrays/Array.mqh +++ /dev/null @@ -1,182 +0,0 @@ -//+------------------------------------------------------------------+ -//| Array.mqh | -//| Copyright 2009-2017, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -//+------------------------------------------------------------------+ -//| 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 deleted file mode 100644 index ea822b0..0000000 --- a/Include/Arrays/ArrayChar.mqh +++ /dev/null @@ -1,771 +0,0 @@ -//+------------------------------------------------------------------+ -//| 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(CArray::Minimum(m_data,start,count)); } - int Maximum(const int start,const int count) const { return(CArray::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 deleted file mode 100644 index fde1633..0000000 --- a/Include/Arrays/TreeNode.mqh +++ /dev/null @@ -1,174 +0,0 @@ -//+------------------------------------------------------------------+ -//| 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 deleted file mode 100644 index 75b7a34..0000000 --- a/Include/Canvas/Canvas.mqh +++ /dev/null @@ -1,4846 +0,0 @@ -//+------------------------------------------------------------------+ -//| 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); - virtual bool Attach(const long chart_id,const string objname,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA); - virtual bool Attach(const long chart_id,const string objname,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA); - virtual 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); - //--- load bitmap from file to buffer - static bool LoadBitmap(const string filename,uint &data[],int &width,int &height); - -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)ChartID()+(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_chart_id=chart_id; - 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_chart_id=chart_id; - 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,clr,size,style,end_style); - return; - } - if(dy==0) - { - LineThickHorizontal(x1,x2,y1,clr,size,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)); - } -//+------------------------------------------------------------------+ -//| 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; 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 M#L|%;i-Umw2O)7eL;wH) diff --git a/Include/Canvas/Charts/ChartCanvas.mqh b/Include/Canvas/Charts/ChartCanvas.mqh deleted file mode 100644 index 5c72678..0000000 --- a/Include/Canvas/Charts/ChartCanvas.mqh +++ /dev/null @@ -1,1041 +0,0 @@ -//+------------------------------------------------------------------+ -//| ChartCanvas.mqh | -//| Copyright 2009-2017, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include "..\Canvas.mqh" -#include -#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); - uint 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 deleted file mode 100644 index c81e9e3..0000000 --- a/Include/Canvas/Charts/LineChart.mqh +++ /dev/null @@ -1,383 +0,0 @@ -//+------------------------------------------------------------------+ -//| 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 deleted file mode 100644 index 79be4d1..0000000 --- a/Include/Canvas/Charts/PieChart.mqh +++ /dev/null @@ -1,414 +0,0 @@ -//+------------------------------------------------------------------+ -//| 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/DX/DXBox.mqh b/Include/Canvas/DX/DXBox.mqh deleted file mode 100644 index fb50af5..0000000 --- a/Include/Canvas/DX/DXBox.mqh +++ /dev/null @@ -1,77 +0,0 @@ -//+------------------------------------------------------------------+ -//| DXBox.mqh | -//| Copyright 2019, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2019, MetaQuotes Software Corp." -#property link "https://www.mql5.com" -//--- -#include "DXMesh.mqh" -#include "DXMath.mqh" -#include "DXUtils.mqh" -//+------------------------------------------------------------------+ -//| 3D Box object | -//+------------------------------------------------------------------+ -class CDXBox : public CDXMesh - { -public: - CDXBox(); - ~CDXBox(); - //--- create bon in specified context - bool Create(CDXDispatcher &dispatcher,CDXInput* buffer_scene,const DXVector3 &from,const DXVector3 &to); - //--- update box - bool Update(const DXVector3 &from,const DXVector3 &to); - -private: - //--- - void PrepareVertices(const DXVector3 &from,const DXVector3 &to); - }; -//+------------------------------------------------------------------+ -//| Class constructor | -//+------------------------------------------------------------------+ -void CDXBox::CDXBox() : CDXMesh() - { - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -void CDXBox::~CDXBox(void) - { - } -//+------------------------------------------------------------------+ -//| Create box in specified context | -//+------------------------------------------------------------------+ -bool CDXBox::Create(CDXDispatcher &dispatcher,CDXInput* buffer_scene,const DXVector3 &from,const DXVector3 &to) - { -//--- release previous buffers - Shutdown(); -//--- - DXVertex vertices[]; - uint indices[]; -//--- prepare box vertices and indices - DXColor white=DXColor(1.0f,1.0f,1.0f,1.0f); - if(!DXComputeBox(from,to,vertices,indices)) - return(false); - for(int i=0; i - bool Create(int context_handle,const TVertex &vertices[],uint start=0,uint count=WHOLE_ARRAY) - { - Shutdown(); - m_context=context_handle; - m_handle=DXBufferCreate(m_context,DX_BUFFER_VERTEX,vertices,start,count); - return(m_handle!=INVALID_HANDLE); - } - //+------------------------------------------------------------------+ - //| Render | - //+------------------------------------------------------------------+ - bool Render(uint start=0,uint count=WHOLE_ARRAY) - { - return(DXBufferSet(m_context,m_handle,start,count)); - } - //+------------------------------------------------------------------+ - //| Shutdown | - //+------------------------------------------------------------------+ - void Shutdown(void) - { - //--- relase handle - if(m_handle!=INVALID_HANDLE) - DXRelease(m_handle); - m_handle=INVALID_HANDLE; - } - }; -//+------------------------------------------------------------------+ -//| DX index buffer | -//+------------------------------------------------------------------+ -class CDXIndexBuffer : public CDXHandleShared - { -public: - //+------------------------------------------------------------------+ - //| Destructor | - //+------------------------------------------------------------------+ - virtual ~CDXIndexBuffer(void) - { - Shutdown(); - } - //+------------------------------------------------------------------+ - //| Create index buffer in specified context | - //+------------------------------------------------------------------+ - bool Create(int context_handle,const uint &indices[],uint start=0,uint count=WHOLE_ARRAY) - { - Shutdown(); - m_context=context_handle; - m_handle=DXBufferCreate(m_context,DX_BUFFER_INDEX,indices,start,count); - return(m_handle!=INVALID_HANDLE); - } - //+------------------------------------------------------------------+ - //| Render | - //+------------------------------------------------------------------+ - bool Render(uint start=0,uint count=WHOLE_ARRAY) - { - return(DXBufferSet(m_context,m_handle,start,count)); - } - //+------------------------------------------------------------------+ - //| Shutdown | - //+------------------------------------------------------------------+ - void Shutdown(void) - { - //--- relase handle - if(m_handle!=INVALID_HANDLE) - DXRelease(m_handle); - m_handle=INVALID_HANDLE; - } - }; -//+------------------------------------------------------------------+ diff --git a/Include/Canvas/DX/DXData.mqh b/Include/Canvas/DX/DXData.mqh deleted file mode 100644 index 252803c57692cc9d78ce97f6517147aecb616b20..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4048 zcmeH}T~8BH5QgX4#Q(6VmncQl3o%|GRYOv#0x=}SY%1MKO~2gTQXAl}tIy1K+bun% z3uv<>=47|0d(L@h=ADl-zkijbENk+l0Ao!a$^*11%Y}F=9Tho}iqs|MS(lFdkW=Je z+(Dlm=}BKk5=u+Hffj?eDI4-sUdm(UA0#kopJc$!n12yp512RkH$;z+Z=NVl2+}(9 zyXcdjPt`R>VkBGUiy_(!$E>vF1+x=$>dfdxc4mZoW+zOPSOYnoG|e zO!irch?|(FNA$e9;rXs1cZjg|wP!aSvSZ69)vPghRT*2S3Xl&mWj~GMEvkxJ%IgW|S??v@EXhZy zQ5|>Xkf$blQnD(#VQ-b;%R9dBljYm&@tHlN-oCf@8+&itTlZDjsk=P6!C^Z)6?HTeROnqH15ckzKR4WFy3Fmr7CF_cK=g4ZBhX)95H_N1<`DOWgJ? z+7HN!fPZ?+u4>$un(AUH^>Q{lmC@v0)jr34OP#S2&_QJDQ=W5uDq>H*b5<+&?do!y zb4mB*Q(apiUWc}<+Gf$T0?yZ6wQCtlo!;rIani*u->UOfr2CagHS9_K^gokkyOU`q zWm&pyE@|&mx0|;~{Dnl))vQ_;eVPSL#(-NmSP*?lU$qP=Kza)l?VGe4a7S`JtcaSd unK`iTBV35pw4Bq - CDXVertexBuffer* VertexBufferCreate(const TVertex &vertices[],uint start=0,uint count=WHOLE_ARRAY); - CDXIndexBuffer* IndexBufferCreate(const uint &indicies[],uint start=0,uint count=WHOLE_ARRAY); - //--- create shader inputs - template - CDXInput* InputCreate(void); - CDXTexture* TextureCreateFromFile(string path,uint data_x=0,uint data_y=0,uint data_width=0,uint data_height=0); - CDXTexture* TextureCreateFromData(ENUM_DX_FORMAT format,uint width,uint height,const uint &data[],uint data_x=0,uint data_y=0,uint data_width=0,uint data_height=0); - -private: - //--- add resource to list - bool ResourceAdd(CDXObjectBase *resource); - //--- check resources - void ResourcesCheck(void); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CDXDispatcher::CDXDispatcher(void) - { - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CDXDispatcher::~CDXDispatcher(void) - { - Destroy(); - } -//+------------------------------------------------------------------+ -//| Create | -//+------------------------------------------------------------------+ -bool CDXDispatcher::Create(int context) - { -//--- check if context already exist - if(m_context!=INVALID_HANDLE) - return(false); -//--- save context - m_context=context; -//--- - return(true); - } -//+------------------------------------------------------------------+ -//| Destroy | -//+------------------------------------------------------------------+ -void CDXDispatcher::Destroy(void) - { -//--- release default shaders - if(m_default_ps) - { - m_default_ps.Release(); - m_default_ps=NULL; - } - if(m_default_vs) - { - m_default_vs.Release(); - m_default_vs=NULL; - } -//--- release and delete all DX resources - while(m_dx_resources.Next()) - { - CDXHandleShared* resource=(CDXHandleShared*)m_dx_resources.Next(); - resource.Release(); - } -//--- forget context - m_context=INVALID_HANDLE; - } -//+------------------------------------------------------------------+ -//| Check resources | -//+------------------------------------------------------------------+ -void CDXDispatcher::Check(void) - { -//--- - CDXHandleShared* resource=(CDXHandleShared*)m_dx_resources.Next(); -//--- release and delete all DX resources - while(CheckPointer(resource)!=POINTER_INVALID) - { - CDXHandleShared* next=(CDXHandleShared*)resource.Next(); - //--- if references count 1 or less, then only we hold the resource - if(resource.References()<=1) - resource.Release(); - //--- - resource=next; - } - } -//+------------------------------------------------------------------+ -//| Create default shader of specified type | -//+------------------------------------------------------------------+ -CDXShader* CDXDispatcher::ShaderCreateDefault(ENUM_DX_SHADER_TYPE shader_type) - { - switch(shader_type) - { - //--- default pixel shader - case DX_SHADER_PIXEL: - { - if(m_default_ps==NULL) - m_default_ps=ShaderCreateFromSource(DX_SHADER_PIXEL,ExtDefaultShaderPixel,"PSMain"); - return(m_default_ps); - } - //--- default vertex shader - case DX_SHADER_VERTEX: - { - if(m_default_vs==NULL) - { - m_default_vs=ShaderCreateFromSource(DX_SHADER_VERTEX,ExtDefaultShaderVertex,"VSMain"); - if(m_default_vs && !m_default_vs.LayoutSet()) - { - m_default_vs.Release(); - m_default_vs=NULL; - } - } - return(m_default_vs); - } - } -//--- return result - return(NULL); - } -//+------------------------------------------------------------------+ -//| Create new shader of specified type from file | -//+------------------------------------------------------------------+ -CDXShader* CDXDispatcher::ShaderCreateFromFile(ENUM_DX_SHADER_TYPE shader_type,string path,string entry_point) - { -//--- open source file - int file=FileOpen(path,FILE_READ); - if(file==INVALID_HANDLE) - return(NULL); -//--- check file size - uint size=(uint)FileSize(file); - FileClose(file); - if(size>16*1024*1024) - return(NULL); -//--- prepare buffer - char buffer[]; - ArrayResize(buffer,size); -//--- read file into buffer - int read=(int)FileLoad(path,buffer); - if(read<=0) - return(NULL); -//--- convert vuffer to string - string source=CharArrayToString(buffer,0,WHOLE_ARRAY,CP_UTF8); -//--- add shader by source - return(ShaderCreateFromSource(shader_type,source,entry_point)); - } -//+------------------------------------------------------------------+ -//| Create new shader of specified type from source code | -//+------------------------------------------------------------------+ -CDXShader* CDXDispatcher::ShaderCreateFromSource(ENUM_DX_SHADER_TYPE shader_type,string source,string entry_point) - { -//--- check context - if(m_context==INVALID_HANDLE) - return(NULL); -//--- allocate new shader - CDXShader* shader=new CDXShader(); - if(shader==NULL) - return(NULL); -//--- create shader - if(!shader.Create(m_context,shader_type,source,entry_point)) - { - shader.Release(); - return(NULL); - } -//--- add shader to resources list - if(!ResourceAdd(shader)) - { - shader.Release(); - return(NULL); - } -//--- return shader - return(shader); - } -//+------------------------------------------------------------------+ -//| Create vertex buffer | -//+------------------------------------------------------------------+ -template -CDXVertexBuffer* CDXDispatcher::VertexBufferCreate(const TVertex &vertices[],uint start=0,uint count=WHOLE_ARRAY) - { -//--- check context - if(m_context==INVALID_HANDLE) - return(NULL); -//--- allocate new buffer - CDXVertexBuffer* buffer=new CDXVertexBuffer(); - if(buffer==NULL) - return(NULL); -//--- create buffer - if(!buffer.Create(m_context,vertices,start,count)) - { - buffer.Release(); - return(NULL); - } -//--- add buffer to resources list - if(!ResourceAdd(buffer)) - { - buffer.Release(); - return(NULL); - } -//--- return buffer - return(buffer); - } -//+------------------------------------------------------------------+ -//| Create vertex buffer | -//+------------------------------------------------------------------+ -CDXIndexBuffer* CDXDispatcher::IndexBufferCreate(const uint &indicies[],uint start=0,uint count=WHOLE_ARRAY) - { -//--- check context - if(m_context==INVALID_HANDLE) - return(NULL); -//--- allocate new buffer - CDXIndexBuffer* buffer=new CDXIndexBuffer(); - if(buffer==NULL) - return(NULL); -//--- create buffer - if(!buffer.Create(m_context,indicies,start,count)) - { - buffer.Release(); - return(NULL); - } -//--- add buffer to resources list - if(!ResourceAdd(buffer)) - { - buffer.Release(); - return(NULL); - } -//--- return input buffer - return(buffer); - } -//+------------------------------------------------------------------+ -//| Create shader input buffer | -//+------------------------------------------------------------------+ -template -CDXInput* CDXDispatcher::InputCreate(void) - { -//--- check context - if(m_context==INVALID_HANDLE) - return(NULL); -//--- allocate new input buffer - CDXInput* input_buffer=new CDXInput(); - if(input_buffer==NULL) - return(NULL); -//--- create buffer - if(!input_buffer.Create(m_context)) - { - input_buffer.Release(); - return(NULL); - } -//--- add buffer to resources list - if(!ResourceAdd(input_buffer)) - { - input_buffer.Release(); - return(NULL); - } -//--- return shader - return(input_buffer); - } -//+------------------------------------------------------------------+ -//| Create texture from bitmap file | -//+------------------------------------------------------------------+ -CDXTexture* CDXDispatcher::TextureCreateFromFile(string path,uint data_x=0,uint data_y=0,uint data_width=0,uint data_height=0) - { -//--- check context - if(m_context==INVALID_HANDLE) - return(NULL); -//--- allocate new texture - CDXTexture* texture=new CDXTexture(); - if(texture==NULL) - return(NULL); -//--- create texture - if(!texture.Create(m_context,path,data_x,data_y,data_width,data_height)) - { - texture.Release(); - return(NULL); - } -//--- add texture to resources list - if(!ResourceAdd(texture)) - { - texture.Release(); - return(NULL); - } -//--- return shader - return(texture); - } -//+------------------------------------------------------------------+ -//| Create texture from raw data, only 32-bit pixel formats supported| -//+------------------------------------------------------------------+ -CDXTexture* CDXDispatcher::TextureCreateFromData(ENUM_DX_FORMAT format,uint width,uint height,const uint &data[],uint data_x=0,uint data_y=0,uint data_width=0,uint data_height=0) - { -//--- check context - if(m_context==INVALID_HANDLE) - return(NULL); -//--- allocate new texture - CDXTexture* texture=new CDXTexture(); - if(texture==NULL) - return(NULL); -//--- create texture - if(!texture.Create(m_context,format,width,height,data,data_x,data_y,data_width,data_height)) - { - texture.Release(); - return(NULL); - } -//--- add texture to resources list - if(!ResourceAdd(texture)) - { - texture.Release(); - return(NULL); - } -//--- return shader - return(texture); - } -//+------------------------------------------------------------------+ -//| Add DX resource | -//+------------------------------------------------------------------+ -bool CDXDispatcher::ResourceAdd(CDXObjectBase *resource) - { -//--- add resource - if(!CheckPointer(resource)) - return(false); -//--- - CDXObjectBase *last=&m_dx_resources; - while(CheckPointer(last.Next())!=POINTER_INVALID) - { - if(last==resource) - return(false); - //--- - last=last.Next(); - } -//--- - resource.Next(NULL); - resource.Prev(last); - last.Next(resource); - return(true); - } -//+------------------------------------------------------------------+ diff --git a/Include/Canvas/DX/DXHandle.mqh b/Include/Canvas/DX/DXHandle.mqh deleted file mode 100644 index 598d5290fb053b175fc2ecc741191687cbd61daa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8568 zcmd^EYflqF6uqBK{0~z|Obzlf@q;CN;1w`Ij1Z0A2vCaEKClmn0{(RMoS9DdZfAC> zMaUM@lrG!ZnS0MY_uezp-@g`RQRZa60IxZDDoyPH__|ctwWWv58;lnuR z;Zgx!=U~Dy#?=vfk6w%oj6d0Z1u4nu2xDBvxelSTj|yWS5ut)~+9F<${M!E6QHHwpbX88+nOqf@r+MA@z;-y+ z?CO73!SYo~8ka1^qPwDJ(Kt$_4^FnxAJ1|yCkq*u8s7Y*er9#iip43FaFpv&{ed20 ze=?{_pYgoG4Aeh9;%%kC=>gyQ`ergkqVd!{!DW?OHLgy4R_1+%HRtyA++13CZ;PjcA7c9Zn=uZ-sw(QnV0O1C-N1{3R#uz zrZrSj?)H2?Wo(YI4?Kfjbse2EP;ausb4{Lp)ocuFcT)(S! zN3L3jHFwRbT%Ht^WhSx@)0h}omYlm8d$P$hEPBFz;!ak0ziz!W@Poe0%MX0Z6POrE zoPnp1PIZ)EMfxPeS-y!G99ruZ=_6oXj*N6Qe-@*822A{X^oqSJbXp;X4;eF_4s%FN z`nQ;wto2a7T4OiJQe2(`VFoj6yyhTZPr=@J6cUaauqrE;v$NU7MXy)JZ#8rFTqB;l zD^tSVZHr+HwRCRZACn&gclUu}p2{yOhqLyZx{4RO_7eFfGWr6aF%~o5*}eEXneX1+ z%-!%L_4l#xH@>S(GuPqc&ge=x)z3fW@l03FrD5++^jPvl7AL9OTvbh;O6!-ra}KAr zJO^lxQ#b~yt%cu*W8CQuYq-~Hd-Lb|&BmD5a LFe_%ouOoi|5JmNF diff --git a/Include/Canvas/DX/DXInput.mqh b/Include/Canvas/DX/DXInput.mqh deleted file mode 100644 index 39076685c173e4f375d8d34a46bd4f6fd2d02698..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4968 zcmeHKVQ&&a5PhFb{10bM%r(VQP5dB=i2;+E)Fz5Cej`^n^x^?}K+kI1pRT^yWqZ4O zAP@|>CguX{-QMoZzIktE`2DMnIu7u#0@nfV;tsv3;}XFRuQop7HAeV~8KyYI5Z~~b z_Aj^ar-d>1yFi8npSatU`#r`H9^ol!9KS)#XA$1g=9r@x6F%*5Jm6iYQxI zh|P?VPZ{s>bzM?fh;w3@Fl+2vT#%KTE%qM5DXAZQuE?2bLauq{t-7-At5$dQSq!6E zs{TYgk5r+EpAknneN*PdNGuEpCXEM(G+pGGF5^RRVLb8#JpY!{I_c0NQI3vit zw>pa#R`k!vlJOEA8XWBygbH`*BBc6`l)dl#Ud>C1sP66pRuY$^b~L5;GM43c9X{*4 zSnM8AFLG+b71vka!Vq2WG)?c`*N*TFAMg?<9JM)r%<(BlCwR4B$J>)lIz&mh zYsaRqR3n*X7uWx6QuK~G8sS`P6BQXdPX%~jMXJk+CiyMeFxT|R?wB^dcyYHi=W8-i zO7fM_T&WCyAI&KF2UX~8z!Rj@Y`j28ZeEdhma)~hb$R!^d%x4%Dvn!b|-xN$T= 1.0f) || (q.w == -1.0f)) - t = 1.0f; - else - t = (float)(acos(q.w)/sqrt(1.0f - q.w*q.w)); - out.x = t*q.x; - out.y = t*q.y; - out.z = t*q.z; - out.w = 0.0f; - } -//+------------------------------------------------------------------+ -//| Multiplies two quaternions. | -//+------------------------------------------------------------------+ -void DXQuaternionMultiply(DXQuaternion &pout,const DXQuaternion &pq1,const DXQuaternion &pq2) - { - DXQuaternion out; - out.x = pq2.w*pq1.x + pq2.x*pq1.w + pq2.y*pq1.z - pq2.z*pq1.y; - out.y = pq2.w*pq1.y - pq2.x*pq1.z + pq2.y*pq1.w + pq2.z*pq1.x; - out.z = pq2.w*pq1.z + pq2.x*pq1.y - pq2.y*pq1.x + pq2.z*pq1.w; - out.w = pq2.w*pq1.w - pq2.x*pq1.x - pq2.y*pq1.y - pq2.z*pq1.z; - pout = out; - } -//+------------------------------------------------------------------+ -//| Computes a unit length quaternion. | -//+------------------------------------------------------------------+ -void DXQuaternionNormalize(DXQuaternion &out,const DXQuaternion &q) - { - float norm = DXQuaternionLength(q); - if(!norm) - { - out.x = 0.0f; - out.y = 0.0f; - out.z = 0.0f; - out.w = 0.0f; - } - else - { - out.x = q.x/norm; - out.y = q.y/norm; - out.z = q.z/norm; - out.w = q.w/norm; - } - } -//+------------------------------------------------------------------+ -//| Rotates a quaternion about an arbitrary axis. | -//+------------------------------------------------------------------+ -void DXQuaternionRotationAxis(DXQuaternion &out,const DXVector3 &v,float angle) - { - DXVector3 temp; - DXVec3Normalize(temp,v); - out.x = (float)sin(angle/2.0f)*temp.x; - out.y = (float)sin(angle/2.0f)*temp.y; - out.z = (float)sin(angle/2.0f)*temp.z; - out.w = (float)cos(angle/2.0f); - } -//+------------------------------------------------------------------+ -//| Builds a quaternion from a rotation matrix. | -//+------------------------------------------------------------------+ -void DXQuaternionRotationMatrix(DXQuaternion &out,const DXMatrix &m) - { - float s; - float trace = m.m[0][0] + m.m[1][1] + m.m[2][2] + 1.0f; - if(trace>1.0f) - { - s = 2.0f*(float)sqrt(trace); - out.x = (m.m[1][2] - m.m[2][1])/s; - out.y = (m.m[2][0] - m.m[0][2])/s; - out.z = (m.m[0][1] - m.m[1][0])/s; - out.w = 0.25f*s; - } - else - { - int maxi = 0; - for(int i=1; i<3; i++) - { - if(m.m[i][i] > m.m[maxi][maxi]) - maxi = i; - } - switch(maxi) - { - case 0: - s = 2.0f*(float)sqrt(1.0f + m.m[0][0] - m.m[1][1] - m.m[2][2]); - out.x = 0.25f*s; - out.y = (m.m[0][1] + m.m[1][0])/s; - out.z = (m.m[0][2] + m.m[2][0])/s; - out.w = (m.m[1][2] - m.m[2][1])/s; - break; - - case 1: - s = 2.0f*(float)sqrt(1.0f + m.m[1][1] - m.m[0][0] - m.m[2][2]); - out.x = (m.m[0][1] + m.m[1][0])/s; - out.y = 0.25f*s; - out.z = (m.m[1][2] + m.m[2][1])/s; - out.w = (m.m[2][0] - m.m[0][2])/s; - break; - - case 2: - s = 2.0f*(float)sqrt(1.0f + m.m[2][2] - m.m[0][0] - m.m[1][1]); - out.x = (m.m[0][2] + m.m[2][0])/s; - out.y = (m.m[1][2] + m.m[2][1])/s; - out.z = 0.25f*s; - out.w = (m.m[0][1] - m.m[1][0])/s; - break; - } - } - } -//+------------------------------------------------------------------+ -//| Builds a quaternion with the given yaw, pitch, and roll. | -//+------------------------------------------------------------------+ -void DXQuaternionRotationYawPitchRoll(DXQuaternion &out,float yaw,float pitch,float roll) - { - float syaw = (float)sin(yaw/2.0f); - float cyaw = (float)cos(yaw/2.0f); - float spitch = (float)sin(pitch/2.0f); - float cpitch = (float)cos(pitch/2.0f); - float sroll = (float)sin(roll/2.0f); - float croll = (float)cos(roll/2.0f); -//--- - out.x = syaw*cpitch*sroll + cyaw*spitch*croll; - out.y = syaw*cpitch*croll - cyaw*spitch*sroll; - out.z = cyaw*cpitch*sroll - syaw*spitch*croll; - out.w = cyaw*cpitch*croll + syaw*spitch*sroll; - } -//+------------------------------------------------------------------+ -//| Interpolates between two quaternions, using spherical linear | -//| interpolation. | -//+------------------------------------------------------------------+ -void DXQuaternionSlerp(DXQuaternion &out,DXQuaternion &q1,DXQuaternion &q2,float t) - { - float temp = 1.0f - t; - float dot = DXQuaternionDot(q1,q2); - if(dot<0.0f) - { - t = -t; - dot = -dot; - } - if(1.0f-dot>0.001f) - { - float theta = (float)acos(dot); - temp = (float)sin(theta*temp)/(float)sin(theta); - t = (float)sin(theta*t)/(float)sin(theta); - } - out.x = temp*q1.x + t*q2.x; - out.y = temp*q1.y + t*q2.y; - out.z = temp*q1.z + t*q2.z; - out.w = temp*q1.w + t*q2.w; - } -//+------------------------------------------------------------------+ -//| Interpolates between quaternions, using spherical quadrangle | -//| interpolation. | -//+------------------------------------------------------------------+ -void DXQuaternionSquad(DXQuaternion &pout,DXQuaternion &pq1,DXQuaternion &pq2,DXQuaternion &pq3,DXQuaternion &pq4,float t) - { - DXQuaternion temp1,temp2; - DXQuaternionSlerp(temp1,pq1,pq4,t); - DXQuaternionSlerp(temp2,pq2,pq3,t); - DXQuaternionSlerp(pout,temp1,temp2,2.0f*t*(1.0f - t)); - } -//+------------------------------------------------------------------+ -//| add_diff | -//+------------------------------------------------------------------+ -DXQuaternion add_diff(const DXQuaternion &q1,const DXQuaternion &q2,const float add) - { - DXQuaternion temp; - temp.x = q1.x + add * q2.x; - temp.y = q1.y + add * q2.y; - temp.z = q1.z + add * q2.z; - temp.w = q1.w + add * q2.w; -//--- - return(temp); - } -//+------------------------------------------------------------------+ -//| Sets up control points for spherical quadrangle interpolation. | -//+------------------------------------------------------------------+ -void DXQuaternionSquadSetup(DXQuaternion &paout,DXQuaternion &pbout,DXQuaternion &pcout,DXQuaternion &pq0,DXQuaternion &pq1,DXQuaternion &pq2,DXQuaternion &pq3) - { - DXQuaternion q,temp1,temp2,temp3,zero; - DXQuaternion aout,cout; - zero.x = 0.0f; - zero.y = 0.0f; - zero.z = 0.0f; - zero.w = 0.0f; -//--- - if(DXQuaternionDot(pq0,pq1) < 0.0f) - temp2 = add_diff(zero,pq0,-1.0f); - else - temp2 = pq0; -//--- - if(DXQuaternionDot(pq1,pq2) < 0.0f) - cout = add_diff(zero,pq2,-1.0f); - else - cout = pq2; -//--- - if(DXQuaternionDot(cout,pq3) < 0.0f) - temp3 = add_diff(zero,pq3,-1.0f); - else - temp3 = pq3; -//--- - DXQuaternionInverse(temp1,pq1); - DXQuaternionMultiply(temp2,temp1,temp2); - DXQuaternionLn(temp2,temp2); - DXQuaternionMultiply(q,temp1,cout); - DXQuaternionLn(q,q); - temp1 = add_diff(temp2,q,1.0f); - temp1.x *= -0.25f; - temp1.y *= -0.25f; - temp1.z *= -0.25f; - temp1.w *= -0.25f; - DXQuaternionExp(temp1,temp1); - DXQuaternionMultiply(aout,pq1,temp1); -//--- - DXQuaternionInverse(temp1,cout); - DXQuaternionMultiply(temp2,temp1,pq1); - DXQuaternionLn(temp2,temp2); - DXQuaternionMultiply(q,temp1,temp3); - DXQuaternionLn(q,q); - temp1 = add_diff(temp2,q,1.0f); - temp1.x *= -0.25f; - temp1.y *= -0.25f; - temp1.z *= -0.25f; - temp1.w *= -0.25f; - DXQuaternionExp(temp1,temp1); - DXQuaternionMultiply(pbout,cout,temp1); - paout = aout; - pcout = cout; - } -//+------------------------------------------------------------------+ -//| Computes a quaternion's axis and angle of rotation. | -//+------------------------------------------------------------------+ -void DXQuaternionToAxisAngle(const DXQuaternion &pq,DXVector3 &paxis,float &pangle) - { -//--- paxis - paxis.x = pq.x; - paxis.y = pq.y; - paxis.z = pq.z; -//--- pangle - pangle = 2.0f*(float)acos(pq.w); - } -//+------------------------------------------------------------------+ -//| DXMatrixIdentity creates an identity matrix | -//+------------------------------------------------------------------+ -void DXMatrixIdentity(DXMatrix &out) - { - for(int j=0; j<4; j++) - for(int i=0; i<4; i++) - { - if(i==j) - out.m[j,i]=1.0f; - else - out.m[j,i]=0.0f; - } - } -//+------------------------------------------------------------------+ -//| Determines if a matrix is an identity matrix. | -//+------------------------------------------------------------------+ -bool DXMatrixIsIdentity(DXMatrix &pm) - { - for(int j=0; j<4; j++) - for(int i=0; i<4; i++) - { - if(i==j) - { - if(fabs(pm.m[j,i]-1.0f)>1e-6f) - return(false); - } - else - if(fabs(pm.m[j,i])>1e-6f) - return(false); - } -//--- - return(true); - } -//+------------------------------------------------------------------+ -//| Builds a 3D affine transformation matrix. | -//+------------------------------------------------------------------+ -//| This function calculates the affine transformation matrix | -//| with the following formula, with matrix concatenation | -//| evaluated in left-to-right order: | -//| Mout = Ms * (Mrc)-1 * Mr * Mrc * Mt | -//| where: | -//| Mout = output matrix (pOut) | -//| Ms = scaling matrix (Scaling) | -//| Mrc = center of rotation matrix (pRotationCenter) | -//| Mr = rotation matrix (pRotation) | -//| Mt = translation matrix (pTranslation) | -//+------------------------------------------------------------------+ -void DXMatrixAffineTransformation(DXMatrix &out,float scaling,const DXVector3 &rotationcenter,const DXQuaternion &rotation,const DXVector3 &translation) - { - DXMatrixIdentity(out); -//--- rotation - float temp00 = 1.0f - 2.0f*(rotation.y*rotation.y + rotation.z*rotation.z); - float temp01 = 2.0f * (rotation.x*rotation.y + rotation.z*rotation.w); - float temp02 = 2.0f * (rotation.x*rotation.z - rotation.y*rotation.w); - float temp10 = 2.0f * (rotation.x*rotation.y - rotation.z*rotation.w); - float temp11 = 1.0f - 2.0f*(rotation.x*rotation.x + rotation.z*rotation.z); - float temp12 = 2.0f * (rotation.y*rotation.z + rotation.x*rotation.w); - float temp20 = 2.0f * (rotation.x*rotation.z + rotation.y*rotation.w); - float temp21 = 2.0f * (rotation.y*rotation.z - rotation.x*rotation.w); - float temp22 = 1.0f - 2.0f*(rotation.x*rotation.x + rotation.y*rotation.y); -//--- scaling - out.m[0][0] = scaling*temp00; - out.m[0][1] = scaling*temp01; - out.m[0][2] = scaling*temp02; - out.m[1][0] = scaling*temp10; - out.m[1][1] = scaling*temp11; - out.m[1][2] = scaling*temp12; - out.m[2][0] = scaling*temp20; - out.m[2][1] = scaling*temp21; - out.m[2][2] = scaling*temp22; -//--- rotationcenter - out.m[3][0] = rotationcenter.x*(1.0f - temp00) - rotationcenter.y*temp10 - rotationcenter.z*temp20; - out.m[3][1] = rotationcenter.y*(1.0f - temp11) - rotationcenter.x*temp01 - rotationcenter.z*temp21; - out.m[3][2] = rotationcenter.z*(1.0f - temp22) - rotationcenter.x*temp02 - rotationcenter.y*temp12; -//--- translation - out.m[3][0] += translation.x; - out.m[3][1] += translation.y; - out.m[3][2] += translation.z; - } -//+------------------------------------------------------------------+ -//| Builds a 2D affine transformation matrix in the xy plane. | -//+------------------------------------------------------------------+ -//| This function calculates the affine transformation matrix | -//| with the following formula, with matrix concatenation evaluated | -//| in left-to-right order: | -//| Mout = Ms * (Mrc)^(-1) * Mr * Mrc * Mt | -//| where: | -//| Mout = output matrix (pOut) | -//| Ms = scaling matrix (Scaling) | -//| Mrc = center of rotation matrix (pRotationCenter) | -//| Mr = rotation matrix (Rotation) | -//| Mt = translation matrix (pTranslation) | -//+------------------------------------------------------------------+ -void DXMatrixAffineTransformation2D(DXMatrix &out,float scaling,const DXVector2 &rotationcenter,float rotation,const DXVector2 &translation) - { - float s = (float)sin(rotation/2.0f); - float tmp1 = 1.0f - 2.0f*s*s; - float tmp2 = 2.0f*s*(float)cos(rotation/2.0f); -//--- - DXMatrixIdentity(out); - out.m[0][0] = scaling*tmp1; - out.m[0][1] = scaling*tmp2; - out.m[1][0] = -scaling*tmp2; - out.m[1][1] = scaling*tmp1; -//--- rotationcenter - float x = rotationcenter.x; - float y = rotationcenter.y; - out.m[3][0] = y*tmp2 - x*tmp1 + x; - out.m[3][1] = -x*tmp2 - y*tmp1 + y; -//--- translation - out.m[3][0] += translation.x; - out.m[3][1] += translation.y; - } -#define D3DERR_INVALIDCALL -2005530516 -//#define S_OK 0; -//+------------------------------------------------------------------+ -//| Breaks down a general 3D transformation matrix into its scalar, | -//| rotational, and translational components. | -//+------------------------------------------------------------------+ -int DXMatrixDecompose(DXVector3 &poutscale,DXQuaternion &poutrotation,DXVector3 &pouttranslation,const DXMatrix &pm) - { - DXMatrix normalized; - DXVector3 vec; -//--- Compute the scaling part - vec.x=pm.m[0][0]; - vec.y=pm.m[0][1]; - vec.z=pm.m[0][2]; - poutscale.x=DXVec3Length(vec); - vec.x=pm.m[1][0]; - vec.y=pm.m[1][1]; - vec.z=pm.m[1][2]; - poutscale.y=DXVec3Length(vec); - vec.x=pm.m[2][0]; - vec.y=pm.m[2][1]; - vec.z=pm.m[2][2]; - poutscale.z=DXVec3Length(vec); -//--- compute the translation part - pouttranslation.x=pm.m[3][0]; - pouttranslation.y=pm.m[3][1]; - pouttranslation.z=pm.m[3][2]; -//--- let's calculate the rotation now - if((poutscale.x == 0.0f) || (poutscale.y == 0.0f) || (poutscale.z == 0.0f)) - return(D3DERR_INVALIDCALL); -//--- - normalized.m[0][0]=pm.m[0][0]/poutscale.x; - normalized.m[0][1]=pm.m[0][1]/poutscale.x; - normalized.m[0][2]=pm.m[0][2]/poutscale.x; - normalized.m[1][0]=pm.m[1][0]/poutscale.y; - normalized.m[1][1]=pm.m[1][1]/poutscale.y; - normalized.m[1][2]=pm.m[1][2]/poutscale.y; - normalized.m[2][0]=pm.m[2][0]/poutscale.z; - normalized.m[2][1]=pm.m[2][1]/poutscale.z; - normalized.m[2][2]=pm.m[2][2]/poutscale.z; - DXQuaternionRotationMatrix(poutrotation,normalized); -//--- - return(0); - } -//+------------------------------------------------------------------+ -//| Returns the determinant of a matrix. | -//+------------------------------------------------------------------+ -float DXMatrixDeterminant(const DXMatrix &pm) - { - float t[3],v[4]; - t[0] = pm.m[2][2]*pm.m[3][3] - pm.m[2][3]*pm.m[3][2]; - t[1] = pm.m[1][2]*pm.m[3][3] - pm.m[1][3]*pm.m[3][2]; - t[2] = pm.m[1][2]*pm.m[2][3] - pm.m[1][3]*pm.m[2][2]; - v[0] = pm.m[1][1]*t[0] - pm.m[2][1] * t[1] + pm.m[3][1]*t[2]; - v[1] = -pm.m[1][0]*t[0] + pm.m[2][0] * t[1] - pm.m[3][0]*t[2]; -//--- - t[0] = pm.m[1][0]*pm.m[2][1] - pm.m[2][0]*pm.m[1][1]; - t[1] = pm.m[1][0]*pm.m[3][1] - pm.m[3][0]*pm.m[1][1]; - t[2] = pm.m[2][0]*pm.m[3][1] - pm.m[3][0]*pm.m[2][1]; - v[2] = pm.m[3][3]*t[0] - pm.m[2][3]*t[1] + pm.m[1][3]*t[2]; - v[3] = -pm.m[3][2]*t[0] + pm.m[2][2]*t[1] - pm.m[1][2]*t[2]; -//--- - return(pm.m[0][0]*v[0] + pm.m[0][1]*v[1] + pm.m[0][2]*v[2] + pm.m[0][3]*v[3]); - } -//+------------------------------------------------------------------+ -//| Calculates the inverse of a matrix. | -//+------------------------------------------------------------------+ -void DXMatrixInverse(DXMatrix &pout,float &pdeterminant,const DXMatrix &pm) - { - float t[3],v[16]; - t[0] = pm.m[2][2]*pm.m[3][3] - pm.m[2][3]*pm.m[3][2]; - t[1] = pm.m[1][2]*pm.m[3][3] - pm.m[1][3]*pm.m[3][2]; - t[2] = pm.m[1][2]*pm.m[2][3] - pm.m[1][3]*pm.m[2][2]; - v[0] = pm.m[1][1]*t[0] - pm.m[2][1]*t[1] + pm.m[3][1]*t[2]; - v[4] = -pm.m[1][0]*t[0] + pm.m[2][0]*t[1] - pm.m[3][0]*t[2]; -//--- - t[0] = pm.m[1][0]*pm.m[2][1] - pm.m[2][0]*pm.m[1][1]; - t[1] = pm.m[1][0]*pm.m[3][1] - pm.m[3][0]*pm.m[1][1]; - t[2] = pm.m[2][0]*pm.m[3][1] - pm.m[3][0]*pm.m[2][1]; - v[8] = pm.m[3][3]*t[0] - pm.m[2][3]*t[1] + pm.m[1][3]*t[2]; - v[12] = -pm.m[3][2]*t[0] + pm.m[2][2]*t[1] - pm.m[1][2]*t[2]; -//--- - float det = pm.m[0][0]*v[0] + pm.m[0][1]*v[4] + pm.m[0][2]*v[8] + pm.m[0][3]*v[12]; - if(det == 0.0f) - { - for(int j=0; j<4; j++) - for(int i=0; i<4; i++) - { - pout.m[j,i]=0.0; - } - //--- - return; - } - if(pdeterminant) - pdeterminant = det; -//--- - t[0] = pm.m[2][2]*pm.m[3][3] - pm.m[2][3]*pm.m[3][2]; - t[1] = pm.m[0][2]*pm.m[3][3] - pm.m[0][3]*pm.m[3][2]; - t[2] = pm.m[0][2]*pm.m[2][3] - pm.m[0][3]*pm.m[2][2]; - v[1] = -pm.m[0][1]*t[0] + pm.m[2][1]*t[1] - pm.m[3][1]*t[2]; - v[5] = pm.m[0][0]*t[0] - pm.m[2][0]*t[1] + pm.m[3][0]*t[2]; -//--- - t[0] = pm.m[0][0]*pm.m[2][1] - pm.m[2][0] * pm.m[0][1]; - t[1] = pm.m[3][0]*pm.m[0][1] - pm.m[0][0] * pm.m[3][1]; - t[2] = pm.m[2][0]*pm.m[3][1] - pm.m[3][0] * pm.m[2][1]; - v[9] = -pm.m[3][3]*t[0] - pm.m[2][3]*t[1]- pm.m[0][3]*t[2]; - v[13] = pm.m[3][2]*t[0] + pm.m[2][2]*t[1] + pm.m[0][2]*t[2]; -//--- - t[0] = pm.m[1][2]*pm.m[3][3] - pm.m[1][3] * pm.m[3][2]; - t[1] = pm.m[0][2]*pm.m[3][3] - pm.m[0][3] * pm.m[3][2]; - t[2] = pm.m[0][2]*pm.m[1][3] - pm.m[0][3] * pm.m[1][2]; - v[2] = pm.m[0][1]*t[0] - pm.m[1][1]*t[1] + pm.m[3][1]*t[2]; - v[6] = -pm.m[0][0]*t[0] + pm.m[1][0]*t[1] - pm.m[3][0]*t[2]; -//--- - t[0] = pm.m[0][0]*pm.m[1][1] - pm.m[1][0] * pm.m[0][1]; - t[1] = pm.m[3][0]*pm.m[0][1] - pm.m[0][0] * pm.m[3][1]; - t[2] = pm.m[1][0]*pm.m[3][1] - pm.m[3][0] * pm.m[1][1]; - v[10] = pm.m[3][3]*t[0] + pm.m[1][3]*t[1] + pm.m[0][3]*t[2]; - v[14] = -pm.m[3][2]*t[0] - pm.m[1][2]*t[1] - pm.m[0][2]*t[2]; -//--- - t[0] = pm.m[1][2]*pm.m[2][3] - pm.m[1][3] * pm.m[2][2]; - t[1] = pm.m[0][2]*pm.m[2][3] - pm.m[0][3] * pm.m[2][2]; - t[2] = pm.m[0][2]*pm.m[1][3] - pm.m[0][3] * pm.m[1][2]; - v[3] = -pm.m[0][1]*t[0] + pm.m[1][1]*t[1] - pm.m[2][1]*t[2]; - v[7] = pm.m[0][0]*t[0] - pm.m[1][0]*t[1] + pm.m[2][0]*t[2]; -//--- - v[11] = -pm.m[0][0]*(pm.m[1][1]*pm.m[2][3] - pm.m[1][3]*pm.m[2][1]) + - pm.m[1][0]*(pm.m[0][1]*pm.m[2][3] - pm.m[0][3]*pm.m[2][1]) - - pm.m[2][0]*(pm.m[0][1]*pm.m[1][3] - pm.m[0][3]*pm.m[1][1]); -//--- - v[15] = pm.m[0][0]*(pm.m[1][1]*pm.m[2][2] - pm.m[1][2]*pm.m[2][1]) - - pm.m[1][0]*(pm.m[0][1]*pm.m[2][2] - pm.m[0][2]*pm.m[2][1]) + - pm.m[2][0]*(pm.m[0][1]*pm.m[1][2] - pm.m[0][2]*pm.m[1][1]); -//--- - det = 1.0f/det; - for(int i=0; i<4; i++) - for(int j=0; j<4; j++) - pout.m[i][j] = v[4*i + j]*det; - } -//+------------------------------------------------------------------+ -//| Builds a left-handed,look-at matrix. | -//| This function uses the following formula to compute | -//| the returned matrix. | -//| | -//| zaxis = normal(At - Eye) | -//| xaxis = normal(cross(Up,zaxis)) | -//| yaxis = cross(zaxis,xaxis) | -//| | -//| xaxis.x yaxis.x zaxis.x 0 | -//| xaxis.y yaxis.y zaxis.y 0 | -//| xaxis.z yaxis.z zaxis.z 0 | -//| -dot(xaxis,eye) -dot(yaxis,eye) -dot(zaxis,eye) 1 | -//+------------------------------------------------------------------+ -void DXMatrixLookAtLH(DXMatrix &out,const DXVector3 &eye,const DXVector3 &at,const DXVector3 &up) - { - DXVector3 right,upn,vec; - DXVec3Subtract(vec,at,eye); - DXVec3Normalize(vec,vec); - DXVec3Cross(right,up,vec); - DXVec3Cross(upn,vec,right); - DXVec3Normalize(right,right); - DXVec3Normalize(upn,upn); -//--- - out.m[0][0] = right.x; - out.m[1][0] = right.y; - out.m[2][0] = right.z; - out.m[3][0] = -DXVec3Dot(right,eye); - out.m[0][1] = upn.x; - out.m[1][1] = upn.y; - out.m[2][1] = upn.z; - out.m[3][1] = -DXVec3Dot(upn,eye); - out.m[0][2] = vec.x; - out.m[1][2] = vec.y; - out.m[2][2] = vec.z; - out.m[3][2] = -DXVec3Dot(vec,eye); - out.m[0][3] = 0.0f; - out.m[1][3] = 0.0f; - out.m[2][3] = 0.0f; - out.m[3][3] = 1.0f; - } -//+------------------------------------------------------------------+ -//| Builds a right-handed, look-at matrix. | -//+------------------------------------------------------------------+ -//| This function uses the following formula to compute | -//| the returned matrix. | -//| | -//| zaxis = normal(Eye - At) | -//| xaxis = normal(cross(Up,zaxis)) | -//| yaxis = cross(zaxis,xaxis) | -//| | -//| xaxis.x yaxis.x zaxis.x 0 | -//| xaxis.y yaxis.y zaxis.y 0 | -//| xaxis.z yaxis.z zaxis.z 0 | -//| dot(xaxis,eye) dot(yaxis,eye) dot(zaxis,eye) 1 | -//+------------------------------------------------------------------+ -void DXMatrixLookAtRH(DXMatrix &out,const DXVector3 &eye,const DXVector3 &at,const DXVector3 &up) - { - DXVector3 right,upn,vec; - DXVec3Subtract(vec,at,eye); - DXVec3Normalize(vec,vec); - DXVec3Cross(right,up,vec); - DXVec3Cross(upn,vec,right); - DXVec3Normalize(right,right); - DXVec3Normalize(upn,upn); -//--- - out.m[0][0] = -right.x; - out.m[1][0] = -right.y; - out.m[2][0] = -right.z; - out.m[3][0] = DXVec3Dot(right,eye); - out.m[0][1] = upn.x; - out.m[1][1] = upn.y; - out.m[2][1] = upn.z; - out.m[3][1] = -DXVec3Dot(upn,eye); - out.m[0][2] = -vec.x; - out.m[1][2] = -vec.y; - out.m[2][2] = -vec.z; - out.m[3][2] = DXVec3Dot(vec,eye); - out.m[0][3] = 0.0f; - out.m[1][3] = 0.0f; - out.m[2][3] = 0.0f; - out.m[3][3] = 1.0f; - } -//+------------------------------------------------------------------+ -//| Determines the product of two matrices. | -//+------------------------------------------------------------------+ -void DXMatrixMultiply(DXMatrix &pout,const DXMatrix &pm1,const DXMatrix &pm2) - { - DXMatrix out= {}; - for(int i=0; i<4; i++) - { - for(int j=0; j<4; j++) - { - out.m[i][j] = pm1.m[i][0]*pm2.m[0][j] + pm1.m[i][1]*pm2.m[1][j] + pm1.m[i][2]*pm2.m[2][j] + pm1.m[i][3]*pm2.m[3][j]; - } - } - pout = out; - } -//+------------------------------------------------------------------+ -//| Calculates the transposed product of two matrices. | -//+------------------------------------------------------------------+ -void DXMatrixMultiplyTranspose(DXMatrix &pout,const DXMatrix &pm1,const DXMatrix &pm2) - { - DXMatrix temp= {}; - for(int i = 0; i < 4; i++) - for(int j = 0; j < 4; j++) - temp.m[j][i] = pm1.m[i][0]*pm2.m[0][j] + pm1.m[i][1]*pm2.m[1][j] + pm1.m[i][2]*pm2.m[2][j] + pm1.m[i][3]*pm2.m[3][j]; - pout = temp; - } -//+------------------------------------------------------------------+ -//| Builds a left-handed orthographic projection matrix. | -//+------------------------------------------------------------------+ -void DXMatrixOrthoLH(DXMatrix &pout,float w,float h,float zn,float zf) - { - DXMatrixIdentity(pout); -//--- - pout.m[0][0] = 2.0f/w; - pout.m[1][1] = 2.0f/h; - pout.m[2][2] = 1.0f/(zf - zn); - pout.m[3][2] = zn/(zn - zf); - } -//+------------------------------------------------------------------+ -//| Builds a customized,left-handed orthographic projection matrix. | -//+------------------------------------------------------------------+ -void DXMatrixOrthoOffCenterLH(DXMatrix &pout,float l,float r,float b,float t,float zn,float zf) - { - DXMatrixIdentity(pout); -//--- - pout.m[0][0] = 2.0f/(r - l); - pout.m[1][1] = 2.0f/(t - b); - pout.m[2][2] = 1.0f/(zf -zn); - pout.m[3][0] = -1.0f -2.0f*l/(r - l); - pout.m[3][1] = 1.0f + 2.0f*t/(b - t); - pout.m[3][2] = zn/(zn -zf); - } -//+------------------------------------------------------------------+ -//| Builds a customized,right-handed orthographic projection matrix. | -//+------------------------------------------------------------------+ -void DXMatrixOrthoOffCenterRH(DXMatrix &pout,float l,float r,float b,float t,float zn,float zf) - { - DXMatrixIdentity(pout); -//--- - pout.m[0][0] = 2.0f/(r - l); - pout.m[1][1] = 2.0f/(t - b); - pout.m[2][2] = 1.0f/(zn -zf); - pout.m[3][0] = -1.0f -2.0f*l/(r - l); - pout.m[3][1] = 1.0f + 2.0f*t/(b - t); - pout.m[3][2] = zn/(zn -zf); - } -//+------------------------------------------------------------------+ -//| Builds a right-handed orthographic projection matrix. | -//+------------------------------------------------------------------+ -//| All the parameters of the DXMatrixOrthoRH function | -//| are distances in camera space. The parameters describe | -//| the dimensions of the view volume. | -//| | -//| This function uses the following formula to compute | -//| the returned matrix: | -//| 2/w 0 0 0 | -//| 0 2/h 0 0 | -//| 0 0 1/(zn-zf) 0 | -//| 0 0 zn/(zn-zf) 1 | -//+------------------------------------------------------------------+ -void DXMatrixOrthoRH(DXMatrix &pout,float w,float h,float zn,float zf) - { - DXMatrixIdentity(pout); - pout.m[0][0] = 2.0f/w; - pout.m[1][1] = 2.0f/h; - pout.m[2][2] = 1.0f/(zn - zf); - pout.m[3][2] = zn/(zn - zf); - } -//+------------------------------------------------------------------+ -//| Builds a left-handed perspective projection matrix | -//| based on a field of view. | -//+------------------------------------------------------------------+ -//| This function computes the returned matrix as shown: | -//| xScale 0 0 0 | -//| 0 yScale 0 0 | -//| 0 0 zf/(zf-zn) 1 | -//| 0 0 -zn*zf/(zf-zn) 0 | -//| where: | -//| yScale = cot(fovY/2) | -//| xScale = yScale / aspect ratio | -//+------------------------------------------------------------------+ -void DXMatrixPerspectiveFovLH(DXMatrix &pout,float fovy,float aspect,float zn,float zf) - { - DXMatrixIdentity(pout); -//--- - pout.m[0][0] = 1.0f/(aspect*(float)tan(fovy/2.0f)); - pout.m[1][1] = 1.0f/(float)tan(fovy/2.0f); - pout.m[2][2] = zf/(zf - zn); - pout.m[2][3] = 1.0f; - pout.m[3][2] = (zf*zn)/(zn - zf); - pout.m[3][3] = 0.0f; - } -//+------------------------------------------------------------------+ -//| Builds a right-handed perspective projection matrix | -//| based on a field of view. | -//+------------------------------------------------------------------+ -//| This function computes the returned matrix as shown. | -//| xScale 0 0 0 | -//| 0 yScale 0 0 | -//| 0 0 zf/(zn-zf) -1 | -//| 0 0 zn*zf/(zn-zf) 0 | -//| where: | -//| yScale = cot(fovY/2) | -//| xScale = yScale / aspect ratio | -//+------------------------------------------------------------------+ -void DXMatrixPerspectiveFovRH(DXMatrix &pout,float fovy,float aspect,float zn,float zf) - { - DXMatrixIdentity(pout); -//--- - pout.m[0][0] = 1.0f/(aspect*(float)tan(fovy/2.0f)); - pout.m[1][1] = 1.0f/(float)tan(fovy/2.0f); - pout.m[2][2] = zf/(zn - zf); - pout.m[2][3] = -1.0f; - pout.m[3][2] = (zf*zn)/(zn - zf); - pout.m[3][3] = 0.0f; - } -//+------------------------------------------------------------------+ -//| Builds a left-handed perspective projection matrix | -//+------------------------------------------------------------------+ -//| This function uses the following formula to compute | -//| the returned matrix. | -//| 2*zn/w 0 0 0 | -//| 0 2*zn/h 0 0 | -//| 0 0 zf/(zf-zn) 1 | -//| 0 0 zn*zf/(zn-zf) 0 | -//+------------------------------------------------------------------+ -void DXMatrixPerspectiveLH(DXMatrix &pout,float w,float h,float zn,float zf) - { - DXMatrixIdentity(pout); - pout.m[0][0] = 2.0f*zn/w; - pout.m[1][1] = 2.0f*zn/h; - pout.m[2][2] = zf/(zf - zn); - pout.m[3][2] = (zn*zf)/(zn - zf); - pout.m[2][3] = 1.0f; - pout.m[3][3] = 0.0f; - } -//+------------------------------------------------------------------+ -//| Builds a customized, left-handed perspective projection matrix. | -//+------------------------------------------------------------------+ -//| All the parameters of the DXMatrixPerspectiveOffCenterLH | -//| function are distances in camera space. The parameters describe | -//| the dimensions of the view volume. | -//| | -//| This function uses the following formula to compute | -//| the returned matrix. | -//| 2*zn/(r-l) 0 0 0 | -//| 0 2*zn/(t-b) 0 0 | -//| (l+r)/(l-r) (t+b)/(b-t) zf/(zf-zn) 1 | -//| 0 0 zn*zf/(zn-zf) 0 | -//+------------------------------------------------------------------+ -void DXMatrixPerspectiveOffCenterLH(DXMatrix &pout,float l,float r,float b,float t,float zn,float zf) - { - DXMatrixIdentity(pout); -//--- - pout.m[0][0] = 2.0f*zn/(r - l); - pout.m[1][1] = -2.0f*zn/(b - t); - pout.m[2][0] = -1.0f - 2.0f*l/(r - l); - pout.m[2][1] = 1.0f + 2.0f*t/(b - t); - pout.m[2][2] = - zf/(zn - zf); - pout.m[3][2] = (zn*zf)/(zn -zf); - pout.m[2][3] = 1.0f; - pout.m[3][3] = 0.0f; - } -//+------------------------------------------------------------------+ -//| Builds a customized, right-handed perspective projection matrix. | -//+------------------------------------------------------------------+ -//| All the parameters of the DXMatrixPerspectiveOffCenterRH | -//| function are distances in camera space. The parameters describe | -//| the dimensions of the view volume. | -//| | -//| This function uses the following formula to compute | -//| the returned matrix. | -//| 2*zn/(r-l) 0 0 0 | -//| 0 2*zn/(t-b) 0 0 | -//| (l+r)/(r-l) (t+b)/(t-b) zf/(zn-zf) -1 | -//| 0 0 zn*zf/(zn-zf) 0 | -//+------------------------------------------------------------------+ -void DXMatrixPerspectiveOffCenterRH(DXMatrix &pout,float l,float r,float b,float t,float zn,float zf) - { - DXMatrixIdentity(pout); -//--- - pout.m[0][0] = 2.0f*zn/(r - l); - pout.m[1][1] = -2.0f*zn/(b - t); - pout.m[2][0] = 1.0f + 2.0f*l/(r - l); - pout.m[2][1] = -1.0f -2.0f*t/(b - t); - pout.m[2][2] = zf/(zn - zf); - pout.m[3][2] = (zn*zf)/(zn -zf); - pout.m[2][3] = -1.0f; - pout.m[3][3] = 0.0f; - } -//+------------------------------------------------------------------+ -//| Builds a right-handed perspective projection matrix. | -//+------------------------------------------------------------------+ -//| All the parameters of the DXMatrixPerspectiveRH function | -//| are distances in camera space. The parameters describe | -//| the dimensions of the view volume. | -//| | -//| This function uses the following formula to compute | -//| the returned matrix. | -//| 2*zn/w 0 0 0 | -//| 0 2*zn/h 0 0 | -//| 0 0 zf/(zn-zf) -1 | -//| 0 0 zn*zf/(zn-zf) 0 | -//+------------------------------------------------------------------+ -void DXMatrixPerspectiveRH(DXMatrix &pout,float w,float h,float zn,float zf) - { - DXMatrixIdentity(pout); -//--- - pout.m[0][0] = 2.0f*zn/w; - pout.m[1][1] = 2.0f*zn/h; - pout.m[2][2] = zf/(zn - zf); - pout.m[3][2] = (zn*zf)/(zn - zf); - pout.m[2][3] = -1.0f; - pout.m[3][3] = 0.0f; - } -//+------------------------------------------------------------------+ -//| Builds a matrix that reflects the coordinate system about a plane| -//| This function normalizes the plane equation before it creates | -//| the reflected matrix. | -//| | -//| This function uses the following formula to compute | -//| the returned matrix. | -//| P = normalize(Plane); | -//| -2 * P.a * P.a + 1 -2 * P.b * P.a -2 * P.c * P.a 0 | -//| -2 * P.a * P.b -2 * P.b * P.b + 1 -2 * P.c * P.b 0 | -//| -2 * P.a * P.c -2 * P.b * P.c -2 * P.c * P.c + 1 0 | -//| -2 * P.a * P.d -2 * P.b * P.d -2 * P.c * P.d 1 | -//+------------------------------------------------------------------+ -void DXMatrixReflect(DXMatrix &pout,const DXPlane &pplane) - { - DXPlane Nplane; - DXPlaneNormalize(Nplane,pplane); - DXMatrixIdentity(pout); -//--- - pout.m[0][0] = 1.0f - 2.0f*Nplane.a*Nplane.a; - pout.m[0][1] = -2.0f*Nplane.a*Nplane.b; - pout.m[0][2] = -2.0f*Nplane.a*Nplane.c; - pout.m[1][0] = -2.0f*Nplane.a*Nplane.b; - pout.m[1][1] = 1.0f - 2.0f*Nplane.b*Nplane.b; - pout.m[1][2] = -2.0f*Nplane.b*Nplane.c; - pout.m[2][0] = -2.0f*Nplane.c*Nplane.a; - pout.m[2][1] = -2.0f*Nplane.c*Nplane.b; - pout.m[2][2] = 1.0f - 2.0f*Nplane.c*Nplane.c; - pout.m[3][0] = -2.0f*Nplane.d*Nplane.a; - pout.m[3][1] = -2.0f*Nplane.d*Nplane.b; - pout.m[3][2] = -2.0f*Nplane.d*Nplane.c; - } -//+------------------------------------------------------------------+ -//| Builds a matrix that rotates around an arbitrary axis. | -//+------------------------------------------------------------------+ -void DXMatrixRotationAxis(DXMatrix &out,const DXVector3 &v,float angle) - { - DXVector3 nv; - DXVec3Normalize(nv,v); -//--- - float sangle = (float)sin(angle); - float cangle = (float)cos(angle); - float cdiff = 1.0f - cangle; -//--- - out.m[0][0] = cdiff*nv.x*nv.x + cangle; - out.m[1][0] = cdiff*nv.x*nv.y - sangle*nv.z; - out.m[2][0] = cdiff*nv.x*nv.z + sangle*nv.y; - out.m[3][0] = 0.0f; - out.m[0][1] = cdiff*nv.y*nv.x + sangle*nv.z; - out.m[1][1] = cdiff*nv.y*nv.y + cangle; - out.m[2][1] = cdiff*nv.y*nv.z - sangle*nv.x; - out.m[3][1] = 0.0f; - out.m[0][2] = cdiff*nv.z*nv.x - sangle*nv.y; - out.m[1][2] = cdiff*nv.z*nv.y + sangle*nv.x; - out.m[2][2] = cdiff*nv.z*nv.z + cangle; - out.m[3][2] = 0.0f; - out.m[0][3] = 0.0f; - out.m[1][3] = 0.0f; - out.m[2][3] = 0.0f; - out.m[3][3] = 1.0f; - } -//+------------------------------------------------------------------+ -//| Builds a rotation matrix from a quaternion. | -//+------------------------------------------------------------------+ -void DXMatrixRotationQuaternion(DXMatrix &pout,const DXQuaternion &pq) - { - DXMatrixIdentity(pout); -//--- - pout.m[0][0] = 1.0f - 2.0f*(pq.y*pq.y + pq.z*pq.z); - pout.m[0][1] = 2.0f*(pq.x*pq.y + pq.z*pq.w); - pout.m[0][2] = 2.0f*(pq.x*pq.z - pq.y*pq.w); - pout.m[1][0] = 2.0f*(pq.x*pq.y - pq.z*pq.w); - pout.m[1][1] = 1.0f - 2.0f * (pq.x*pq.x + pq.z*pq.z); - pout.m[1][2] = 2.0f*(pq.y*pq.z + pq.x*pq.w); - pout.m[2][0] = 2.0f*(pq.x*pq.z + pq.y*pq.w); - pout.m[2][1] = 2.0f*(pq.y*pq.z - pq.x*pq.w); - pout.m[2][2] = 1.0f - 2.0f*(pq.x*pq.x + pq.y*pq.y); - } -//+------------------------------------------------------------------+ -//| Builds a matrix that rotates around the x-axis. | -//+------------------------------------------------------------------+ -void DXMatrixRotationX(DXMatrix &pout,float angle) - { - DXMatrixIdentity(pout); -//--- - pout.m[1][1] = (float)cos(angle); - pout.m[2][2] = (float)cos(angle); - pout.m[1][2] = (float)sin(angle); - pout.m[2][1] = -(float)sin(angle); - } -//+------------------------------------------------------------------+ -//| Builds a matrix that rotates around the y-axis. | -//+------------------------------------------------------------------+ -void DXMatrixRotationY(DXMatrix &pout,float angle) - { - DXMatrixIdentity(pout); -//--- - pout.m[0][0] = (float)cos(angle); - pout.m[2][2] = (float)cos(angle); - pout.m[0][2] = -(float)sin(angle); - pout.m[2][0] = (float)sin(angle); - } -//+------------------------------------------------------------------+ -//| Builds a matrix with a specified yaw, pitch, and roll. | -//+------------------------------------------------------------------+ -//| The order of transformations is roll first, then pitch, then yaw.| -//| Relative to the object's local coordinate axis, this is | -//| equivalent to rotation around the z-axis, followed by rotation | -//| around the x-axis, followed by rotation around the y-axis. | -//+------------------------------------------------------------------+ -void DXMatrixRotationYawPitchRoll(DXMatrix &out,float yaw,float pitch,float roll) - { - float sroll = (float)sin(roll); - float croll = (float)cos(roll); - float spitch = (float)sin(pitch); - float cpitch = (float)cos(pitch); - float syaw = (float)sin(yaw); - float cyaw = (float)cos(yaw); -//--- - out.m[0][0] = sroll * spitch * syaw + croll * cyaw; - out.m[0][1] = sroll * cpitch; - out.m[0][2] = sroll * spitch * cyaw - croll * syaw; - out.m[0][3] = 0.0f; - out.m[1][0] = croll * spitch * syaw - sroll * cyaw; - out.m[1][1] = croll * cpitch; - out.m[1][2] = croll * spitch * cyaw + sroll * syaw; - out.m[1][3] = 0.0f; - out.m[2][0] = cpitch * syaw; - out.m[2][1] = -spitch; - out.m[2][2] = cpitch * cyaw; - out.m[2][3] = 0.0f; - out.m[3][0] = 0.0f; - out.m[3][1] = 0.0f; - out.m[3][2] = 0.0f; - out.m[3][3] = 1.0f; - } -//+------------------------------------------------------------------+ -//| Builds a matrix that rotates around the z-axis. | -//+------------------------------------------------------------------+ -void DXMatrixRotationZ(DXMatrix &pout,float angle) - { - DXMatrixIdentity(pout); -//--- - pout.m[0][0] = (float)cos(angle); - pout.m[1][1] = (float)cos(angle); - pout.m[0][1] = (float)sin(angle); - pout.m[1][0] = -(float)sin(angle); - } -//+------------------------------------------------------------------+ -//| Builds a matrix that scales along the x-axis, | -//| the y-axis,and the z-axis. | -//+------------------------------------------------------------------+ -void DXMatrixScaling(DXMatrix &pout,float sx,float sy,float sz) - { - DXMatrixIdentity(pout); - pout.m[0][0] = sx; - pout.m[1][1] = sy; - pout.m[2][2] = sz; - } -//+------------------------------------------------------------------+ -//| Builds a matrix that flattens geometry into a plane. | -//+------------------------------------------------------------------+ -//| The DXMatrixShadow function flattens geometry into a plane, as | -//| if casting a shadow from a light. | -//| This function uses the following formula to compute the returned | -//| matrix. | -//| | -//| P = normalize(Plane); | -//| L = Light; | -//| d = -dot(P,L) | -//| | -//| P.a * L.x + d P.a * L.y P.a * L.z P.a * L.w | -//| P.b * L.x P.b * L.y + d P.b * L.z P.b * L.w | -//| P.c * L.x P.c * L.y P.c * L.z + d P.c * L.w | -//| P.d * L.x P.d * L.y P.d * L.z P.d * L.w + d | -//| | -//| If the light's w-component is 0, the ray from the origin to the | -//| light represents a directional light. If it is 1,the light is | -//| a point light. | -//+------------------------------------------------------------------+ -void DXMatrixShadow(DXMatrix &pout,const DXVector4 &plight,const DXPlane &pplane) - { - DXPlane Nplane; - DXPlaneNormalize(Nplane,pplane); - float dot = DXPlaneDot(Nplane,plight); -//--- - pout.m[0][0] = dot - Nplane.a*plight.x; - pout.m[0][1] = -Nplane.a*plight.y; - pout.m[0][2] = -Nplane.a*plight.z; - pout.m[0][3] = -Nplane.a*plight.w; - pout.m[1][0] = -Nplane.b*plight.x; - pout.m[1][1] = dot - Nplane.b*plight.y; - pout.m[1][2] = -Nplane.b*plight.z; - pout.m[1][3] = -Nplane.b*plight.w; - pout.m[2][0] = -Nplane.c*plight.x; - pout.m[2][1] = -Nplane.c*plight.y; - pout.m[2][2] = dot - Nplane.c*plight.z; - pout.m[2][3] = -Nplane.c*plight.w; - pout.m[3][0] = -Nplane.d*plight.x; - pout.m[3][1] = -Nplane.d*plight.y; - pout.m[3][2] = -Nplane.d*plight.z; - pout.m[3][3] = dot - Nplane.d*plight.w; - } -//+------------------------------------------------------------------+ -//| Builds a transformation matrix. | -//+------------------------------------------------------------------+ -//| This function calculates the transformation matrix with the | -//| following formula, with matrix concatenation evaluated | -//| in left-to-right order: | -//| | -//| Mout = (Msc)^(-1)*(Msr)^(-1)*Ms*Msr*Msc*(Mrc)^(-1)*Mr*Mrc*Mt | -//| | -//| where: | -//| Mout = output matrix (pOut) | -//| Msc = scaling center matrix (pScalingCenter) | -//| Msr = scaling rotation matrix (pScalingRotation) | -//| Ms = scaling matrix (pScaling) | -//| Mrc = center of rotation matrix (pRotationCenter) | -//| Mr = rotation matrix (pRotation) | -//| Mt = translation matrix (pTranslation) | -//+------------------------------------------------------------------+ -void DXMatrixTransformation(DXMatrix &pout,const DXVector3 &pscalingcenter,const DXQuaternion &pscalingrotation,const DXVector3 &pscaling,const DXVector3 &protationcenter,const DXQuaternion &protation,const DXVector3 &ptranslation) - { - DXMatrix m1,m2,m3,m4,m5,m6,m7; - DXQuaternion prc; - DXVector3 psc,pt; -//--- pscalingcenter - psc.x = pscalingcenter.x; - psc.y = pscalingcenter.y; - psc.z = pscalingcenter.z; -//--- protationcenter - prc.x = protationcenter.x; - prc.y = protationcenter.y; - prc.z = protationcenter.z; -//--- ptranslation - pt.x = ptranslation.x; - pt.y = ptranslation.y; - pt.z = ptranslation.z; - DXMatrixTranslation(m1,-psc.x,-psc.y,-psc.z); -//--- - DXQuaternion temp; - DXMatrixRotationQuaternion(m4,pscalingrotation); - temp.w = pscalingrotation.w; - temp.x = -pscalingrotation.x; - temp.y = -pscalingrotation.y; - temp.z = -pscalingrotation.z; - DXMatrixRotationQuaternion(m2,temp); -//--- pscaling - DXMatrixScaling(m3,pscaling.x,pscaling.y,pscaling.z); -//--- protation - DXMatrixRotationQuaternion(m6,protation); -//--- - DXMatrixTranslation(m5,psc.x - prc.x,psc.y - prc.y,psc.z - prc.z); - DXMatrixTranslation(m7,prc.x + pt.x,prc.y + pt.y,prc.z + pt.z); - DXMatrixMultiply(m1,m1,m2); - DXMatrixMultiply(m1,m1,m3); - DXMatrixMultiply(m1,m1,m4); - DXMatrixMultiply(m1,m1,m5); - DXMatrixMultiply(m1,m1,m6); - DXMatrixMultiply(pout,m1,m7); - } -//+------------------------------------------------------------------+ -//| Builds a 2D transformation matrix that represents | -//| transformations in the xy plane. | -//+------------------------------------------------------------------+ -//| This function calculates the transformation matrix with the | -//| following formula, with matrix concatenation evaluated | -//| in left-to-right order: | -//| | -//| Mout = (Msc)^(-1)*(Msr)^(-1)*Ms*Msr*Msc*(Mrc)^(-1)*Mr*Mrc*Mt | -//| | -//| where: | -//| Mout = output matrix (pOut) | -//| Msc = scaling center matrix (pScalingCenter) | -//| Msr = scaling rotation matrix (pScalingRotation) | -//| Ms = scaling matrix (pScaling) | -//| Mrc = center of rotation matrix (pRotationCenter) | -//| Mr = rotation matrix (Rotation) | -//| Mt = translation matrix (pTranslation) | -//+------------------------------------------------------------------+ -void DXMatrixTransformation2D(DXMatrix &pout,const DXVector2 &pscalingcenter,float scalingrotation,const DXVector2 &pscaling,const DXVector2 &protationcenter,float rotation,const DXVector2 &ptranslation) - { - DXQuaternion rot,sca_rot; - DXVector3 rot_center,sca,sca_center,trans; -//--- pscalingcenter - sca_center.x=pscalingcenter.x; - sca_center.y=pscalingcenter.y; - sca_center.z=0.0f; -//--- pscaling - sca.x=pscaling.x; - sca.y=pscaling.y; - sca.z=1.0f; -//--- protationcenter - rot_center.x=protationcenter.x; - rot_center.y=protationcenter.y; - rot_center.z=0.0f; -//--- ptranslation - trans.x=ptranslation.x; - trans.y=ptranslation.y; - trans.z=0.0f; -//--- - rot.w=(float)cos(rotation/2.0f); - rot.x=0.0f; - rot.y=0.0f; - rot.z=(float)sin(rotation/2.0f); -//--- - sca_rot.w=(float)cos(scalingrotation/2.0f); - sca_rot.x=0.0f; - sca_rot.y=0.0f; - sca_rot.z=(float)sin(scalingrotation/2.0f); - DXMatrixTransformation(pout,sca_center,sca_rot,sca,rot_center,rot,trans); - } -//+------------------------------------------------------------------+ -//| Builds a matrix using the specified offsets. | -//+------------------------------------------------------------------+ -void DXMatrixTranslation(DXMatrix &pout,float x,float y,float z) - { - DXMatrixIdentity(pout); -//--- - pout.m[3][0] = x; - pout.m[3][1] = y; - pout.m[3][2] = z; - } -//+------------------------------------------------------------------+ -//| Returns the matrix transpose of a matrix. | -//+------------------------------------------------------------------+ -void DXMatrixTranspose(DXMatrix &pout,const DXMatrix &pm) - { - const DXMatrix m = pm; - for(int i=0; i<4; i++) - for(int j=0; j<4; j++) - pout.m[i][j] = m.m[j][i]; - } -//+------------------------------------------------------------------+ -//| Computes the dot product of a plane and a 4D vector. | -//+------------------------------------------------------------------+ -float DXPlaneDot(const DXPlane &p1,const DXVector4 &p2) - { - return(p1.a*p2.x + p1.b*p2.y + p1.c*p2.z + p1.d*p2.w); - } -//+------------------------------------------------------------------+ -//| Computes the dot product of a plane and a 3D vector. | -//| The w parameter of the vector is assumed to be 1. | -//+------------------------------------------------------------------+ -float DXPlaneDotCoord(const DXPlane &pp,const DXVector4 &pv) - { - return(pp.a*pv.x + pp.b*pv.y + pp.c*pv.z + pp.d); - } -//+------------------------------------------------------------------+ -//| Computes the dot product of a plane and a 3D vector. | -//| The w parameter of the vector is assumed to be 0. | -//+------------------------------------------------------------------+ -float DXPlaneDotNormal(const DXPlane &pp,const DXVector4 &pv) - { - return(pp.a*pv.x + pp.b*pv.y + pp.c*pv.z); - } -//+------------------------------------------------------------------+ -//| Constructs a plane from a point and a normal. | -//+------------------------------------------------------------------+ -void DXPlaneFromPointNormal(DXPlane &pout,const DXVector3 &pvpoint,const DXVector3 &pvnormal) - { - pout.a = pvnormal.x; - pout.b = pvnormal.y; - pout.c = pvnormal.z; - pout.d = -DXVec3Dot(pvpoint,pvnormal); - } -//+------------------------------------------------------------------+ -//| Constructs a plane from three points. | -//+------------------------------------------------------------------+ -void DXPlaneFromPoints(DXPlane &pout,const DXVector3 &pv1,const DXVector3 &pv2,const DXVector3 &pv3) - { - DXVector3 edge1,edge2,normal,Nnormal; -//--- - edge1.x = 0.0f; - edge1.y = 0.0f; - edge1.z = 0.0f; - edge2.x = 0.0f; - edge2.y = 0.0f; - edge2.z = 0.0f; -//--- - DXVec3Subtract(edge1,pv2,pv1); - DXVec3Subtract(edge2,pv3,pv1); - DXVec3Cross(normal,edge1,edge2); - DXVec3Normalize(Nnormal,normal); - DXPlaneFromPointNormal(pout,pv1,Nnormal); - } -//+------------------------------------------------------------------+ -//| Finds the intersection between a plane and a line. | -//| If the line is parallel to the plane, null vector is returned. | -//+------------------------------------------------------------------+ -void DXPlaneIntersectLine(DXVector3 &pout,const DXPlane &pp,const DXVector3 &pv1,const DXVector3 &pv2) - { - DXVector3 direction,normal; - normal.x = pp.a; - normal.y = pp.b; - normal.z = pp.c; - direction.x = pv2.x - pv1.x; - direction.y = pv2.y - pv1.y; - direction.z = pv2.z - pv1.z; -//--- - float dot = DXVec3Dot(normal,direction); - if(!dot) - { - pout.x=0.0f; - pout.y=0.0f; - pout.z=0.0f; - } - float temp = (pp.d + DXVec3Dot(normal,pv1))/dot; - pout.x = pv1.x - temp*direction.x; - pout.y = pv1.y - temp*direction.y; - pout.z = pv1.z - temp*direction.z; - } -//+------------------------------------------------------------------+ -//| Normalizes the plane coefficients so that the plane normal | -//| has unit length. | -//| This function normalizes a plane so that |a,b,c| == 1. | -//+------------------------------------------------------------------+ -void DXPlaneNormalize(DXPlane &out,const DXPlane &p) - { - float norm = (float)sqrt(p.a*p.a + p.b*p.b + p.c*p.c); - if(norm) - { - out.a = p.a/norm; - out.b = p.b/norm; - out.c = p.c/norm; - out.d = p.d/norm; - } - else - { - out.a = 0.0f; - out.b = 0.0f; - out.c = 0.0f; - out.d = 0.0f; - } - } -//+------------------------------------------------------------------+ -//| Scale the plane with the given scaling factor. | -//+------------------------------------------------------------------+ -void DXPlaneScale(DXPlane &pout,const DXPlane &p,float s) - { - pout.a = p.a*s; - pout.b = p.b*s; - pout.c = p.c*s; - pout.d = p.d*s; - }; -//+------------------------------------------------------------------+ -//| Transforms a plane by a matrix. | -//| The input matrix is the inverse transpose of the actual | -//| transformation. | -//+------------------------------------------------------------------+ -void DXPlaneTransform(DXPlane &pout,const DXPlane &pplane,const DXMatrix &pm) - { - DXPlane plane = pplane; -//--- - pout.a = pm.m[0][0]*plane.a + pm.m[1][0]*plane.b + pm.m[2][0]*plane.c + pm.m[3][0]*plane.d; - pout.b = pm.m[0][1]*plane.a + pm.m[1][1]*plane.b + pm.m[2][1]*plane.c + pm.m[3][1]*plane.d; - pout.c = pm.m[0][2]*plane.a + pm.m[1][2]*plane.b + pm.m[2][2]*plane.c + pm.m[3][2]*plane.d; - pout.d = pm.m[0][3]*plane.a + pm.m[1][3]*plane.b + pm.m[2][3]*plane.c + pm.m[3][3]*plane.d; - } -//+------------------------------------------------------------------+ -//| Adds two spherical harmonic (SH) vectors; in other words, | -//| out[i] = a[i] + b[i]. | -//+------------------------------------------------------------------+ -//| Each coefficient of the basis function Y(l,m) is stored | -//| at memory location l^2 + m + l,where: | -//| l is the degree of the basis function. | -//| m is the basis function index for the given l value | -//| and ranges from -l to l, inclusive. | -//+------------------------------------------------------------------+ -void DXSHAdd(float &out[],int order,const float &a[],const float &b[]) - { - for(int i = 0; i DX_PI/2.0f) ? (DX_PI/2.0f) : radius; - float norm = (float)sin(clamped_angle)*(float)sin(clamped_angle); - if(order > DXSH_MAXORDER) - { - //--- order clamped at DXSH_MAXORDER - order = DXSH_MAXORDER; - } -//--- - weightedcapintegrale(cap,order,radius); - DXSHEvalDirection(rout,order,dir); -//--- - for(int i = 0; i DXSH_MAXORDER)) - return; - - out[0] = 0.5f/(float)sqrt(DX_PI); - out[1] = -0.5f/(float)sqrt(DX_PI/3.0f)*dir.y; - out[2] = 0.5f/(float)sqrt(DX_PI/3.0f)*dir.z; - out[3] = -0.5f/(float)sqrt(DX_PI/3.0f)*dir.x; - if(order == 2) - return; - - out[4] = 0.5f/(float)sqrt(DX_PI/15.0f)*dirxy; - out[5] = -0.5f/(float)sqrt(DX_PI/15.0f)*diryz; - out[6] = 0.25f/(float)sqrt(DX_PI/5.0f)*(3.0f*dirzz - 1.0f); - out[7] = -0.5f/(float)sqrt(DX_PI/15.0f)*dirxz; - out[8] = 0.25f/(float)sqrt(DX_PI/15.0f)*(dirxx - diryy); - if(order == 3) - return; - - out[9] = -(float)sqrt(70.0f/DX_PI)/8.0f*dir.y*(3.0f*dirxx - diryy); - out[10] = (float)sqrt(105.0f/DX_PI)/2.0f*dirxy*dir.z; - out[11] = -(float)sqrt(42.0f/DX_PI)/8.0f*dir.y*(-1.0f + 5.0f*dirzz); - out[12] = (float)sqrt(7.0f/DX_PI)/4.0f*dir.z*(5.0f*dirzz - 3.0f); - out[13] = (float)sqrt(42.0f/DX_PI)/8.0f*dir.x*(1.0f - 5.0f*dirzz); - out[14] = (float)sqrt(105.0f/DX_PI)/4.0f*dir.z*(dirxx - diryy); - out[15] = -(float)sqrt(70.0f/DX_PI)/8.0f*dir.x*(dirxx - 3.0f*diryy); - if(order == 4) - return; - - out[16] = 0.75f*float(sqrt(35.0f/DX_PI))*dirxy*(dirxx - diryy); - out[17] = 3.0f*dir.z*out[9]; - out[18] = 0.75f*(float)sqrt(5.0f/DX_PI)*dirxy*(7.0f*dirzz - 1.0f); - out[19] = 0.375f*(float)sqrt(10.0f/DX_PI)*diryz*(3.0f - 7.0f*dirzz); - out[20] = 3.0f/(16.0f*(float)sqrt(DX_PI))*(35.0f*dirzzzz - 30.f*dirzz + 3.0f); - out[21] = 0.375f*(float)sqrt(10.0f/DX_PI)*dirxz*(3.0f - 7.0f*dirzz); - out[22] = 0.375f*(float)sqrt(5.0f/DX_PI)*(dirxx - diryy)*(7.0f*dirzz - 1.0f); - out[23] = 3.0f*dir.z*out[15]; - out[24] = 3.0f / 16.0f*float(sqrt(35.0f/DX_PI))*(dirxxxx - 6.0f*dirxyxy + diryyyy); - if(order == 5) - return; - - out[25] = -3.0f/32.0f*(float)sqrt(154.0f/DX_PI)*dir.y*(5.0f*dirxxxx - 10.0f*dirxyxy + diryyyy); - out[26] = 0.75f*(float)sqrt(385.0f/DX_PI)*dirxy*dir.z*(dirxx - diryy); - out[27] = (float)sqrt(770.0f/DX_PI)/32.0f*dir.y*(3.0f*dirxx - diryy)*(1.0f - 9.0f*dirzz); - out[28] = (float)sqrt(1155.0f/DX_PI)/4.0f*dirxy*dir.z*(3.0f*dirzz - 1.0f); - out[29] = (float)sqrt(165.0f/DX_PI)/16.0f*dir.y*(14.0f*dirzz - 21.0f*dirzzzz - 1.0f); - out[30] = (float)sqrt(11.0f/DX_PI)/16.0f*dir.z*(63.0f*dirzzzz - 70.0f*dirzz + 15.0f); - out[31] = (float)sqrt(165.0f/DX_PI)/16.0f*dir.x*(14.0f*dirzz - 21.0f*dirzzzz - 1.0f); - out[32] = (float)sqrt(1155.0f/DX_PI)/8.0f*dir.z*(dirxx - diryy)*(3.0f*dirzz - 1.0f); - out[33] = (float)sqrt(770.0f/DX_PI)/32.0f*dir.x*(dirxx - 3.0f*diryy)*(1.0f - 9.0f*dirzz); - out[34] = 3.0f/16.0f*(float)sqrt(385.0f/DX_PI)*dir.z*(dirxxxx - 6.0f*dirxyxy + diryyyy); - out[35] = -3.0f/32.0f*(float)sqrt(154.0f/DX_PI)*dir.x*(dirxxxx - 10.0f*dirxyxy + 5.0f*diryyyy); - } -//+------------------------------------------------------------------+ -//| Evaluates a directional light and | -//| returns spectral spherical harmonic (SH) data. | -//+------------------------------------------------------------------+ -//| The output vector is computed so that if the intensity ratio | -//| R/G/B is equal to 1 ,the resulting exit radiance of a point | -//| directly under the light on a diffuse object with an albedo | -//| of 1 would be 1.0. This will compute three spectral samples; | -//| rout[], gout[] and bout[] will be returned. | -//+------------------------------------------------------------------+ -int DXSHEvalDirectionalLight(int order,const DXVector3 &dir,float Rintensity,float Gintensity,float Bintensity,float &rout[],float &gout[],float &bout[]) - { - float s = 0.75f; - if(order > 2) - s += 5.0f/16.0f; - if(order > 4) - s -= 3.0f/32.0f; - s /= DX_PI; - - DXSHEvalDirection(rout,order,dir); - for(int j=0; j DXSH_MAXORDER) - order = DXSH_MAXORDER; -//--- check radius - if(radius < 0.0f) - radius = -radius; - - float dist = DXVec3Length(dir); - float clamped_angle = (dist <= radius) ? DX_PI/2.0f : (float)asin(radius / dist); - - weightedcapintegrale(cap,order,clamped_angle); - DXVec3Normalize(normal,dir); - DXSHEvalDirection(rout,order,normal); - - for(int i=0; iDXSH_MAXORDER) || (order0; j--) - { - out[sum - j] = 0.0f; - out[sum - j] = c[j - 1]*in[sum - j]; - out[sum - j] += s[j - 1]*in[sum + j]; - } - out[sum] = in[sum]; - //--- - for(int j=1; j(); - if(m_buffer_object!=NULL) - { - m_buffer_object.AddRef(); - //--- use default vertex shader - m_shader_vertex=dispatcher.ShaderCreateDefault(DX_SHADER_VERTEX); - if(m_shader_vertex!=NULL) - { - m_shader_vertex.AddRef(); - //--- use default pixel shader - m_shader_pixel=dispatcher.ShaderCreateDefault(DX_SHADER_PIXEL); - if(m_shader_pixel!=NULL) - { - m_shader_pixel.AddRef(); - //--- create vertex buffer - m_buffer_vertex=dispatcher.VertexBufferCreate(vertices); - if(m_buffer_vertex!=NULL) - { - m_buffer_vertex.AddRef(); - //--- create index buffer - m_buffer_index=dispatcher.IndexBufferCreate(indices); - if(m_buffer_index!=NULL) - m_buffer_index.AddRef(); - } - } - } - } - //--- set object buffer to shaders - if(m_buffer_object==NULL || m_shader_vertex==NULL || m_shader_pixel==NULL || m_buffer_vertex==NULL || m_buffer_index==NULL) - { - Shutdown(); - return(false); - } - //--- save scene buffer - m_buffer_scene=buffer_scene; - m_buffer_scene.AddRef(); - //--- save topology - m_topology=topology; - //--- - return(true); - } - //+------------------------------------------------------------------+ - //| Create mesh object from OBJ mesh file | - //+------------------------------------------------------------------+ - bool Create(CDXDispatcher &dispatcher,CDXInput* buffer_scene,string obj_path,float scale=1.0f,bool inverse_winding=false) - { - DXVertex vertices[]; - uint indices[]; - //--- load model - if(!DXLoadObjModel(obj_path,vertices,indices,scale)) - return(false); - //--- set white vertices color - DXColor white=DXColor(1.0f,1.0f,1.0f,1.0f); - int count=ArraySize(vertices); - for(int i=0; imre#bi0kB6YdJF>rUz4D%)hIXtY)d7R9!JM)0SrZ?+v+N`n{@(`*XU zc6R2?o43>NuPUmjV7maTf_1DBO%)?J|GG|ajbpSB!Gnt~Uh%;EqZRNp@q!-S5yHnk zqs5H3haK$V09&+AnJH$*OZ4d(^Dg4kE82Iw8}d!aXAUGz$Ve{jRq!m&r(lhlF+$Ds zVn{T@l$8Mcv^vDpoxxKi{cMo&XJQPibX@8F<-7OM&RezKCMUSG2 zCPbfh4XV}UyZU#}soILfkMwmJUTWm6M+LO$@3Zg1qRpU88sX%_sG!F)mYhOSh)3Pj z%=3gb(UY9tMXQS&b1uZw!yA9=#$WTuzm3O^KOn-8JNm3F$j$P(Km#QVh}|dVvW0nC zn~i#w0|%R|EJ54AS!$ISr=E$FWlwerXC8AmaFJU1J4MmS*Tpdz?2{RDGJ2dPGIs+` zK8KfdLZ(ZLm-H?oGs>dY;?u80PGolnPedRLB;1F5qg9pXIME2|;acdmqP+Tl%Q)Se Z?Sf`h57%N^QOsu?Pih{g-6-03`UfF0>bC#@ diff --git a/Include/Canvas/DX/DXShader.mqh b/Include/Canvas/DX/DXShader.mqh deleted file mode 100644 index 34ce5cc1178b86c9001afbf6e648f5bce7f8bf57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16984 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 CdqPYA diff --git a/Include/Canvas/DX/DXSurface.mqh b/Include/Canvas/DX/DXSurface.mqh deleted file mode 100644 index d636aa1..0000000 --- a/Include/Canvas/DX/DXSurface.mqh +++ /dev/null @@ -1,162 +0,0 @@ -//+------------------------------------------------------------------+ -//| DXSurface.mqh | -//| Copyright 2019, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2019, MetaQuotes Software Corp." -#property link "https://www.mql5.com" -//--- -#include "DXMesh.mqh" -#include "DXMath.mqh" -#include "DXUtils.mqh" -//+------------------------------------------------------------------+ -//| 3D Box object | -//+------------------------------------------------------------------+ -class CDXSurface : public CDXMesh - { -public: - //--- surface creation flags - enum EN_SURFACE_FLAGS - { - SF_NONE =0x0, - SF_TWO_SIDED =0x1, - SF_USE_NORMALS =0x2, - }; - //--- surface color scheme - enum EN_COLOR_SCHEME - { - CS_NONE =0, - CS_JET =1, - CS_COLD_TO_HOT =2, - CS_RED_TO_GREEN=3 - }; - -protected: - uint m_data_width; - uint m_data_height; - uint m_flags; - EN_COLOR_SCHEME m_color_scheme; - -public: - CDXSurface(); - ~CDXSurface(); - //--- create bon in specified context - bool Create(CDXDispatcher &dispatcher,CDXInput* buffer_scene,double &data[],uint m_data_widht,uint m_data_height,float data_range,const DXVector3 &from,const DXVector3 &to,DXVector2 &texture_size,uint flags=SF_NONE,EN_COLOR_SCHEME color_scheme=CS_NONE); - //--- update box - bool Update(double &data[],uint m_data_widht,uint m_data_height,float data_range,const DXVector3 &from,const DXVector3 &to,DXVector2 &texture_size,uint flags=0,EN_COLOR_SCHEME color_scheme=CS_NONE); - -private: - //--- - void PrepareColors(DXVertex &vertices[],const DXVector3 &from,const DXVector3 &to); - }; -//+------------------------------------------------------------------+ -//| Class constructor | -//+------------------------------------------------------------------+ -void CDXSurface::CDXSurface() : CDXMesh() - { - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -void CDXSurface::~CDXSurface(void) - { - } -//+------------------------------------------------------------------+ -//| Create box in specified context | -//+------------------------------------------------------------------+ -bool CDXSurface::Create(CDXDispatcher &dispatcher,CDXInput* buffer_scene, - double &data[],uint data_width,uint data_height,float data_range, - const DXVector3 &from,const DXVector3 &to,DXVector2 &texture_size, - uint flags=SF_NONE,EN_COLOR_SCHEME color_scheme=CS_NONE) - { -//--- release previous buffers - Shutdown(); -//--- save parameters - m_data_width =data_width; - m_data_height =data_height; - m_flags =flags; - m_color_scheme=color_scheme; -//--- - DXVertex vertices[]; - uint indices[]; -//--- prepare surface vertices and indices - DXColor white=DXColor(1.0f,1.0f,1.0f,1.0f); - if(!DXComputeSurface(data,data_width,data_height,data_range,from,to,texture_size,flags&SF_TWO_SIDED,flags&SF_USE_NORMALS,vertices,indices)) - return(false); -//--- calculate colors - PrepareColors(vertices,from,to); -//--- create mesh - return(CDXMesh::Create(dispatcher,buffer_scene,vertices,indices)); - } -//+------------------------------------------------------------------+ -//| Update box bounds | -//+------------------------------------------------------------------+ -bool CDXSurface::Update(double &data[],uint data_width,uint data_height,float data_range, - const DXVector3 &from,const DXVector3 &to,DXVector2 &texture_size, - uint flags=0,EN_COLOR_SCHEME color_scheme=CS_NONE) - { -//--- - DXVertex vertices[]; - uint indices[]; -//--- prepare surface vertices and indices - DXColor white=DXColor(1.0f,1.0f,1.0f,1.0f); - if(!DXComputeSurface(data,data_width,data_height,data_range,from,to,texture_size,flags&SF_TWO_SIDED,flags&SF_USE_NORMALS,vertices,indices)) - return(false); -//--- calculate colors - m_color_scheme=color_scheme; - PrepareColors(vertices,from,to); -//--- update vertices - bool res=CDXMesh::VerticesSet(vertices); -//--- do not update indices if vertices relations are the same - if(m_data_width!=data_width || m_data_height!=data_height || (m_flags&SF_TWO_SIDED)!=(flags&SF_TWO_SIDED)) - res=res && CDXMesh::IndicesSet(indices); -//--- check result - if(!res) - { - Shutdown(); - return(false); - } -//--- save parameters - m_data_width =data_width; - m_data_height =data_height; - m_flags =flags; -//--- success - return(true); - } -//+------------------------------------------------------------------+ -//| Update box bounds | -//+------------------------------------------------------------------+ -void CDXSurface::PrepareColors(DXVertex &vertices[],const DXVector3 &from,const DXVector3 &to) - { - uint count=ArraySize(vertices); - float scale=1.0f/(fmax(FLT_EPSILON,to.y-from.y)); - switch(m_color_scheme) - { - case CS_JET: - { - for(uint i=0; i^$y0_uR+q_ixLxEQ_*Kg3qE{mP?RkS^;QX`Skf$y^Ig$}}Y|B1&OR?Wgxh^;4u2j)}j+0Vp%1fNuLu*g^7~Mkq1A0R| zp)84TpJVKF4ej5NXLdX(Yl;*5vSMs8gfzo3Djm6v)-Gf^4CE;jf35)WE@bQg*_Od@ zUTEc~z_g2z4#u2~=Z%H4EA9h#&OX6!U)}{hxAwt=9c9wqc~2dBQg*VcZuAdXK06=I zJJYkZO!$x&({Wh=Vn^W44raE&BZr^n&lWt|dT7hAfEb;cmR`9sd6pPYDiaRYs*WwI zCjO*|Gy`aynwWE5yPt2JWs8@pd{~`;4adM{0Lyn^@9gJmuBTNHMS57vO3Ywks>zNmiLa<|pRv8rxzSQGj%lQr?}qBX=nM|{Rjkn@hmIb{b( zrN}N#_#nsIz?!Si_bETCcA$5!fKN_mjbjCfbb(M}vM^f~$tof}{g+So@$?7?reISQ zd~z#VW~?awamW7>klB2t9dx<=d904_*UL$c%LXuyc|{N=+BFN z#l~G*+a^G{2LxI`r)?OvZOb0heaxgsK+Z+0B5ZlWpGGo7pbz9vfIB^;3k%Tu7-`A$7J7$h+wq?Hx7y`n z@q*&AAMzHpq5bqkpq##7#AbR6Yf zp&^gu1^nr`JjCs=A&=yaJi&Jp--q}%WLq}IGm8DE3iKI;n_!u1G4|@-DCl|g^&E{Y znG{DkjpV;k5%7jgt8{RKPUIGD&P%Ar>1)hvZD7dAK_2jS%xWP8?-P6ncz$F?$r*Y; z`1zkIf;Dh-8ys$!`(McE5IbE7Xbw96Pl7C49oHVLICNINI$=5Ux875;zqoR^_{t-U zIP|k!`3RlzqGlXZY7Y0lZQ=jvlV5MnKRu}V$bsx O>6dYoA{J$Or}qPl=t=GX diff --git a/Include/Canvas/DX/DXUtils.mqh b/Include/Canvas/DX/DXUtils.mqh deleted file mode 100644 index 9168473..0000000 --- a/Include/Canvas/DX/DXUtils.mqh +++ /dev/null @@ -1,942 +0,0 @@ -//+------------------------------------------------------------------+ -//| DXUtils.mqh | -//| Copyright 2019, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2019, MetaQuotes Software Corp." -#property link "https://www.mql5.com" -//--- -#include "DXMath.mqh" -#include "DXData.mqh" -//--- data types in Wavefront OBJ file format -#define OBJ_DATA_UNKNOWN 0 -#define OBJ_DATA_V 1 -#define OBJ_DATA_VT 2 -#define OBJ_DATA_VN 3 -#define OBJ_DATA_F 4 -//+------------------------------------------------------------------+ -//| OBJFaceType | -//+------------------------------------------------------------------+ -struct OBJFaceType - { - int total; - int v[4]; - int t[4]; - int n[4]; - }; -//+------------------------------------------------------------------+ -//| Transforms right to left hand system, or backward | -//| TVertex must have | -//| DXVector4 normal and DXVector2 tcoord members | -//+------------------------------------------------------------------+ -template -void DXInverseWinding(TVertex &vertices[],uint &indices[]) - { -//--- proccess vertices - uint count=ArraySize(vertices); - for(uint i=0; i0) - faces[idx].v[i]=(int)StringToInteger(str_parsed_faces[0]); - if(elements>1) - faces[idx].t[i]=(int)StringToInteger(str_parsed_faces[1]); - if(elements>2) - faces[idx].n[i]=(int)StringToInteger(str_parsed_faces[2]); - } - //--- debug message - if(show_debug) - printf("%face d: %d vertex(%d,%d,%d,%d) texture(%d,%d,%d,%d) normal(%d,%d,%d,%d)",idx+1, - faces[idx].v[0],faces[idx].v[1],faces[idx].v[2],faces[idx].v[3], - faces[idx].t[0],faces[idx].t[1],faces[idx].t[2],faces[idx].t[3], - faces[idx].n[0],faces[idx].n[1],faces[idx].n[2],faces[idx].n[3]); - //--- - break; - } - - default: - { - break; - } - } - } -//--- close the file - FileClose(file_handle); -//--- - if(show_debug) - { - printf("File %s loaded successfully. Total lines: %d",filename,total_lines); - printf("total v_positions=%d",total_positions); - printf("total v_normals=%d",total_normals); - printf("total v_tcoords=%d",total_tcoords); - printf("total faces=%d",total_faces); - } -//--- - return(true); - } -//+------------------------------------------------------------------+ -//| Load static 3D models from Maya 2011 | -//| https://en.wikibooks.org/wiki/DirectX/10.0/Direct3D/Loading_Maya | -//| TVertex must have | -//| DXVector4 position, normal and DXVector2 tcoord members | -//+------------------------------------------------------------------+ -template -bool DXLoadObjModel(const string filename,TVertex &vertices[],uint &indices[],float scale=1.0f) - { -//--- intermediate data arrays - DXVector4 v_positions[]; - DXVector2 v_tcoords[]; - DXVector4 v_normals[]; - OBJFaceType faces[]; -//--- load data - if(!DXLoadObjData(filename,v_positions,v_tcoords,v_normals,faces,false)) - { - printf("Error loading model data from %s",filename); - return(false); - } -//--- - int total_v_positions=ArraySize(v_positions); - int total_v_tcoords =ArraySize(v_tcoords); - int total_v_normals =ArraySize(v_normals); - int total_faces =ArraySize(faces); -//--- check faces - if(total_faces==0) - { - printf("No model data."); - return(false); - } -//--- check consistency of the indices - int vertices_count=0; - int indices_count =0; - bool split_vertices=false; - for(int i=0; i4) - { - printf("Error in %d face, face vertices count is %d",i,faces[i].total); - return(false); - } - //--- - for(int j=0; jtotal_v_positions) - { - printf("Error in %d face, %d vertext index is %d. Total posiitons=%d",i,j,faces[i].v[j],total_v_positions); - return(false); - } - if(total_v_tcoords>0) - { - if(faces[i].t[j]<=0 || faces[i].t[j]>total_v_tcoords) - { - printf("Error in %d face, %d tcoord index is %d. Total tcoords=%d",i,j,faces[i].v[j],total_v_positions); - return(false); - } - if(faces[i].t[j]!=faces[i].v[j]) - split_vertices=true; - } - if(total_v_normals>0) - { - if(faces[i].n[j]<=0 || faces[i].n[j]>total_v_normals) - { - printf("Error in %d face, %d normal index is %d. Total normals=%d",i,j,faces[i].v[j],total_v_positions); - return(false); - } - if(faces[i].n[j]!=faces[i].v[j]) - split_vertices=true; - } - } - //--- calc counts - vertices_count+=faces[i].total; - if(faces[i].total<4) - indices_count+=3; - else - indices_count+=6; - } - printf("Data consistency checked."); -//--- prepare arrays - if(!split_vertices) - vertices_count=total_v_positions; - ArrayResize(vertices,vertices_count); - ArrayResize(indices, indices_count); - int v_idx=0,i_idx=0; - for(int i=0; i -bool DXComputeBox(const DXVector3 &from,const DXVector3 &to,TVertex &vertices[],uint &indices[]) - { -//--- prepare arrays - const int faces=6; - if(ArrayResize(vertices,4*faces)!=4*faces) - return(false); -//--- set indices - uint ind[]= {0,1,2, 2,3,0, 4,5,6, 6,7,4, 8,9,10, 10,11,8, 12,13,14, 14,15,12, 16,17,18, 18,19,16, 20,21,22, 22,23,20}; - ArrayResize(indices,0); - if(ArrayCopy(indices,ind)!=ArraySize(ind)) - return(false); -//--- prepare boundaries - float left=from.x,right=to.x,bottom=from.y,top=to.y,near=from.z,far=to.z; - if(from.x>to.x) - { - right=from.x; - left= to.x; - } - if(from.y>to.y) - { - top= from.y; - bottom=to.y; - } - if(from.z>to.z) - { - far=from.z; - near=to.z; - } -//--- left face - vertices[0].position=DXVector4(left,top, far, 1.0); - vertices[1].position=DXVector4(left,top, near,1.0); - vertices[2].position=DXVector4(left,bottom,near,1.0); - vertices[3].position=DXVector4(left,bottom,far, 1.0); - for(int i=0; i<4; i++) - vertices[i].normal=DXVector4(-1.0,0.0,0.0,0.0); -//--- right face - vertices[4].position=DXVector4(right,top, near,1.0); - vertices[5].position=DXVector4(right,top, far, 1.0); - vertices[6].position=DXVector4(right,bottom,far, 1.0); - vertices[7].position=DXVector4(right,bottom,near,1.0); - for(int i=4; i<8; i++) - vertices[i].normal=DXVector4(1.0,0.0,0.0,0.0); -//--- front face - vertices[8].position =DXVector4(left, top, near,1.0); - vertices[9].position =DXVector4(right,top, near,1.0); - vertices[10].position=DXVector4(right,bottom,near,1.0); - vertices[11].position=DXVector4(left, bottom,near,1.0); - for(int i=8; i<12; i++) - vertices[i].normal=DXVector4(0.0,0.0,-1.0,0.0); -//--- back face - vertices[12].position=DXVector4(right,top, far,1.0); - vertices[13].position=DXVector4(left, top, far,1.0); - vertices[14].position=DXVector4(left, bottom,far,1.0); - vertices[15].position=DXVector4(right,bottom,far,1.0); - for(int i=12; i<16; i++) - vertices[i].normal=DXVector4(0.0,0.0,1.0,0.0); -//--- top face - vertices[16].position=DXVector4(left, top,far, 1.0); - vertices[17].position=DXVector4(right,top,far, 1.0); - vertices[18].position=DXVector4(right,top,near,1.0); - vertices[19].position=DXVector4(left, top,near,1.0); - for(int i=16; i<20; i++) - vertices[i].normal=DXVector4(0.0,1.0,0.0,0.0); -//--- bottom face - vertices[20].position=DXVector4(left, bottom,near,1.0); - vertices[21].position=DXVector4(right,bottom,near,1.0); - vertices[22].position=DXVector4(right,bottom,far, 1.0); - vertices[23].position=DXVector4(left, bottom,far, 1.0); - for(int i=20; i<24; i++) - vertices[i].normal=DXVector4(0.0,-1.0,0.0,0.0); -//--- texture coordinates - for(int i=0; i -bool DXComputeSphere(float radius,uint tessellation,TVertex &vertices[],uint &indices[]) - { - if(tessellation<3) - tessellation=3; - uint segments_y =tessellation; - uint segments_xz=tessellation*2; -//--- prepare arrays - uint count=(segments_y+1)*(segments_xz+1); - if(ArrayResize(vertices,count)!=count) - return(false); - count=6*segments_y*(segments_xz); - if(ArrayResize(indices,count)!=count) - return(false); -//--- create rings of vertices at progressively higher latitudes. - for(uint i=0,idx=0; i<=segments_y; i++) - { - DXVector2 tcoord=DXVector2(0.0f,1.0f-(float)i/segments_y); - float latitude=(i*DX_PI/segments_y)-DX_PI_DIV2; - float dy =(float)sin(latitude); - float dxz=(float)cos(latitude); - //--- create a single ring of vertices at this latitude. - for(uint j=0; j<=segments_xz; j++,idx++) - { - float longitude=(j%segments_xz)*DX_PI_MUL2/segments_xz; - //--- normal - DXVector3 normal=DXVector3((float)sin(longitude)*dxz,dy,(float)cos(longitude)*dxz); - vertices[idx].normal =DXVector4(normal.x,normal.y,normal.z,0.0); - //--- position - DXVec3Scale(normal,normal,radius); - vertices[idx].position=DXVector4(normal.x,normal.y,normal.z,1.0); - //--- texture coords - tcoord.x = float(j)/segments_xz; - vertices[idx].tcoord =tcoord; - } - } -//--- fill the index buffer with triangles joining each pair of latitude rings. - uint stride=segments_xz+1; - uint idx=0; - for(uint i=0; i -bool DXComputeTorus(float outer_radius,float inner_radius,uint tessellation,TVertex &vertices[],uint &indices[]) - { - if(tessellation<3) - tessellation=3; -//--- prepare arrays - uint count=(tessellation+1)*(tessellation+1); - if(ArrayResize(vertices,count)!=count) - return(false); - count=6*tessellation*tessellation; - if(ArrayResize(indices,count)!=count) - return(false); -//--- - uint v=0,idx=0; - uint stride=tessellation+1; -//--- first we loop around the main ring of the torus. - for(uint i=0; i<=tessellation; i++) - { - DXVector2 tcoord=DXVector2(float(i)/tessellation,0.0f); - //--- create a transform matrix that will align geometry to slice perpendicularly though the current ring position. - DXMatrix rotation,transform; - DXMatrixRotationY(rotation,-1.0f*(i%tessellation)*DX_PI_MUL2/tessellation-DX_PI_DIV2); - DXMatrixTranslation(transform,outer_radius,0.0f,0.0f); - DXMatrixMultiply(transform,transform,rotation); - //--- now we loop along the other axis, around the side of the tube. - for(uint j=0; j<=tessellation; j++) - { - //--- calc normal and position - float angle=(j%tessellation)*DX_PI_MUL2/tessellation+DX_PI; - vertices[v].normal=DXVector4((float)cos(angle),(float)sin(angle),0.0f,0.0f); - vertices[v].position=DXVector4(vertices[v].normal.x*inner_radius,vertices[v].normal.y*inner_radius,0.0f,1.0f); - DXVec4Transform(vertices[v].normal, vertices[v].normal, transform); - DXVec4Transform(vertices[v].position,vertices[v].position,transform); - //--- calc texture coord - tcoord.y=1-float(j)/tessellation; - vertices[v].tcoord=tcoord; - v++; - //--- create indices for two triangles. - if(i -bool DXComputeCylinder(float radius,float height,uint tessellation,TVertex &vertices[],uint &indices[]) - { - return(DXComputeTruncatedCone(radius,radius,height,tessellation,vertices,indices)); - } -//+------------------------------------------------------------------+ -//| Truncated Cone | -//| TVertex must have | -//| DXVector4 position, DXVector4 normal and DXVector2 tcoord members| -//+------------------------------------------------------------------+ -template -bool DXComputeTruncatedCone(float radius_top,float radius_bottom,float height,uint tessellation,TVertex &vertices[],uint &indices[]) - { - if(tessellation<3) - tessellation=3; -//--- prepare arrays - uint count=2*(tessellation+1)+2*tessellation; - if(ArrayResize(vertices,count)!=count) - return(false); - count=6*tessellation+6*(tessellation-1); - if(ArrayResize(indices,count)!=count) - return(false); -//--- prepare normal - DXVector2 normal=DXVector2(height,radius_bottom-radius_top); - DXVec2Normalize(normal,normal); - float dy=height/2.0f; - uint v=0,idx=0; - uint stride=2; -//--- create top and bottom rings of vertices - for(uint i=0; i<=tessellation; i++) - { - float u=1.0f-(float)i/tessellation; - float angle=(i*DX_PI_MUL2/tessellation); - float dx=(float)sin(angle); - float dz=(float)cos(angle); - //--- - vertices[v].normal =DXVector4(dx*normal.x,normal.y,dz*normal.x,0.0f); - vertices[v].position=DXVector4(dx*radius_bottom,-dy,dz*radius_bottom,1.0f); - vertices[v].tcoord =DXVector2(u,1.0f); - v++; - vertices[v].normal =vertices[v-1].normal; - vertices[v].position=DXVector4(dx*radius_top,dy,dz*radius_top,1.0f); - vertices[v].tcoord =DXVector2(u,0.0f); - v++; - //--- creater side surface - if(i0 && i -bool DXComputeCone(float radius,float height,uint tessellation,TVertex &vertices[],uint &indices[]) - { - if(tessellation<3) - tessellation=3; -//--- prepare arrays - uint count=2*(tessellation+1)+tessellation; - if(ArrayResize(vertices,count)!=count) - return(false); - count=3*tessellation+3*(tessellation-1); - if(ArrayResize(indices,count)!=count) - return(false); -//--- prepare normal - DXVector2 normal=DXVector2(height,radius); - DXVec2Normalize(normal,normal); - float dy=height/2.0f; - uint v=0,idx=0; - uint stride=2; -//--- create top and bottom rings of vertices - for(uint i=0; i<=tessellation; i++) - { - float u=1.0f-(float)i/tessellation; - float angle=(i*DX_PI_MUL2/tessellation); - float dx=(float)sin(angle); - float dz=(float)cos(angle); - //--- - vertices[v].normal =DXVector4(dx*normal.x,normal.y,dz*normal.x,0.0f); - vertices[v].position=DXVector4(dx*radius,-dy,dz*radius,1.0f); - vertices[v].tcoord =DXVector2(u,1.0f); - v++; - vertices[v].normal =vertices[v-1].normal; - vertices[v].position=DXVector4(0.0f,dy,0.0f,1.0f); - vertices[v].tcoord =DXVector2(u,0.0f); - v++; - //--- creater side surface - if(i0 && i -bool DXComputeSurface(double &data[],uint data_width,uint data_height,double data_range, - const DXVector3 &from,const DXVector3 &to,DXVector2 &texture_size, - bool two_sided,bool use_normals, - TVertex &vertices[],uint &indices[]) - { -//--- - if(data_width<2 || data_height<2) - return(false); -//--- prepare arrays for vertices and triangles - uint count=data_width*data_height*(two_sided?2:1); - if(!ArrayResize(vertices,count)) - return(false); - count=6*(data_width-1)*(data_height-1)*(two_sided?2:1); - if(!ArrayResize(indices,count)) - return(false); -//--- find min and max value - float min_value=+FLT_MAX; - float max_value=-FLT_MAX; - for(uint j=0; jvalue) - min_value=value; - if(max_value=data_width-1) - DXVec4Subtract(v1,vertices[j*data_width+i-1].position,vertices[j*data_width+i].position); - else - DXVec4Subtract(v1,vertices[j*data_width+i-1].position,vertices[j*data_width+i+1].position); - //--- v2 - if(j<=0) - DXVec4Subtract(v2,vertices[j*data_width+i].position,vertices[(j+1)*data_width+i].position); - else - if(j>=data_height-1) - DXVec4Subtract(v2,vertices[(j-1)*data_width+i].position,vertices[j*data_width+i].position); - else - DXVec4Subtract(v2,vertices[(j-1)*data_width+i].position,vertices[(j+1)*data_width+i].position); - //--- normal - DXVec4Cross(normal,v2,v1,DXVector4(0.0f,0.0f,0.0f,1.0f)); - float inv_len=(float)(1.0/sqrt(normal.x*normal.x+normal.y*normal.y+normal.z*normal.z)); - vertices[j*data_width+i].normal.x=normal.x*inv_len; - vertices[j*data_width+i].normal.y=normal.y*inv_len; - vertices[j*data_width+i].normal.z=normal.z*inv_len; - vertices[j*data_width+i].normal.w=0.0f; - } - } - } - else - { - DXVector4 n=DXVector4(0.0f,0.0f,0.0f,0.0f); - for(int i=0; i blue > light blue > green > yellow > red > dark red | -//+---------------------------------------------------------------------+ -void DXComputeColorJet(const float value,DXColor &cout) - { - float v=value*1.1f-0.05f; - cout.r = fmin(fmax(v<0.75f ? 4*v-1.5f : 4.5f-4*v,0.0f),1.0f); - cout.g = fmin(fmax(v<0.5f ? 4*v-0.5f : 3.5f-4*v,0.0f),1.0f); - cout.b = fmin(fmax(v<0.25f ? 4*v+0.5f : 2.5f-4*v,0.0f),1.0f); - cout.a = 1.0; - } -//+---------------------------------------------------------------------+ -//| Computes hot to cold color scheme colors on [0;1] range | -//| blue > light blue > green > yellow > red | -//+---------------------------------------------------------------------+ -void DXComputeColorColdToHot(const float value,DXColor &cout) - { - float v=2*value-1.0f; - cout.r = fmin(fmax(2*v,0.0f),1.0f); - cout.g = fmin(fmax(2.0f-2*fabs(v),0.0f),1.0f); - cout.b = fmin(fmax(-2*v,0.0f),1.0f); - cout.a = 1.0; - } -//+---------------------------------------------------------------------+ -//| Computes red to green color scheme colors on [0;1] range | -//| red > yellow > dark green | -//+---------------------------------------------------------------------+ -void DXComputeColorRedToGreen(const float value,DXColor &cout) - { - if(value<=0.5) - { - cout.r=1.0f; - cout.g=DXScalarLerp(0.01f,0.95f,fmin(fmax(2*value,0.0f),1.0f)); - } - else - { - cout.r=DXScalarLerp(0.1f,1.0f, fmin(fmax(2.0f-2*value,0.0f),1.0f)); - cout.g=DXScalarLerp(0.6f,0.95f,fmin(fmax(2.0f-2*value,0.0f),1.0f)); - } - cout.b=0.0f; - cout.a=1.0f; - } -//+------------------------------------------------------------------+ diff --git a/Include/Canvas/DX/Shaders/DefaultShaderPixel.hlsl b/Include/Canvas/DX/Shaders/DefaultShaderPixel.hlsl deleted file mode 100644 index ce90df8..0000000 --- a/Include/Canvas/DX/Shaders/DefaultShaderPixel.hlsl +++ /dev/null @@ -1,71 +0,0 @@ -//+------------------------------------------------------------------+ -//| Default Pixel Shader | -//| Copyright 2019, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ -//| Inputs for whole scene | -//+------------------------------------------------------------------+ -cbuffer InputScene : register(b0) - { - matrix view; - matrix projection; - float4 light_direction; - float4 light_color; - float4 ambient_color; - }; -//+------------------------------------------------------------------+ -//| Inputs for single object | -//+------------------------------------------------------------------+ -cbuffer InputObject : register(b1) - { - matrix transform; - float4 diffuse_color; - float4 emission_color; - float4 specular_color; - float specular_power; - float dummy[3]; - }; -//+------------------------------------------------------------------+ -//| Input texture | -//+------------------------------------------------------------------+ -Texture2D diffuse_tex : register(t0); -//+------------------------------------------------------------------+ -//| Texture sampler | -//+------------------------------------------------------------------+ -SamplerState diffuse_samp - { - Filter =MIN_MAG_MIP_LINEAR; - AddressU=Wrap; - AddressV=Wrap; - }; -//+------------------------------------------------------------------+ -//| Pixel shader input type | -//+------------------------------------------------------------------+ -struct PSInput - { - float4 position : SV_POSITION; - float4 camera : CAMERA; - float4 normal : NORMAL; - float2 tcoord : TEXCOORD; - float4 color : COLOR; - }; -//+------------------------------------------------------------------+ -//| Pixel shader entry point | -//+------------------------------------------------------------------+ -float4 PSMain(PSInput input) : SV_TARGET - { - float3 diffuse =saturate(-dot(light_direction.xyz,input.normal.xyz))*light_color.rgb*light_color.a; - float3 ambient =ambient_color.rgb *ambient_color.a; - float3 light =(diffuse+ambient)*diffuse_color.rgb*diffuse_color.a+emission_color.rgb*emission_color.a; - float4 specular=float4(light_color.rgb*specular_color.rgb,pow(saturate(dot(reflect(normalize(light_direction.xyz),input.normal.xyz),normalize(input.camera.xyz))),specular_power)*light_color.a*specular_color.a); - float4 clr=input.color; - //--- use texture if it exist - uint width,height; - diffuse_tex.GetDimensions(width,height); - if(width*height>0) - clr*=diffuse_tex.Sample(diffuse_samp,frac(input.tcoord)); - //--- combine light with colors - return(lerp(float4(light*clr.rgb,clr.a),float4(specular.rgb,1.0),specular.a)); - } -//+------------------------------------------------------------------+ diff --git a/Include/Canvas/DX/Shaders/DefaultShaderVertex.hlsl b/Include/Canvas/DX/Shaders/DefaultShaderVertex.hlsl deleted file mode 100644 index 14cae19..0000000 --- a/Include/Canvas/DX/Shaders/DefaultShaderVertex.hlsl +++ /dev/null @@ -1,72 +0,0 @@ -//+------------------------------------------------------------------+ -//| Default Vertex Shader | -//| Copyright 2019, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ - -//+------------------------------------------------------------------+ -//| Inputs for whole scene | -//+------------------------------------------------------------------+ -cbuffer InputScene : register(b0) - { - matrix view; - matrix projection; - float4 light_direction; - float4 light_color; - float4 ambient_color; - }; -//+------------------------------------------------------------------+ -//| Inputs for single object | -//+------------------------------------------------------------------+ -cbuffer InputObject : register(b1) - { - matrix transform; - float4 diffuse_color; - float4 emission_color; - float4 specular_color; - float specular_power; - float dummy[3]; - }; -//+------------------------------------------------------------------+ -//| Vertex shader input type | -//+------------------------------------------------------------------+ -struct VSInput - { - float4 position : POSITION; - float4 normal : NORMAL; - float2 tcoord : TEXCOORD; - float4 color : COLOR; - }; -//+------------------------------------------------------------------+ -//| Pixel shader input type | -//+------------------------------------------------------------------+ -struct PSInput - { - float4 position : SV_POSITION; - float4 camera : CAMERA; - float4 normal : NORMAL; - float2 tcoord : TEXCOORD; - float4 color : COLOR; - }; -//+------------------------------------------------------------------+ -//| Vertex shader entry point | -//+------------------------------------------------------------------+ -PSInput VSMain(VSInput input) - { - PSInput output; - //--- posiiton and camera direction - output.position=mul(input .position,transform); - output.position=mul(output.position,view); - output.camera =-output.position; - output.position=mul(output.position,projection); - //--- transform normals - output.normal = mul(input.normal, transform); - output.normal = mul(output.normal, view); - output.normal = normalize(output.normal); - //--- color and texture coordinates - output.tcoord =input.tcoord; - output.color =input.color; -//--- - return(output); - } -//+------------------------------------------------------------------+ diff --git a/Include/Canvas/FlameCanvas.mqh b/Include/Canvas/FlameCanvas.mqh deleted file mode 100644 index 543133b..0000000 --- a/Include/Canvas/FlameCanvas.mqh +++ /dev/null @@ -1,751 +0,0 @@ -//+------------------------------------------------------------------+ -//| 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 deleted file mode 100644 index 9e1566e..0000000 --- a/Include/ChartObjects/ChartObject.mqh +++ /dev/null @@ -1,1000 +0,0 @@ -//+------------------------------------------------------------------+ -//| 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); - //--- method of identifying the object - virtual int Type(void) const { return(0x8888); } - //--- 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); } - //--- 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((bool)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((bool)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((bool)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((bool)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); - int X_Distance(void) const { return(CChartObjectButton::X_Distance()); } - bool Y_Distance(const int Y); - int Y_Distance(void) const { return(CChartObjectButton::Y_Distance()); } - int X_Size() const; - int X_Size(const int Y) const { return(CChartObjectButton::X_Size()); } - int Y_Size() const; - int Y_Size(const int Y) const { return(CChartObjectButton::Y_Size()); } - - int Timeframes(void) const { return(CChartObjectButton::Timeframes()); } - virtual bool Timeframes(const int timeframes); - bool State(const bool state); - bool State(void) const { return(CChartObjectButton::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((bool)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((bool)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((bool)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((bool)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((bool)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((bool)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((bool)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((bool)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((bool)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((bool)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((bool)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((bool)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((bool)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((bool)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(false); -//--- 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(false); -//--- 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 deleted file mode 100644 index 080541d..0000000 --- a/Include/Controls/BmpButton.mqh +++ /dev/null @@ -1,268 +0,0 @@ -//+------------------------------------------------------------------+ -//| 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 deleted file mode 100644 index 08d5a76..0000000 --- a/Include/Controls/Button.mqh +++ /dev/null @@ -1,146 +0,0 @@ -//+------------------------------------------------------------------+ -//| 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 deleted file mode 100644 index e8186fd..0000000 --- a/Include/Controls/CheckBox.mqh +++ /dev/null @@ -1,183 +0,0 @@ -//+------------------------------------------------------------------+ -//| 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 deleted file mode 100644 index 6d5de34..0000000 --- a/Include/Controls/CheckGroup.mqh +++ /dev/null @@ -1,377 +0,0 @@ -//+------------------------------------------------------------------+ -//| 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}tmYmvAs32IlRE5XvOf51)E-{CU5ECdAuiPlg9p>0}3OqwqO zb_}@EMX9t{#Y#=Vr0HZJ3CW~$`o6cFqOEmO$avw&$=tb|=iGDeOx~Rs^r$h8-%;QL zm%)Jg=kZ*?`zx0Y!L-xBN>AV~_%SyO27p`R8WK-|X>cDr01pA5#{laZ0j|{G^?L7^ zW?S0rwsgB)u`EkbEEY}Qbzc(RTSqlqb)yFQ8;yqKayiN8^NK>DAn|xy48xGofIkE8 zO~A7l0(~9uPuhOdG?kw{h(sc)53Io-2)u#x2DsQ)Ig%avjX(C!K7_+zRYNoyl~SqH z#nO9j`MJkzHmmLc-Mj~k>;uoD)9LKP&HH$2|G{8TVzHPc5{YB@%z3PL9NfQQ)Q`{J zz5~BU+|4un6wt>yHBD2I&yM1w1@zbJy7KcIpx2J}efZb@Z4aHPR7&;2p6eyjuj{%x ze|`feVLk9$$aUK(UnmsndEa&}`fIhCl*>Pbk-gx3;5X51Hl@{S_3XEEo+lPxNA|VM zqL7u$0+^R~WErIAM9VJ9`yAfAona69K9*)5|Jq*vAgP&0XR@_clJwlOy}rwlaOu_4 zs$Sj{QvIu&g8hC`oMmXnrK|Kl&7Y`Ee7 Hzc~*8n19Zv diff --git a/Include/Controls/res/Down.bmp b/Include/Controls/res/Down.bmp deleted file mode 100644 index 5dd180c423f190d9c70582381187e978e6f57bab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 824 zcmZ?rwP0od12Z700mK4O%*Y@C7H0y=3voj*SO7@883km8KzDaH@%k1lSg>{LRv<}? m7ND{{d-fbYd>BX))Y8(@0#vgc27qj!2r;&ds)2+60|Nkq^0+4e diff --git a/Include/Controls/res/DownTransp.bmp b/Include/Controls/res/DownTransp.bmp deleted file mode 100644 index ab50187d160e2cbabb695f09a5ece3c04cd28448..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1080 zcmZ?rwP0ZY12Z700mK4O%*dbsWHB%>0p*3bAs8$$N(}lC=(;IR tK{Tmmfb{Iyv*-We!-v5%DQ2{^w1DkgzI^$A7zXJFiIeJ%QT4PA0RRAQFhc+U diff --git a/Include/Controls/res/DropOff.bmp b/Include/Controls/res/DropOff.bmp deleted file mode 100644 index ab50187d160e2cbabb695f09a5ece3c04cd28448..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1080 zcmZ?rwP0ZY12Z700mK4O%*dbsWHB%>0p*3bAs8$$N(}lC=(;IR tK{Tmmfb{Iyv*-We!-v5%DQ2{^w1DkgzI^$A7zXJFiIeJ%QT4PA0RRAQFhc+U diff --git a/Include/Controls/res/DropOn.bmp b/Include/Controls/res/DropOn.bmp deleted file mode 100644 index 11b45f1e2a654eea69990f30f3aa0a1d6944a9f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1080 zcmZ?rwP0ZY12Z700mK4O%*dbsWHB%>0p*3bAs8$$N({;nXlZHrzhJ?F|I3#zhhq>Q yBu=b@LF)JH+4KMK;lp4W#3xoSOdUwi)~#E?Zh?uBN_Tg6lWZ@kc8sd0Bm@9)Krll9 diff --git a/Include/Controls/res/Left.bmp b/Include/Controls/res/Left.bmp deleted file mode 100644 index 1de38acff966cb748ed6f408d37c4a499405278e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 824 zcmZ?rwP0od12Z700mK4O%*Y@C7H0y=3voj*SO7@88NQ&UrGXe`^C4~^$^8&5B!v$#J{^i`7#IMbySOI+ diff --git a/Include/Controls/res/LeftTransp.bmp b/Include/Controls/res/LeftTransp.bmp deleted file mode 100644 index dc8ed846c172b41f2d1891d102a74b46014f0529..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1080 zcmZ?rwP0ZY12Z700mK4O%*dbsWHB%>0p*3bAs8$$O3)<)T3TBElWWm}1q=RzFgf}` z`u6PE^MCpB>FBo08cG2 ALjV8( diff --git a/Include/Controls/res/RadioButtonOff.bmp b/Include/Controls/res/RadioButtonOff.bmp deleted file mode 100644 index 0c39bbc58d9d7ee608effac793716078b438c63f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 632 zcmZuvO;5r=5Urk#|G>nfzre&RcmIn=e+f;vz_}dYAi?+nNQ(g_tbAA@2+|are$Y}V zczy1yt|rDNZ+ANTW@qNjrcTdy74aSO^@wBd8#~G&w-hDC&-MK;2nSyP2&~uZ1IE}{ zu~;l;G8vyhHu>mG@@RJ)=R{T2LN1qsuIuo9Uw~}#rPJvGafnN?D*w;t^N8aZ@3swR zJ{SBrijX7;G))sRvIe>%S}f3I43=eKwOV1b*@!&|0&t$lBkMI9ItEV+;};X2?;;38 zB-;;cw_8L!hwHj93MMi6g7^=WAOSRbs+xjWeLM>2P3nG zx5+EqxsAZ{;PbnCy`IP+HPa0p?N$S=dKClKhRNe5!)MH<6PSa(0BI%lrG5jRLTLG4J^z~*=|P|x Xve_(XmU3Ql&TGD7{;fr)m{o}iO}^R-2w|E&=iSal`b8uC6?+G-8y>clG#Nl)(WiY&y1Nt zvqT##gkp%!>@Fy=3I;-ZutU4!Fe}T{{nz(SeiqTd^UXW&`+nc|yw5WO7e@9P@zbr= z;|lwCu*Yaukzov|x|{foIH49GMifQIs@3YPLZR@{G|fODvE-zt`{Z4(*UuD-#rL*t z6N|m?KpX&R*Q`}Xc0p*3bAs8$$%!uyp?*Ee}P5KX_VHn0I#;YK; z*wo0p*3bAs8$$O3*9>T3TBEQ)2jn1q=RzFu7(d sU%veRo;`cWHUp&p@ZrP%w{G3~zq`AeWOq<%Kc)VsH2ld8_o1f`05&`@LjV8( diff --git a/Include/Controls/res/SpinDec.bmp b/Include/Controls/res/SpinDec.bmp deleted file mode 100644 index ad4d3d036ee90c672dcb37dc3bbf8128f033a4d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 568 zcmZ?rwP0cZ12Z700mK48%mKuV3<^M!fq@AqFT@SOV1Xe(ba!|EC)b$^7A*L`b?esu rAevM&KzjD<+4KMK;lp5>6f;^{TEKQLU%vc541@H8#7T7r?bQPS_02Fh diff --git a/Include/Controls/res/SpinInc.bmp b/Include/Controls/res/SpinInc.bmp deleted file mode 100644 index ce0ae600964765232993b06d33d986be749a43b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 568 zcmZ?rwP0cZ12Z700mK48%mKuV3<^M!fq@AqFT@SOV1YqOw6wJRU$9`o|K-bEA@L@0w;uEVErVgZM>(;Gcx4^_mrMtVkNw$|%J1A2R0A{W*Hvj+t diff --git a/Include/Controls/res/ThumbHor.bmp b/Include/Controls/res/ThumbHor.bmp deleted file mode 100644 index 8c9bed398c71bc8f057cdfd614e8df0420ae50f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1144 zcmZ?rtzcmQ12Z700mNcJEC9re3=%++fx!tVFT@SOU;!X;jA8&be4ZN)`ZWq^%i~zyRnrOa`)p@w#I<7yy-HGDgi0p*3bAs8$$N}z;5dwcu)rAwFoU%q@fRt%B@ WsX@_%#GzC_l2N0~(GZ|h2mk=wFFNA@ diff --git a/Include/Controls/res/Up.bmp b/Include/Controls/res/Up.bmp deleted file mode 100644 index bfea4cda288065cc9b0e702b9dd8581cb0f46ff3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 824 zcmZ?rwP0od12Z700mK4O%*Y@C7H0y=3voj*SO7@883m+-Kub%@f&~kf!vK&C6v1x* qP|cn_dk!By3?zYU{E8v6KxJFEZY5GNL`!#fH!&uUszD0@1_l5;g}5gG diff --git a/Include/Controls/res/UpTransp.bmp b/Include/Controls/res/UpTransp.bmp deleted file mode 100644 index 11b45f1e2a654eea69990f30f3aa0a1d6944a9f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1080 zcmZ?rwP0ZY12Z700mK4O%*dbsWHB%>0p*3bAs8$$N({;nXlZHrzhJ?F|I3#zhhq>Q yBu=b@LF)JH+4KMK;lp4W#3xoSOdUwi)~#E?Zh?uBN_Tg6lWZ@kc8sd0Bm@9)Krll9 diff --git a/Include/E_CheckHistory.mqh b/Include/E_CheckHistory.mqh deleted file mode 100644 index aa967ff0957a7cbffdf4a11b375ae5b73ff64be2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4886 zcmd5=T~8B16ur+T{)e$9rVW)36JJC~lvX7HA-0(CL@F%USSWV4ng;#9@+Z`D=JqIzMZSppr=uxHvL){&kz@HFucRxf zWYU*`jAU8PB(c<9mD4HoIQ(#pZl`5 zZ-yK=Z*egj6(HcYb5!w&nPx!`IJiL0<2+P6F6N1~%3ah-JpoEjy?;b&?BV~q50$z| zNHq3XB%A&RyUv&O#mw0!a6%WX>`MDXRcgM<>E+e0J10Z%G#Q<2t|Nma_Ll@Kv;pp4 zk5-fShw={JknK5?wOB`4VPyw1l+hjc2D^*pv464G1pO(P?;INX&=IdJTIulR2-=h1 ztYSZ+j?s7>(XE!Bpg&Ewu!Z@KXJLm3IBAc4*n;l^43)`|=&r^pSxU?%8SB zBU7p3T~pr3w(Lm*-MfK4TFY6S@8bNLu|0+bRs1w|!JhgITk>*;KC0~BHn>xuUp@Gg z*V=$a&Zm%WYv^4Ze^wxKkjbvc3~jr_Oc&n{po4K*%YCu$W5VcHr4mVYh>YrU-bROh z67OUjR&%cr>@`b5?oMIJ0CIzu-7!`v^J(<$IwW0>ZWt`vc50v7R-r3_aaSWtD)r4bRbWl_++OfZGFP zlP5KvVCVUw1q*gCoIJoVj?i6zlY3s%D$ZPGjHGca<0XCDgC)!O+5RE!#Pde10Y+f7 zEK(|Y@@l$tN1@#;&ogxGq#}%RS;~CB4q+L3b$C`C0T15WjNwL^Lxn>jdM3^z8 zp^g!?IpT}R}&&|%#*NL9Y$QNhBv)+*h7U`7q6A8y}DgXcg diff --git a/Include/E_ClosePositions.mqh b/Include/E_ClosePositions.mqh deleted file mode 100644 index 7b061e4..0000000 --- a/Include/E_ClosePositions.mqh +++ /dev/null @@ -1,81 +0,0 @@ -//+------------------------------------------------------------------+ -//| E_ClosePositions.mqh | -//| Copyright 2021, Nkondog Anselme Venceslas | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2021, Nkondog Anselme Venceslas" -#property link "https://www.mql5.com" -CTrade trade; - -// We declare a function CloseOpenPositions of type int and we want to return -// the number of positions that are closed. -void CloseOpenPositions() - { - - int TotalClose=0; // We want to count how many orders have been closed. - int c_slippage = Slippage; -Print("Close position status ", ClosePosition); -// Normalization of the slippage. - if(_Digits==3 || _Digits==5) - { - c_slippage=c_slippage*10; - } - -// We scan all the orders backwards. -// This is required as if we start from the first order, we will have problems with the counters and the loop. - for(int i=PositionsTotal()-1; i>=0; i--) - { - - ulong ticket = PositionGetTicket(i); - - Print("Position profit is ", PositionGetDouble(POSITION_PROFIT)); - PositionProfit = PositionGetDouble(POSITION_PROFIT); - if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && iClose(Symb, PERIOD_CURRENT, 1) < Senkouspanb && iClose(Symb, PERIOD_CURRENT, 1) < Senkouspana) - { - // We select the order of index i, selecting by position and from the pool of market/pending trades. - //If the selection is successful we try to close the order. - if(trade.PositionClose(ticket, c_slippage)) - { - TotalClose++; - } - else - { - // If the order fails to be closed, we print the error. - Print("Order failed to close with error - ",GetLastError()); - } - } - - if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && iClose(Symb, PERIOD_CURRENT, 1) > Senkouspanb && iClose(Symb, PERIOD_CURRENT, 1) > Senkouspana) - { - // We select the order of index i, selecting by position and from the pool of market/pending trades. - //If the selection is successful we try to close the order. - if(trade.PositionClose(ticket, c_slippage)) - { - TotalClose++; - } - else - { - // If the order fails to be closed, we print the error. - Print("Order failed to close with error - ",GetLastError()); - } - } - - if(ClosePosition) - { - if(trade.PositionClose(ticket, c_slippage)) - { - TotalClose++; - ClosePosition = false; - } - else - { - // If the order fails to be closed, we print the error. - Print("Order failed to close with error - ",GetLastError()); - } - } - // We can use a delay if the execution is too fast. - // Sleep() will wait X milliseconds before proceeding with the code. - // Sleep(300); - } - } -//+------------------------------------------------------------------+ diff --git a/Include/E_EntriesManagement.mqh b/Include/E_EntriesManagement.mqh deleted file mode 100644 index d69973d97d3cdc9ef5640bd721ceb171be5e4681..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20382 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 F@L#s;__F{2 diff --git a/Include/E_ScanPositions.mqh b/Include/E_ScanPositions.mqh deleted file mode 100644 index 53f5789..0000000 --- a/Include/E_ScanPositions.mqh +++ /dev/null @@ -1,49 +0,0 @@ -//+------------------------------------------------------------------+ -//| E_ScanPositions.mqh | -//| Copyright 2021, Nkondog Anselme Venceslas | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2021, Nkondog Anselme Venceslas" -#property link "https://www.mql5.com" - -//Scan all positions to find the ones submitted by the EA -//NOTE This function is defined as bool because we want to return true if it is successful and false if it fails -bool ScanPositions() - { - -//Scan all the orders, retrieving some of the details - TotalOpenOrders = 0; - TotalOpenBuy = 0; - TotalOpenSell = 0; - for(int i=0; iLastBarTraded || LastBarTraded==0) - LastBarTraded=(datetime)PositionGetInteger(POSITION_TIME); - } - Print("Total positions ", TotalOpenOrders, " - Total buys ", TotalOpenBuy, " - Total sells ", TotalOpenSell); - return true; - } \ No newline at end of file diff --git a/Include/E_TradeManagement.mqh b/Include/E_TradeManagement.mqh deleted file mode 100644 index 9b95978..0000000 --- a/Include/E_TradeManagement.mqh +++ /dev/null @@ -1,57 +0,0 @@ -//+------------------------------------------------------------------+ -//| E_TradeManagement.mqh | -//| Copyright 2021, Nkondog Anselme Venceslas | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2021, Nkondog Anselme Venceslas" -#property link "https://www.mql5.com" - -//Done for the day after a profitable trade -//If closed trade was opened the day before, look for trade opportunities -double minProfitAllow = AccountInfoDouble(ACCOUNT_BALANCE)*(Breakevent/100); -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -void TradeManager() - { - CanSell = true; - CanBuy = true; - - if(lt.time == TimeToString(TimeCurrent(), TIME_DATE)) - { - if(lt.type == DEAL_TYPE_BUY && lt.profit < 0) - { - CanBuy = false; - } - if(lt.type = DEAL_TYPE_SELL && lt.profit < 0) - { - CanSell = false; - } - } - } -//+------------------------------------------------------------------+ - -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -void ProfitRunner() - { - Print("Min acceptablbe profit ", minProfitAllow); - ClosePosition = false; - if(PositionProfit > minProfitAllow) - FollowProfit=true; - - if(FollowProfit) - { - if(Kijunsen > iClose(Symb, _Period, 1) && TotalOpenBuy > 0) - { - ClosePosition = true; - } - if(Kijunsen < iClose(Symb, _Period, 1) && TotalOpenSell > 0) - { - ClosePosition = true; - } - } - Print("Looking to close this position ", ClosePosition, " Follow profit ", FollowProfit); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Expert.mqh b/Include/Expert/Expert.mqh deleted file mode 100644 index 0b1e844e53cbb2332eaf87e5f1cb0fea7aa55b3a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 122604 zcmeHwX?Gk)a&3L!r+3c#4=wr(4UQ;K)G|+&9>#~8hO`M1CSdC6%flhTMeuMN0vrxa z*+1QO+`I@xuPhg`MmjJ0e(Jj{&(}ggqo|( zug&aKe{MH_Yu+}`ns?1%v);UF{?hy+{r@_co}0}ZY3HM~v){asHV&ngubMCA=O2W> z_;juLKg|`nx+%RKHjkTsY2M2-hw|5fT-}z>&*iTV^36NBHfzx0J85%WJ`bm7J}!dp zL+SJTFc%+$nh!@@dD(m`pZ0{NR}npnBtL&Aynih;z7)0v^VUz?H~!S<=K}5d)yQ*zZN<_4t$Q3?n{5*!;9qUMb-9aLhE~xD(K*2 zk-q&fdg#Py{g`$wk~Cw!h|M!WhL^&d7Xc}N6Eoo!acfUF_DrM`SN^3{i!{&N(ORnt7zenMl9l;);FSz~b_|vR%@2<46of zqh`Y0UxeaWb5ZVr-FSVZYx>MvxqcwmRE{r(5$en+pX=PsNApO=b1%#vX6@C4 zDUS6(<`8p?vA+xW|1NxnWK2KHH)W0?$G4MltIU2k;mBbjDW$LywYeQXo7c~}Qht8uPU0omj=)TENe*SsvMj&AB)Z@f#-jjbjm3ibWemCJb z;h(;ge`+U83r}Kvu$_0sX25DZ%n(K~=9-M}%jnzr=dn#6hsx@IG(QBt1k@~=hlY4{ zQ!M44pboql%qy%X`~scZ1M$RjUu4QFi|@hi1;1&p`Ll3B{SEK=ndh&XVE!x+`R^QO z;eXu~Te;i(B-l&O4<1pQFL+xJJLmXXvnG+pZiu=$UqH`YnM3v1E(s=-eCD>kE;pYA z-|TXb+IcCj`+XS6w3OHTnr19!NA3y&r86<@Sgfy~n`x*w-z=pZ5;ZOL*4H$&*L|?* zY0vwbXAIu|Fz>3wdFt~R{+Ih2OSMU0N!q8S+WMML+C2xn7gXc-RNVG`jpcXj-Q@T( zR?;=W?a7u7$x86t**kUc`A;xpcq#*_Zv{1f;~TaxcXW*af+Gs!j28qLhkLiQF} zTIB!KKR|ANCO+0vvC8}M4dU@}9#u@wE$Im{BWynUeI9%{X6al;Ux8DBq2q zMe=X!qo0LYdn@z!L^y<85!NfbWGR0%nr3G4ZQv|2mYTQx-enx&HDjjRe&DTfy#{&W zr}CF(?G7YLs6WX_1|B&wRhZ$&;ZvMjT??~~tQO>KKa39Eru9Lej{Wqd_m#BzH=)$> zNbR(ub<)cxkts!n{7H~g^^bjP@IpWhW=z*U(j1kid{frBUWy+Eult#Jxa3OAJ#d=R ze<+{8Ie72<1RmD79dlZ#)t2D>vn7=b#7v|^XD6nEe}Nj}!G4%K+>2F`8Wq|`N=>N^ z(5TrGqY6)I{{0u}jaj63vMMu^zg~+>yqQaOfqLK~*8aMv=O{RavJ5bm&NGr+1K{(0 z?<0Gp5R#8oX<)NHt$MBF2E`wpKHy1e&+vK18hAMxuhUFQ4X2ep^&!;W z0Dp8nH(xU|eN)ZXyCI{@l|O0zO*o16yqv_=Z^!kaNc8)VY0&oS_^J2XZ;nl$EKy=S zj_L4g(Apm9fOUHzV}icdxvJ0bcbN{~5~THw*eT^ujV@c^wjM|q^1odB?n{;GxIH-& zPCpJ~<7z-ZnmA{+dJf9`oY^;hDD%9sCuc`iCRbJyCh{eawO{0t?7ml?U=0c>hkaa?D@b%%e}$CbWgz zJ=YfTbgV;n3*X11$H+^qw2c}qaOC-u@bSSr>z^eQlVWOJVfZUFZ%PEh?){(mq3 zTfWkdz>gI&_)a_~Z?b<8(3@gZyBTPNqdMw%Om3` z9>|kBN6*b9hYUT3-onztBg2Y-w!<0?n^Sn~;2k6k@&p+H!oQbm-cuhs3bk#J7~g+s z9DWq~+|Y64qriw>1`HW94n`#Jg5(bwhd#F$;{ejqbMk8nwYjnRxOx2C?U0pVT--;( zPG&wRg^2!aWu!I=#ad{`4bgx%f`LOvQPPf7u7FoQ1K~3XUe9WuV^3)<*wB5^$;+bi zhK04K?fQQvnU7ja9>-vZ=;1Bpe*u{(L}Kp)e>}y;Ta^j#{jVib z>c4}Z>%I7mAT9T#A|mB||GraiI_*FG9yCCH5&3ET>J)TXq>)l!-_Xy86rkpIie9~Z z!Mf+#awVA$d%`#Y`K(dnB@6fULzGl{N*a30wblpAkPF0$KCpvP4JzaiL!g#i@d(-b ze-o)?E&*9%`be;j%)}xS8GCRg>P*V{>4D6e`e0k~ym?$}PMbZNq%HWrRnswFhIpx^ z+Yno!=#=|aUjO@#K>e?=V@OA!?G72kd?QfLYw8hbyC*$@lFv2YSmHV8=L4oPHP0O6 z-qw8do5iCZ&?>fje<}U5#*Y9f0Q=hZ15e;@F7iAO+pPKnE8P9#Eji`@F*_{fJL#Qu zKJZr3l^EE#a@&3cN=f-nUM-D4M{bDGZ!9(kC7N??m+A5&@D`(t*{EXEcvUkXZv&?K z6+6uVKX!gj>`TYK1u6Tz_?eb*96GaXqkDe67gL{C%<-O0j11%m!=S9b_`j!dV^=cSAZb9*h^CEFww$2lJPe zr>M+hM1tROFBrqk@O^q6K2J{7K`-yeB2ug{)v`e;j#e*;l-ZrJ zocEo%-1^01%X_p4S$kwo0bZm>JfB(cS_f`*NAW5BZ921c%vb0>{b4`rvZnR7ci!G<3)uPC$S}fzH;*3fv@z&2Uqylvq_}bJE{Q?ZJT|A)x!QNWNw~@j1uS{Mm;R1_MEP& z^c#zhAC-gf9Fdg(&E9YF+3h|$9{b{Ky$@B;Z|*+^kLvXvSjp17*D$`pE-+vA;Hdo? zU46!xw{}nH#%xa8>b6h~nL+NeTRZx5ksh!5!JMaI{8TR5xMRDB9*{A8CN?(y=0M~( zy@vhxvDWvQ1*O4rDeh}56&?jVcY#3kmVpGN%A_eI6-Z^h)Fhw}r%YbsHf{FG(lw@S zKP%GE6)+wKqB;P#lVHzp6_NJ9!YuC@hFzM~$ z=6K09Dz6J)Uy5yrJ9_=vCtvypq$F#VO^+YHga_ z&Cl6d+ua=PGjHYA$Jn`Yizmm4Za#SJdKr8xRLuf=tfu9e%j3j4YpVwS6UK8WD}l^) z*y!SC%~MJvW>~V=dy1d*ec9)@S3mOj>67UsTSWd5xg%t!4ApdJXB} z&IYOzZH3RTookgvOrNh%{Z-Zv?OCq!`!(M_G~btboR02pnlA~>|CvzjY4)>aa^rb4 zbiLMO#pWf=o@HjIz^`JJX6S znNig8v~$cTJPqC%b^Yg*6rL`1-ox&i)zg|;*q}qHn}I!t)$F4W!+9557S^1^=OnzB z-ffRuY-hUtBUI_a_p>&y%ZR{Z?*nx0PKdoCdRQjOrB8Xk2eSKt_4SDIuh>a}q<)p4H=2<3jh2r;eeo1^K_8V{}4R>9#3NAfqWKGUV zyeu)3WfzBV6D^m{p%~xlTbXS;U1EHDKpey)i0gns<6DF@;?$O@+SBs~bT{gBEvM%t zj2}BZVa9oDZimenDf0EMQ?>ajAP9ECOw}UCZR<%>wYztm<&Ss3uSHSx82$oFAyMVM z!E5r3#x_&*qSBG>bU2Cez^>)HYp3oBGt|BRb?RQ3D{0@aFkPRe`usIHW8Uh+J~=zV zeeaXsj%CZ|%hRWkAw>iX`_%7g;E(RZLVN&O(@d4Nup!ic8ST1EZK2+o z{@##W$wSH9@-)^*vcnW7*Wb?Cg7<}bT(4WuGDs!fvH`ztLr#sj=AL901YYVQoskB5 zaHbvN28`&eye|Kam__1G>}A34YTGZZ{*>1ka2E2wUCyyDj{6r?BJLj1ydONMc#pU3 zw=f%qF=9uxuAbm;>~BXszSYKaeG&U4Q{Bt|UQAEiGTFIoD9_G*H+zcSK05aKP0WMk z?6GqKyM=V8&22$IT*F^0@E5Bms4RXg|GX`@Ds80kGODT3{_}wP%mtu#R4wDQ zO6?UV)Vz})y#qb?H8`{Z4%_|*oL3Fq+;-Qn-w3Dzbn|vb@7)Si(DvY7;}|8;>oBii z1qNI=l=vHQ04yhBie35nQS8KhiOK9OF1v#B7lkIQKwyN_4o@{#o-pp5Q>fbJZeu-< z<##gT?;HGoS=zl4jUOi@@Qk<}=?U3xQi_^oKX#1L+hdN)%R}r}r1zQ)^Cu#uQh{m& z%qTr^N)Azh9OD^9ij|Z(?r-$m*^oKKsSn)8Z+C;{d~PTcrB)z2ALN;vk#s;)LDOaF zrQQ$uldcGuzU18WYaOKNGvPz*C#}o4xMw_;;#>y%_FVICHlo@0vxz6TwiKU^p({@D z)$~csBTvmx4&faPcGcg%E&UvZcMQA>&%Bn;@b|C^6Z4P!Dp8f{Cf+}k>WpUN${rkg zGFszLz(yb#vU&K;Q;@vg_*@~Xg0Qw2OJo~GzNI!gjH;L->@CCo2JnaL2r;6m7oj?d zwJTtCY>&T|u`!qSt$YF!V+P|>0Euq#x4VHe>T_?%tmX22%e97Cg-)SAqHn+Zzm?}^ z%|FUNc<(%+*Za@RXtnwOkib;au$skDfv(?2+dSPcip5*8$0X~y-b{v3@;7_YLJuU$Mc~;F(ziUeAw>;tLjl8@+_UvS! z6qijS|Lr*HQAp#(aTQeks-t3mqh9f(_xVx06@7uvfqbBzp&eTXKPtvd2V#lsOp537 z7xu?79_Bj&u#RAn&)bl1gm(d%WF%&`+$;<1oMJmNV8~M9sSR0Wy)XZEP|pYdgkypoCVx=sgw%EK;ThBSNf4e-ja_+1T_1dX+hk`SlW#iqy){rUPSb~^jsJE3)lG}4;Dw?TYei`(eK*}dyW zvvu3~Pe#jqkvx5C0M<9*nWwTCM~`+wOE(qX16U97iE^O3C$k;h{n))jdr2*HcVFof zT|F8K=sS#$lu%?o$s^YsfiE_@}Q@5^7`UHAw2=8qSyUHB*Y z=6m@@+w-Vk^V+UI7#mJsKpl08Q)z6N_G5jtWs^K|Qi6z|jHrDZmb3E6XmfCqS*u!p zBSv|y?=hN9xdVR&UJLkWql&f4I2gC979q~${wd6h#qx-8^E?FnXwpLNmRt55HAIVT z&8uU3*r!FbQqOI9sfLe+^$^G!vWR+eHvUF6vG*X=M^O&K-^2O}eluI8IT_~RZ5`BS ztI9mMmGuW~H2$Kl%zFZt<*%SNSK5#*&(RE7oAD!D zmx!DvzkCd<7&zyfwyeDJky^C4Ewf;3Bez_?Rh*^Wv|MW}Svh9Tb7gsPmcFEMCp}#} z{oYRXwr9F9H=Ti@xSKwoVoHh*>HYKLZ{AWFgLgtyT%edx3|J)RJR~=msXHjUM!X`)siWGFE2iCx;3)c z3$|~7$;QPlG`2g3;;=oLqDYDbc4r$7esZe~oMoQ}@okh*ck`GxXXW>L8trq+oi>cM zr()?(IZAZ3yO#r3J-y=))wlFp#?sOW>*-rcYU@!`AnBskXSe09OFZN1AZ!w{Y4OQE zs(T)vh)ka)yY2Mt;8+#u*ULQdqmSIMx1DF)V%9DGE!S4-NPs}7l`X~1^V03PL&=)A zI;ndc)7K(+KBnH<5MHLwuFow8)A2KQ^#r`zkcuX( zsoC0SE#hA|f$+o8=RJ`Gp4^?!d#TR{$1(@3Nk%wDW*whCzs?YXJtB13DVG3yP0FK>bd899Jx>96_{M*+Iu>(RqJB3qua^Cnd`wv&)2Z|TohG=o~Hc6;G>e_0GN-KWKj zX4>k>J}ykqJ-R@cy)Ke@8qU)*+gQTyHtH-(78Q2k-2) zw2wD&sLxYxJxA`Y9!R~d)As4bYjRino8q%!6$Pgub<+g8J$R|b&h!>2bZR?V`?;j&Z z+>(!z*D-J}z4X0AMHi;!t+?D(9MEtGeAX4TRtsB#Y*bM)wR!L2CD;D9l@Esus1wC!)LB|nj~b%Ru7Qb!Mk|;DVmUI z|D2u#aZBbhe!6T)ybl5mM<1-TK^13=%YH41XwZ&AxqtL2^8-9j>OG^rj5T(D4N?l8 zJqh?{+DA$B?fJ1;T^_~+jy;io*k6TrS7Ou{J2=K&#;`!XnlI)=+AFzXRniZmcFG7z zdeNi#i^%@uXEjYRGOT!U478LnKg{-C70c<@6e$Z>oiYoHJ8%|xnG2};*Q$HOaOjmj zXzm4KWVuXCF<#^)K=pH(U8TJ?=5!qFKb_Mwlc;Y;Y@1!S)PIiik^5(HCN^g37a1EX zDycDyXXrcSvr?kL?7g>7yp#XiijM!grd{9_@PfXx#xbbZ>yjMI4XRuDW*}hVhP+8a z-@1Mf;v7WIekGX{aenMM#3{M|pGz03RM&!3pyz#g&RXHyCvf$Tp*@^`yf5#h_@WTQ zfR4OiOCCAC>V-`I(gw`LJ4CM5r%?+v4{aN^PPpVEg<=>99Y-b*OuFc!> zwzT;`>PgFp!x7bHj^EZKT`>gq$J-A`5F-`%wY2BR_tf!|GS8auj~SNcTsKrjc368c z4&4iLh_mavW}9t$WbyAb`k|GUF22xbsM*&NDxVaWQoKH0PNn#%^I3~f^!qxZ@QyD2 zPbZhK+NfVCTSrnuJm`{4|5o+$D4X+esxFyWpdinAQvADj6B62(OXl$XrAWaPY*)#sDy=xth&>cE2|%rE1x=V^|*Q*l4;rR?o3b~fUH_#-=FVX?mg`=#)P>Zif# zoz{Cz7c(27t7)ZGW6!g`SqP2P;Hmgr2C_i#=3hAcr=)XNH2g*X9=G`E-0$)dNe{!z z`g`e}Yh;Wau*V6z;gFs5CrsyclBphkmaNxwYhg}JT$vn?jQC-_mNP)!pI-(&(^}xO z(6nXMGv(Q7X`1$je7e`vKDtJ4&HOZaABatn#bEvsnqt2HGDs~~;$RO>-##p>)GE(T zOKP>hd8KyoUEMOcVLIFMh$5=o@5|nTx(8 z9*XU=kMDXacfCJaBS4+P)9Rh*Pv858JF)8*^Z8gZYKEB5uL#c{2v%X;bY1>g z^jEs`Q2Hw0$@oz#BlW$Ws6W9sT$kPm**sLE-W0#g-cxN+r`IX(Tlwl1tDiO*<2%Ms zk)Sy2`}OPLM47x|CdVtA592T19gX+Ufe%+?9C&wWJjQ%&!(*JsBj(WHcXAK5R_)jt z)$Kz2Ydw2qPpr!=(TTSe=hXYzXA3bpDVBHf23$znG7QtV?fSM?s0rD{egSw0h<;8U zH_roVdK*-0R$pOY1K!qUB#iVVfhZtkqmlNKWW|MTPQ3*J?#7U(o^ zQf+Dcd->2)B~W>{miU5RS7R@cUQc`tK2TdEXRVsSEC2KN_KOV31OdiLYzP+-GLtY|0Z&w*Fu9DRxJKu??{Gb2#`N2Wcr^i0_jTHyTs|DCS-&`^Juj9&SPPX3n$__>z@DpSV++>)N#>KSS`4E*kf`!ypkCuAUoSv9`kgb> z9%bVFSvaQx>jQfJ1y1!q^#jfmK`x+QWKCXuA^a|97aqwh=sSL_qQz@rJnl53z9rB5 z?1Vozquk?;(2l)vSOsB3?|F!xeT+_?dK$X38L@A9K%SF0~%; zNnVQd`;*C9bG695 zl4RTyxQc)qEAXaV*R8^8A?t@QmAZ%siyNpO#T875gqg9n$*lSy5O!H;=D$kd)qnrOqkym-F{rXCC zb8S8O=+2MeS6O$gMJKk}XmV#!kM~>FqAa2x=VIsaQpt^RPG{jHe=jr6b=Azr5|V04 z%KH>G>hI~XoEK(hu_f%@ah&p2KKXU{(~`AimN4aBeMhO~VaC~0!!=qJ^Dw8}WlAJr z56fhGyF381dga`4TEi0W>x`}Ad9^hbeUw%#yytdO_GX!pz__=<0d zg$3%Bu8_danTVrnTOqR5IaWT{8{x5L$+P{ghCTdvhZuGkmatyeq^Zn0$Oxy5v zLNy&XehsM}@+U^-$dKb+%(oQH@t#-kzih+Q!h%w~-_-JgUeddI;9Qk^*b$w>euFL1 zKJ|3Uy)bqrwKaLMoPeiK&m%35ozmj(FIyD7!}yivsZb+;cSr+4{{3i7JViCGLDrV= zo1-F!hK`C)<)gy&p`)@n8Zs(8<#WC|vUsj?3c*91ihn8KE>3{mke1>s8BT}t=YeV4 z{O#>m=~OR&x3_zS-KoZ!-`%D4B?`KA9AoBw?Kq3c)-0FF*deY0Tv_O07P`$N^ODi_ z`8--^?^P~?jrQ|6zrGTUV1Lp!`dDetvz47*+36vx0>l^E*0OzD*=fUIZ>Oixe6}6? z3N=gZ^?YTkErVJ56lXP4j+!TxW-!hBO0~hHV4hFQXRA}5`ACb^{c%)9iHxts{;`kz z%2h?g8q+e%J`1MaioP*O{Yf)gl?>vriJx11IGw67|HfJk|EpnRDs0Z)q z;v45nw3K)lql~A=M@Z)9FXHaDR4VJ5?D2U@T|PgW?CnXcw<}#H#;hE*cCn$BdHHnNc$OmJ1Ig{7&iS3&A2K9@wyL7k3ZoiKS2(c>fzP^HInQd8 z%_#Dbq&ctt z^^E%m(icwXNACEGq~Dz5-d3-2Yqi{(onAjRHk?mn@D_hDvB7(7rbpADgCG6r;)Cyb zg%I=k53%o%Vlm%{!d3C9v7qc#EFVIoJS*9+I1b>xsY9{Awr=^!?F~Y;pH|_(Gq4z$ z>$RrAc|D(xnd4r~CeM!6ebd+%?bg;Y`|6h;Tb&j}LOTB((->NO4nEt z*7@F%zgMqlr%i}a(>yx*H{PQdo?Egx9Oi*ol||`2(4UE~`K8DNYrfPs$lu!i$KY+0 zS}-4(Jn(jbSKxt^oSfdhD(kVp7gSeHR|qzjdB0?$-G%ZFB;XXZy?r$Re6l`CX6LWL;aPU!swAPn|j zA_s?)e6V7+;c_Ymk`dACws*ng+OUUvPu3)F!WQ?X9c%N8=9=`o-~2K7O85j%JoS4# zf*HQ8%X=p2QR1Xqyc=FKKFr0#G@?{i7|EX#q-hJO~HtqzCLj?Izxn3nZ)8_$g{B(W&X z=5;)#oF61HZ+(R*PetqAHRlsi%J^nDs#$MEx$?Vdc*g&(pz)4i@RlGAB3?t66o-)W zk82v{?eU(xXLvKbYj}mQwG7sn>v8sL2*OT@t0q6^2Vs3&u)^3C#Ac`PA^lw1-1zL7UZJqc_5SZ#di^0_|Kn#&|=0bk3Ue2jKy^W?3}urE&%)Y<;4WYc$x87Tk$8$`*hhPSM{x9hg5 zV3l~g(VW_I>M`ZMfRDs&bdTI<7>UG|mITkQD0? zP8`ZlUPXj;e)xT;7<(+gQ7xuEu=>Wo$a4qs9XJR-O=qz7doi`jkRtbZw`63`#NP!k zo;7!(@!mS(OIK!Tv-yi?o!*T~1ne3CUk`0Bf^gW) z^EmXObBEs+)c{9dgjs(b{zt^aI7sJ~=!m~&Qcr>RzT$aBQq=BZj}cqMd$I65{B_F9 zN9X5j#RlnK5AyU;vfCR{?~!W1#|}yn5k#LQRpn=Sf8GMGr!8D-zKW_`yv*voA7wn4 zd1P%lPyQ}^_BF8lu6C*eztxsGj#9h6MZFsu_)&TT$2=YSJtEonLT6g(tKYv0bByQX zN?`pSaVQ;gVS6CoDyPORw7rP=&k{aD z%7KK4V1ac&JnjQkJu$lm&r2(th9V=SWBKqgM#QaS4gfLU$PX&`o{N0E3G4jEE1z9A z4503s?8Rq8(6i;45WpW=<-H*JxC;C+X(euaHlTOT!OXqkd`BpMEOPuTNI8+zYN|Y) z&>(%!`YcF^*+rgaLCHwzi}|f4oL{YtF@RvL_x97~Rc&|#HLt-HWnz(3wd z?3;PlG0 zMY3-^NqM#>p*@gecw>;|I)6yRGT|t*1JFs-VM3EQM)NvU(-5WMZd8aK^zbSDTz4DW$YVFR!b18%Eqd#>!M;Hf2;icXD6m_-Qy9>IXN|Y?1%pmwSH_`GAyIi#U_& zp^WI3T-%j@kK`YZc9Aj$Kn&!b<|^39*-iIMEe=%Z_FNm z3uv;fHiEfO%~Iv>AX^lvv}~16wPQcdO%+PgHXW? zl}6*Z_g%RAP`nqVtX6#^{rr?3c+*FTLW76vw zc{&=llWPyJdue5@1Z2wmee7D=3-XTq;dA-xrTo}Tv6Z|nlV?30(jp~hJT*^!RoX?( z0i_xH!H93=J}4P6QYbg#t7Sg4b0Z%I+nk1Ww%%q%b4&e5Jdk@~bq7}cro{Z$gSS%m zM%YWAaq^xv+yip>7}u}iAO=#OwB29v6pi;?>KyU8OW&veoO?C?Tdxggh25T>`EcB~ z5PKq=>vlfXIOKWLuH9O5HCBV`XvPuNFpb}OdUGvqr;#lT(^TxAg2#O}nyHmmb-%<* z1wW71MICdyM6tJ;T=82!TPw|r=gRY@UGw1eA%=JvaGR0CTCk_M_Ff_hjUChjqnG&h z=!pYa>p|uL{u?R`;BUhA)of{hYmD9EwN^0NF}i%(qvq@kLx-DU#gSb&8+5SKd`{C+ z+nC4WLwQ9Z))W3U#Gly~*@h+9Ig)u>Eh@E)YhD*uIOVyN<9pkj)%4x-mo_?%N02GU zTW^7FW&gsraJDlv#(RtXHd`O4X;R94{_T0;EeGO8@Q`&vC!bdu8j-_VXs#%YaW&dY zuj~DB6sUK{S5r%rOQYx9aBg)Yk!6%_xw)vJv!~{)WO_bnj^(%(f3!<0G6Q(~16Duq zNwc5W2XZ=j(Rt)|n2b#^MoJz1l2kiX57O)P7%SHaw(n)JgwU&uQJgawlkFOUBRi3n z^os-iT%HxKaE$zaK8*1#^urtfL~1$pJI@<$JBQ{H`o~ChT_jC4jpVnU-k~(I1)}qY zc*DA`V5^H}uU2vfZk>gk<#BG=1MV+zryG@*sa?rlpS3x1$#`X}%Qc_MKT*cG{OT%V zn`hm$G%Hg?Z14%WzU!;(Sk;fU$Nf+pz;*DSX-%E+hYexDpju7PWbA>)@z%0X$!;+)tkSr+5YR zv#8;mh4rC_LIG;ZP+N9Q_UPjtRu>x$yE5OXGI=4-{TeDCZ#4fTPhfp1e*TB>{FC5~ zAZ!0amJ_S@{?*9du^$K2&)56cBYXdPRPW!6?ERZjy?;Bh_isn_{)dsh|6x?`*JMu< zq<(&xM~(lyQiok+<9esm&nNTO8qWOuW9Q7z*ZWr^IgjV(=ls_rd&l$h_I_t1(&G8~ zvF^^1%*`wFcz#UpcQPhv((c|5q-1nYFQn+eR9TmS=P6#Hkz~ zMD|Dt>h%86MfLe?fd+k#NjnGFVi&z$w@UQ!d!AgPRfIURDW&?Nj6wCqB*VA<|66h! zw1KJSYA>A2HoowVethA*C(9T10iK{{9=Sc^*$3g>Gs)g~j(ODU$20g$pC4mkoGYS7 zlX6q{t-wlR9}adH{WW~rm;ZSRByA`5v>b%I7jum~vF1atuYV56g%fFPe-Cg@PZ_~U zC&(U~45L(A5p_I-w$!i^8ISsR-?V)9hnDZYYx&N2?zyJ6j-DaT^LiF} z0*WLa`*^RH8^f1j$d|XYn7FqYvJ|PjrdT^I?rnygSXZCZ;@)P+gmv}#?WAb1DfwzI zOJ$ofE!J*^oLkp8v5GJy?qMx1KRZZI!c$HAo!m7o-lAV**}BI&^~_=|qPt(@{HNtJ kR}s3#i){b2{c`;v?$@$cdisL5EOu`{>u0SkQboc404zpO@&Et; diff --git a/Include/Expert/ExpertBase.mqh b/Include/Expert/ExpertBase.mqh deleted file mode 100644 index 2edde23..0000000 --- a/Include/Expert/ExpertBase.mqh +++ /dev/null @@ -1,715 +0,0 @@ -//+------------------------------------------------------------------+ -//| ExpertBase.mqh | -//| Copyright 2009-2017, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -#include -#include -#include -#include -#include -#include -//+------------------------------------------------------------------+ -//| enumerations | -//+------------------------------------------------------------------+ -//--- constants of identification of trend -enum ENUM_TYPE_TREND - { - TYPE_TREND_HARD_DOWN =0, // strong down trend - TYPE_TREND_DOWN =1, // down trend - TYPE_TREND_SOFT_DOWN =2, // weak down trend - TYPE_TREND_FLAT =3, // no trend - TYPE_TREND_SOFT_UP =4, // weak up trend - TYPE_TREND_UP =5, // up trend - TYPE_TREND_HARD_UP =6 // strong up trend - }; -//--- flags of used timeseries -enum ENUM_USED_SERIES - { - USE_SERIES_OPEN =0x1, - USE_SERIES_HIGH =0x2, - USE_SERIES_LOW =0x4, - USE_SERIES_CLOSE =0x8, - USE_SERIES_SPREAD =0x10, - USE_SERIES_TIME =0x20, - USE_SERIES_TICK_VOLUME=0x40, - USE_SERIES_REAL_VOLUME=0x80 - }; -//--- phases of initialization of an object -enum ENUM_INIT_PHASE - { - INIT_PHASE_FIRST =0, // start phase (only Init(...) can be called) - INIT_PHASE_TUNING =1, // phase of tuning (set in Init(...)) - INIT_PHASE_VALIDATION =2, // phase of checking of parameters(set in ValidationSettings(...)) - INIT_PHASE_COMPLETE =3 // end phase (set in InitIndicators(...)) - }; -//+------------------------------------------------------------------+ -//| Macro definitions. | -//+------------------------------------------------------------------+ -//--- check the use of timeseries -#define IS_OPEN_SERIES_USAGE ((m_used_series&USE_SERIES_OPEN)!=0) -#define IS_HIGH_SERIES_USAGE ((m_used_series&USE_SERIES_HIGH)!=0) -#define IS_LOW_SERIES_USAGE ((m_used_series&USE_SERIES_LOW)!=0) -#define IS_CLOSE_SERIES_USAGE ((m_used_series&USE_SERIES_CLOSE)!=0) -#define IS_SPREAD_SERIES_USAGE ((m_used_series&USE_SERIES_SPREAD)!=0) -#define IS_TIME_SERIES_USAGE ((m_used_series&USE_SERIES_TIME)!=0) -#define IS_TICK_VOLUME_SERIES_USAGE ((m_used_series&USE_SERIES_TICK_VOLUME)!=0) -#define IS_REAL_VOLUME_SERIES_USAGE ((m_used_series&USE_SERIES_REAL_VOLUME)!=0) -//+------------------------------------------------------------------+ -//| Class CExpertBase. | -//| Purpose: Base class of component of Expert Advisor. | -//| Derives from class CObject. | -//+------------------------------------------------------------------+ -class CExpertBase : public CObject - { -protected: - //--- variables - ulong m_magic; // expert magic number - ENUM_INIT_PHASE m_init_phase; // the phase (stage) of initialization of object - bool m_other_symbol; // flag of a custom work symbols (different from one of the Expert Advisor) - CSymbolInfo *m_symbol; // pointer to the object-symbol - bool m_other_period; // flag of a custom timeframe (different from one of the Expert Advisor) - ENUM_TIMEFRAMES m_period; // work timeframe - double m_adjusted_point; // "weight" 2/4 of a point - CAccountInfo m_account; // object-deposit - ENUM_ACCOUNT_MARGIN_MODE m_margin_mode; // netting or hedging - ENUM_TYPE_TREND m_trend_type; // identifier of trend - bool m_every_tick; // flag of starting the analysis from current (incomplete) bar - //--- timeseries - int m_used_series; // flags of using of series - CiOpen *m_open; // pointer to the object for access to open prices of bars - CiHigh *m_high; // pointer to the object for access to high prices of bars - CiLow *m_low; // pointer to the object for access to low prices of bars - CiClose *m_close; // pointer to the object for access to close prices of bars - CiSpread *m_spread; // pointer to the object for access to spreads - CiTime *m_time; // pointer to the object for access to time of closing of bars - CiTickVolume *m_tick_volume; // pointer to the object for access to tick volumes of bars - CiRealVolume *m_real_volume; // pointer to the object for access to real volumes of bars - -public: - CExpertBase(void); - ~CExpertBase(void); - //--- methods of access to protected data - ENUM_INIT_PHASE InitPhase(void) const { return(m_init_phase); } - void TrendType(ENUM_TYPE_TREND value) { m_trend_type=value; } - int UsedSeries(void) const; - void EveryTick(bool value) { m_every_tick=value; } - //--- methods of access to protected data - double Open(int ind) const; - double High(int ind) const; - double Low(int ind) const; - double Close(int ind) const; - int Spread(int ind) const; - datetime Time(int ind) const; - long TickVolume(int ind) const; - long RealVolume(int ind) const; - //--- methods of initialization of the object - virtual bool Init(CSymbolInfo *symbol,ENUM_TIMEFRAMES period,double point); - bool Symbol(string name); - bool Period(ENUM_TIMEFRAMES value); - void Magic(ulong value) { m_magic=value; } - void SetMarginMode(void) { m_margin_mode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE); } - //--- method of verification of settings - virtual bool ValidationSettings(); - //--- methods of creating the indicator and timeseries - virtual bool SetPriceSeries(CiOpen *open,CiHigh *high,CiLow *low,CiClose *close); - virtual bool SetOtherSeries(CiSpread *spread,CiTime *time,CiTickVolume *tick_volume,CiRealVolume *real_volume); - virtual bool InitIndicators(CIndicators *indicators=NULL); - -protected: - //--- methods initialization of timeseries - bool InitOpen(CIndicators *indicators); - bool InitHigh(CIndicators *indicators); - bool InitLow(CIndicators *indicators); - bool InitClose(CIndicators *indicators); - bool InitSpread(CIndicators *indicators); - bool InitTime(CIndicators *indicators); - bool InitTickVolume(CIndicators *indicators); - bool InitRealVolume(CIndicators *indicators); - //--- method of getting the measure units of price levels - virtual double PriceLevelUnit(void) { return(m_adjusted_point); } - //--- method of getting index of bar the analysis starts with - virtual int StartIndex(void) { return((m_every_tick?0:1)); } - virtual bool CompareMagic(ulong magic) { return(m_magic==magic); } - bool IsHedging(void) const { return(m_margin_mode==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING); } - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -void CExpertBase::CExpertBase(void) : m_magic(0), - m_margin_mode(ACCOUNT_MARGIN_MODE_RETAIL_NETTING), - m_init_phase(INIT_PHASE_FIRST), - m_other_symbol(false), - m_symbol(NULL), - m_other_period(false), - m_period(PERIOD_CURRENT), - m_adjusted_point(1.0), - m_trend_type(TYPE_TREND_FLAT), - m_every_tick(false), - m_used_series(0), - m_open(NULL), - m_high(NULL), - m_low(NULL), - m_close(NULL), - m_spread(NULL), - m_time(NULL), - m_tick_volume(NULL), - m_real_volume(NULL) - - { - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -void CExpertBase::~CExpertBase(void) - { -//--- if the symbol is "custom", delete it - if(m_other_symbol && m_symbol!=NULL) - delete m_symbol; -//--- release of "custom" timeseries - if(m_other_symbol || m_other_period) - { - if(IS_OPEN_SERIES_USAGE && CheckPointer(m_open)==POINTER_DYNAMIC) - delete m_open; - if(IS_HIGH_SERIES_USAGE && CheckPointer(m_high)==POINTER_DYNAMIC) - delete m_high; - if(IS_LOW_SERIES_USAGE && CheckPointer(m_low)==POINTER_DYNAMIC) - delete m_low; - if(IS_CLOSE_SERIES_USAGE && CheckPointer(m_close)==POINTER_DYNAMIC) - delete m_close; - if(IS_SPREAD_SERIES_USAGE && CheckPointer(m_spread)==POINTER_DYNAMIC) - delete m_spread; - if(IS_TIME_SERIES_USAGE && CheckPointer(m_time)==POINTER_DYNAMIC) - delete m_time; - if(IS_TICK_VOLUME_SERIES_USAGE && CheckPointer(m_tick_volume)==POINTER_DYNAMIC) - delete m_tick_volume; - if(IS_REAL_VOLUME_SERIES_USAGE && CheckPointer(m_real_volume)==POINTER_DYNAMIC) - delete m_real_volume; - } - } -//+------------------------------------------------------------------+ -//| Get flags of used timeseries | -//+------------------------------------------------------------------+ -int CExpertBase::UsedSeries(void) const - { - if(m_other_symbol || m_other_period) - return(0); -//--- - return(m_used_series); - } -//+------------------------------------------------------------------+ -//| Initialization of object. | -//+------------------------------------------------------------------+ -bool CExpertBase::Init(CSymbolInfo *symbol,ENUM_TIMEFRAMES period,double point) - { -//--- check the initialization phase - if(m_init_phase!=INIT_PHASE_FIRST) - { - Print(__FUNCTION__+": attempt of re-initialization"); - return(false); - } -//--- check of pointer - if(symbol==NULL) - { - Print(__FUNCTION__+": error initialization"); - return(false); - } -//--- initialization - m_symbol =symbol; - m_period =period; - m_adjusted_point=point; - m_other_symbol =false; - m_other_period =false; - SetMarginMode(); -//--- primary initialization is successful, pass to the phase of tuning - m_init_phase=INIT_PHASE_TUNING; -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Changing work symbol. | -//+------------------------------------------------------------------+ -bool CExpertBase::Symbol(string name) - { -//--- check the initialization phase - if(m_init_phase!=INIT_PHASE_TUNING) - { - Print(__FUNCTION__+": changing of symbol is forbidden"); - return(false); - } - if(m_symbol!=NULL) - { - //--- symbol has been already set - if(m_symbol.Name()==name) - return(true); - //--- symbol is not the one required, but is already "custom" - if(m_other_symbol) - { - if(!m_symbol.Name(name)) - { - //--- failed to initialize the symbol - delete m_symbol; - return(false); - } - return(true); - } - } - m_symbol=new CSymbolInfo; -//--- check of pointer - if(m_symbol==NULL) - { - Print(__FUNCTION__+": error of changing of symbol"); - return(false); - } - if(!m_symbol.Name(name)) - { - //--- failed to initialize the symbol - delete m_symbol; - return(false); - } - m_other_symbol=true; -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Changing work timeframe. | -//+------------------------------------------------------------------+ -bool CExpertBase::Period(ENUM_TIMEFRAMES value) - { -//--- check the initialization phase - if(m_init_phase!=INIT_PHASE_TUNING) - { - Print(__FUNCTION__+": changing of timeframe is forbidden"); - return(false); - } - if(m_period==value) - return(true); -//--- change work timeframe - m_period=value; - m_other_period=true; -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Checking adjustable parameters | -//+------------------------------------------------------------------+ -bool CExpertBase::ValidationSettings() - { -//--- rechecking parameters - if(m_init_phase==INIT_PHASE_VALIDATION) - return(true); -//--- check the initialization phase - if(m_init_phase!=INIT_PHASE_TUNING) - { - Print(__FUNCTION__+": not the right time to check parameters"); - return(false); - } -//--- initial check of parameters is successful, phase of tuning is over - m_init_phase=INIT_PHASE_VALIDATION; -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Setting pointers of price timeseries. | -//+------------------------------------------------------------------+ -bool CExpertBase::SetPriceSeries(CiOpen *open,CiHigh *high,CiLow *low,CiClose *close) - { -//--- check the initialization phase - if(m_init_phase!=INIT_PHASE_VALIDATION) - { - Print(__FUNCTION__+": changing of timeseries is forbidden"); - return(false); - } -//--- check pointers - if((IS_OPEN_SERIES_USAGE && open==NULL) || - (IS_HIGH_SERIES_USAGE && high==NULL) || - (IS_LOW_SERIES_USAGE && low==NULL) || - (IS_CLOSE_SERIES_USAGE && close==NULL)) - { - Print(__FUNCTION__+": NULL pointer"); - return(false); - } - m_open =open; - m_high =high; - m_low =low; - m_close=close; -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Setting pointers of other timeseries. | -//+------------------------------------------------------------------+ -bool CExpertBase::SetOtherSeries(CiSpread *spread,CiTime *time,CiTickVolume *tick_volume,CiRealVolume *real_volume) - { -//--- check the initialization phase - if(m_init_phase!=INIT_PHASE_VALIDATION) - { - Print(__FUNCTION__+": changing of timeseries is forbidden"); - return(false); - } -//--- check pointers - if((IS_SPREAD_SERIES_USAGE && spread==NULL) || - (IS_TIME_SERIES_USAGE && time==NULL) || - (IS_TICK_VOLUME_SERIES_USAGE && tick_volume==NULL) || - (IS_REAL_VOLUME_SERIES_USAGE && real_volume==NULL)) - { - Print(__FUNCTION__+": NULL pointer"); - return(false); - } - m_spread =spread; - m_time =time; - m_tick_volume=tick_volume; - m_real_volume=real_volume; -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialization of indicators and timeseries. | -//+------------------------------------------------------------------+ -bool CExpertBase::InitIndicators(CIndicators *indicators) - { -//--- this call is for compatibility with the previous version - if(!ValidationSettings()) - return(false); -//--- check the initialization phase - if(m_init_phase!=INIT_PHASE_VALIDATION) - { - Print(__FUNCTION__+": parameters of setting are not checked"); - return(false); - } - if(!m_other_symbol && !m_other_period) - return(true); -//--- check pointers - if(m_symbol==NULL) - return(false); - if(indicators==NULL) - return(false); -//--- initialization of required timeseries - if(IS_OPEN_SERIES_USAGE && !InitOpen(indicators)) - return(false); - if(IS_HIGH_SERIES_USAGE && !InitHigh(indicators)) - return(false); - if(IS_LOW_SERIES_USAGE && !InitLow(indicators)) - return(false); - if(IS_CLOSE_SERIES_USAGE && !InitClose(indicators)) - return(false); - if(IS_SPREAD_SERIES_USAGE && !InitSpread(indicators)) - return(false); - if(IS_TIME_SERIES_USAGE && !InitTime(indicators)) - return(false); - if(IS_TICK_VOLUME_SERIES_USAGE && !InitTickVolume(indicators)) - return(false); - if(IS_REAL_VOLUME_SERIES_USAGE && !InitRealVolume(indicators)) - return(false); -//--- initialization of object (from the point of view of the base class) has been performed successfully -//--- now it's impossible to change anything in the settings - m_init_phase=INIT_PHASE_COMPLETE; -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Access to data of the Open timeseries. | -//+------------------------------------------------------------------+ -double CExpertBase::Open(int ind) const - { -//--- check pointer - if(m_open==NULL) - return(EMPTY_VALUE); -//--- return the result - return(m_open.GetData(ind)); - } -//+------------------------------------------------------------------+ -//| Access to data of the High timeseries. | -//+------------------------------------------------------------------+ -double CExpertBase::High(int ind) const - { -//--- check pointer - if(m_high==NULL) - return(EMPTY_VALUE); -//--- return the result - return(m_high.GetData(ind)); - } -//+------------------------------------------------------------------+ -//| Access to data of the Low timeseries. | -//+------------------------------------------------------------------+ -double CExpertBase::Low(int ind) const - { -//--- check pointer - if(m_low==NULL) - return(EMPTY_VALUE); -//--- return the result - return(m_low.GetData(ind)); - } -//+------------------------------------------------------------------+ -//| Access to data of the Close timeseries. | -//+------------------------------------------------------------------+ -double CExpertBase::Close(int ind) const - { -//--- check pointer - if(m_close==NULL) - return(EMPTY_VALUE); -//--- return the result - return(m_close.GetData(ind)); - } -//+------------------------------------------------------------------+ -//| Access to data of the Spread timeseries. | -//+------------------------------------------------------------------+ -int CExpertBase::Spread(int ind) const - { -//--- check pointer - if(m_spread==NULL) - return(INT_MAX); -//--- return the result - return(m_spread.GetData(ind)); - } -//+------------------------------------------------------------------+ -//| Access to data of the Time timeseries. | -//+------------------------------------------------------------------+ -datetime CExpertBase::Time(int ind) const - { -//--- check pointer - if(m_time==NULL) - return(0); -//--- return the result - return(m_time.GetData(ind)); - } -//+------------------------------------------------------------------+ -//| Access to data of the TickVolume timeseries. | -//+------------------------------------------------------------------+ -long CExpertBase::TickVolume(int ind) const - { -//--- check pointer - if(m_tick_volume==NULL) - return(0); -//--- return the result - return(m_tick_volume.GetData(ind)); - } -//+------------------------------------------------------------------+ -//| Access to data of the RealVolume timeseries. | -//+------------------------------------------------------------------+ -long CExpertBase::RealVolume(int ind) const - { -//--- check pointer - if(m_real_volume==NULL) - return(0); -//--- return the result - return(m_real_volume.GetData(ind)); - } -//+------------------------------------------------------------------+ -//| Initialization of the Open timeseries. | -//+------------------------------------------------------------------+ -bool CExpertBase::InitOpen(CIndicators *indicators) - { -//--- create object - if((m_open=new CiOpen)==NULL) - { - Print(__FUNCTION__+": error creating object"); - return(false); - } -//--- add object to collection - if(!indicators.Add(m_open)) - { - Print(__FUNCTION__+": error adding object"); - delete m_open; - return(false); - } -//--- initialize object - if(!m_open.Create(m_symbol.Name(),m_period)) - { - Print(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialization of the High timeseries. | -//+------------------------------------------------------------------+ -bool CExpertBase::InitHigh(CIndicators *indicators) - { -//--- create object - if((m_high=new CiHigh)==NULL) - { - Print(__FUNCTION__+": error creating object"); - return(false); - } -//--- add object to collection - if(!indicators.Add(m_high)) - { - Print(__FUNCTION__+": error adding object"); - delete m_high; - return(false); - } -//--- initialize object - if(!m_high.Create(m_symbol.Name(),m_period)) - { - Print(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialization of the Low timeseries. | -//+------------------------------------------------------------------+ -bool CExpertBase::InitLow(CIndicators *indicators) - { -//--- create object - if((m_low=new CiLow)==NULL) - { - Print(__FUNCTION__+": error creating object"); - return(false); - } -//--- add object to collection - if(!indicators.Add(m_low)) - { - Print(__FUNCTION__+": error adding object"); - delete m_low; - return(false); - } -//--- initialize object - if(!m_low.Create(m_symbol.Name(),m_period)) - { - Print(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialization of the Close timeseries. | -//+------------------------------------------------------------------+ -bool CExpertBase::InitClose(CIndicators *indicators) - { -//--- create object - if((m_close=new CiClose)==NULL) - { - Print(__FUNCTION__+": error creating object"); - return(false); - } -//--- add object to collection - if(!indicators.Add(m_close)) - { - Print(__FUNCTION__+": error adding object"); - delete m_close; - return(false); - } -//--- initialize object - if(!m_close.Create(m_symbol.Name(),m_period)) - { - Print(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialization of the Spread timeseries. | -//+------------------------------------------------------------------+ -bool CExpertBase::InitSpread(CIndicators *indicators) - { -//--- create object - if((m_spread=new CiSpread)==NULL) - { - Print(__FUNCTION__+": error creating object"); - return(false); - } -//--- add object to collection - if(!indicators.Add(m_spread)) - { - Print(__FUNCTION__+": error adding object"); - delete m_spread; - return(false); - } -//--- initialize object - if(!m_spread.Create(m_symbol.Name(),m_period)) - { - Print(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialization of the Time timeseries. | -//+------------------------------------------------------------------+ -bool CExpertBase::InitTime(CIndicators *indicators) - { -//--- create object - if((m_time=new CiTime)==NULL) - { - Print(__FUNCTION__+": error creating object"); - return(false); - } -//--- add object to collection - if(!indicators.Add(m_time)) - { - Print(__FUNCTION__+": error adding object"); - delete m_time; - return(false); - } -//--- initialize object - if(!m_time.Create(m_symbol.Name(),m_period)) - { - Print(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialization of the TickVolume timeseries. | -//+------------------------------------------------------------------+ -bool CExpertBase::InitTickVolume(CIndicators *indicators) - { -//--- create object - if((m_tick_volume=new CiTickVolume)==NULL) - { - Print(__FUNCTION__+": error creating object"); - return(false); - } -//--- add object to collection - if(!indicators.Add(m_tick_volume)) - { - Print(__FUNCTION__+": error adding object"); - delete m_tick_volume; - return(false); - } -//--- initialize object - if(!m_tick_volume.Create(m_symbol.Name(),m_period)) - { - Print(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialization of the RealVolume timeseries. | -//+------------------------------------------------------------------+ -bool CExpertBase::InitRealVolume(CIndicators *indicators) - { -//--- create object - if((m_real_volume=new CiRealVolume)==NULL) - { - Print(__FUNCTION__+": error creating object"); - return(false); - } -//--- add object to collection - if(!indicators.Add(m_real_volume)) - { - Print(__FUNCTION__+": error adding object"); - delete m_real_volume; - return(false); - } -//--- initialize object - if(!m_real_volume.Create(m_symbol.Name(),m_period)) - { - Print(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/ExpertMoney.mqh b/Include/Expert/ExpertMoney.mqh deleted file mode 100644 index 393f832..0000000 --- a/Include/Expert/ExpertMoney.mqh +++ /dev/null @@ -1,124 +0,0 @@ -//+------------------------------------------------------------------+ -//| ExpertMoney.mqh | -//| Copyright 2009-2017, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include "ExpertBase.mqh" -//+------------------------------------------------------------------+ -//| Class CExpertMoney. | -//| Purpose: Base class money managment. | -//| Derives from class CExpertBase. | -//+------------------------------------------------------------------+ -class CExpertMoney : public CExpertBase - { -protected: - //--- input parameters - double m_percent; - -public: - CExpertMoney(void); - ~CExpertMoney(void); - //--- methods of setting adjustable parameters - void Percent(double percent) { m_percent=percent; } - //--- method of verification of settings - virtual bool ValidationSettings(); - //--- - virtual double CheckOpenLong(double price,double sl); - virtual double CheckOpenShort(double price,double sl); - virtual double CheckReverse(CPositionInfo *position,double sl); - virtual double CheckClose(CPositionInfo *position); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -void CExpertMoney::CExpertMoney(void) : m_percent(10.0) - { - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -void CExpertMoney::~CExpertMoney(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CExpertMoney::ValidationSettings() - { - if(!CExpertBase::ValidationSettings()) - return(false); -//--- initial data checks - if(m_percent<0.0 || m_percent>100.0) - { - printf(__FUNCTION__+": percentage of risk should be in the range from 0 to 100 inclusive"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Getting lot size for open long position. | -//+------------------------------------------------------------------+ -double CExpertMoney::CheckOpenLong(double price,double sl) - { - if(m_symbol==NULL) - return(0.0); -//--- - double lot; - if(price==0.0) - lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_BUY,m_symbol.Ask(),m_percent); - else - lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_BUY,price,m_percent); - if(lotm_account.Balance()*m_percent/100.0) - return(position.Volume()); -//--- - return(0.0); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/ExpertSignal.mqh b/Include/Expert/ExpertSignal.mqh deleted file mode 100644 index 994cb79..0000000 --- a/Include/Expert/ExpertSignal.mqh +++ /dev/null @@ -1,464 +0,0 @@ -//+------------------------------------------------------------------+ -//| ExpertSignal.mqh | -//| Copyright 2009-2017, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include "ExpertBase.mqh" -//+------------------------------------------------------------------+ -//| Macro definitions. | -//+------------------------------------------------------------------+ -//--- check if a market model is used -#define IS_PATTERN_USAGE(p) ((m_patterns_usage&(((int)1)<=m_threshold_open) - { - //--- there's a signal - result=true; - //--- try to get the levels of opening - if(!OpenLongParams(price,sl,tp,expiration)) - result=false; - } -//--- zeroize the base price - m_base_price=0.0; -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ -//| Generating a sell signal | -//+------------------------------------------------------------------+ -bool CExpertSignal::CheckOpenShort(double &price,double &sl,double &tp,datetime &expiration) - { - bool result =false; -//--- the "prohibition" signal - if(m_direction==EMPTY_VALUE) - return(false); -//--- check of exceeding the threshold value - if(-m_direction>=m_threshold_open) - { - //--- there's a signal - result=true; - //--- try to get the levels of opening - if(!OpenShortParams(price,sl,tp,expiration)) - result=false; - } -//--- zeroize the base price - m_base_price=0.0; -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ -//| Detecting the levels for buying | -//+------------------------------------------------------------------+ -bool CExpertSignal::OpenLongParams(double &price,double &sl,double &tp,datetime &expiration) - { - CExpertSignal *general=(m_general!=-1) ? m_filters.At(m_general) : NULL; -//--- - if(general==NULL) - { - //--- if a base price is not specified explicitly, take the current market price - double base_price=(m_base_price==0.0) ? m_symbol.Ask() : m_base_price; - price =m_symbol.NormalizePrice(base_price-m_price_level*PriceLevelUnit()); - sl =(m_stop_level==0.0) ? 0.0 : m_symbol.NormalizePrice(price-m_stop_level*PriceLevelUnit()); - tp =(m_take_level==0.0) ? 0.0 : m_symbol.NormalizePrice(price+m_take_level*PriceLevelUnit()); - expiration+=m_expiration*PeriodSeconds(m_period); - return(true); - } -//--- - return(general.OpenLongParams(price,sl,tp,expiration)); - } -//+------------------------------------------------------------------+ -//| Detecting the levels for selling | -//+------------------------------------------------------------------+ -bool CExpertSignal::OpenShortParams(double &price,double &sl,double &tp,datetime &expiration) - { - CExpertSignal *general=(m_general!=-1) ? m_filters.At(m_general) : NULL; -//--- - if(general==NULL) - { - //--- if a base price is not specified explicitly, take the current market price - double base_price=(m_base_price==0.0) ? m_symbol.Bid() : m_base_price; - price =m_symbol.NormalizePrice(base_price+m_price_level*PriceLevelUnit()); - sl =(m_stop_level==0.0) ? 0.0 : m_symbol.NormalizePrice(price+m_stop_level*PriceLevelUnit()); - tp =(m_take_level==0.0) ? 0.0 : m_symbol.NormalizePrice(price-m_take_level*PriceLevelUnit()); - expiration+=m_expiration*PeriodSeconds(m_period); - return(true); - } -//--- - return(general.OpenShortParams(price,sl,tp,expiration)); - } -//+------------------------------------------------------------------+ -//| Generating a signal for closing of a long position | -//+------------------------------------------------------------------+ -bool CExpertSignal::CheckCloseLong(double &price) - { - bool result =false; -//--- the "prohibition" signal - if(m_direction==EMPTY_VALUE) - return(false); -//--- check of exceeding the threshold value - if(-m_direction>=m_threshold_close) - { - //--- there's a signal - result=true; - //--- try to get the level of closing - if(!CloseLongParams(price)) - result=false; - } -//--- zeroize the base price - m_base_price=0.0; -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ -//| Generating a signal for closing a short position | -//+------------------------------------------------------------------+ -bool CExpertSignal::CheckCloseShort(double &price) - { - bool result =false; -//--- the "prohibition" signal - if(m_direction==EMPTY_VALUE) - return(false); -//--- check of exceeding the threshold value - if(m_direction>=m_threshold_close) - { - //--- there's a signal - result=true; - //--- try to get the level of closing - if(!CloseShortParams(price)) - result=false; - } -//--- zeroize the base price - m_base_price=0.0; -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ -//| Detecting the levels for closing a long position | -//+------------------------------------------------------------------+ -bool CExpertSignal::CloseLongParams(double &price) - { - CExpertSignal *general=(m_general!=-1) ? m_filters.At(m_general) : NULL; -//--- - if(general==NULL) - { - //--- if a base price is not specified explicitly, take the current market price - price=(m_base_price==0.0) ? m_symbol.Bid() : m_base_price; - return(true); - } -//--- - return(general.CloseLongParams(price)); - } -//+------------------------------------------------------------------+ -//| Detecting the levels for closing a short position | -//+------------------------------------------------------------------+ -bool CExpertSignal::CloseShortParams(double &price) - { - CExpertSignal *general=(m_general!=-1) ? m_filters.At(m_general) : NULL; -//--- - if(general==NULL) - { - //--- if a base price is not specified explicitly, take the current market price - price=(m_base_price==0.0)?m_symbol.Ask():m_base_price; - return(true); - } -//--- ok - return(general.CloseShortParams(price)); - } -//+------------------------------------------------------------------+ -//| Generating a signal for reversing a long position | -//+------------------------------------------------------------------+ -bool CExpertSignal::CheckReverseLong(double &price,double &sl,double &tp,datetime &expiration) - { - double c_price; -//--- check the signal of closing a long position - if(!CheckCloseLong(c_price)) - return(false); -//--- check the signal of opening a short position - if(!CheckOpenShort(price,sl,tp,expiration)) - return(false); -//--- difference between the close and open prices must not exceed two spreads - if(c_price!=price) - return(false); -//--- there's a signal - return(true); - } -//+------------------------------------------------------------------+ -//| Generating a signal for reversing a short position | -//+------------------------------------------------------------------+ -bool CExpertSignal::CheckReverseShort(double &price,double &sl,double &tp,datetime &expiration) - { - double c_price; -//--- check the signal of closing a short position - if(!CheckCloseShort(c_price)) - return(false); -//--- check the signal of opening a long position - if(!CheckOpenLong(price,sl,tp,expiration)) - return(false); -//--- difference between the close and open prices must not exceed two spreads - if(c_price!=price) - return(false); -//--- there's a signal - return(true); - } -//+------------------------------------------------------------------+ -//| Detecting the "weighted" direction | -//+------------------------------------------------------------------+ -double CExpertSignal::Direction(void) - { - long mask; - double direction; - double result=m_weight*(LongCondition()-ShortCondition()); - int number=(result==0.0)? 0 : 1; // number of "voted" -//--- - int total=m_filters.Total(); -//--- loop by filters - for(int i=0;i -#include -#include -#include -#include -//+------------------------------------------------------------------+ -//| Class CExpertTrade. | -//| Appointment: Class simple trade operations. | -//| Derives from class CTrade. | -//+------------------------------------------------------------------+ -class CExpertTrade : public CTrade - { -protected: - ENUM_ORDER_TYPE_TIME m_order_type_time; - datetime m_order_expiration; - CSymbolInfo *m_symbol; // symbol object - CAccountInfo m_account; // account object - -public: - CExpertTrade(void); - ~CExpertTrade(void); - //--- methods for easy trade - bool SetSymbol(CSymbolInfo *symbol); - bool SetOrderTypeTime(ENUM_ORDER_TYPE_TIME order_type_time); - bool SetOrderExpiration(datetime order_expiration); - bool Buy(double volume,double price,double sl,double tp,const string comment=""); - bool Sell(double volume,double price,double sl,double tp,const string comment=""); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -void CExpertTrade::CExpertTrade(void) : m_symbol(NULL), - m_order_type_time(ORDER_TIME_GTC), - m_order_expiration(0) - { - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CExpertTrade::~CExpertTrade(void) - { - } -//+------------------------------------------------------------------+ -//| Setting working symbol for easy trade operations. | -//+------------------------------------------------------------------+ -bool CExpertTrade::SetSymbol(CSymbolInfo *symbol) - { - if(symbol!=NULL) - { - m_symbol=symbol; - return(true); - } -//--- - return(false); - } -//+------------------------------------------------------------------+ -//| Setting order expiration type for easy trade operations | -//+------------------------------------------------------------------+ -bool CExpertTrade::SetOrderTypeTime(ENUM_ORDER_TYPE_TIME order_type_time) - { - if(m_symbol==NULL) - return(false); -//--- - if(order_type_time==ORDER_TIME_SPECIFIED) - { - if((m_symbol.TradeTimeFlags()&SYMBOL_EXPIRATION_SPECIFIED)==0) - { - m_order_type_time =ORDER_TIME_GTC; - m_order_expiration=0; - return(false); - } - } -//--- - m_order_type_time=order_type_time; -//--- succeed - return(true); - } -//+------------------------------------------------------------------+ -//| Setting order expiration time for easy trade operations | -//+------------------------------------------------------------------+ -bool CExpertTrade::SetOrderExpiration(datetime order_expiration) - { - if(m_symbol==NULL) - return(false); -//--- check expiration - if(order_expiration>=TimeCurrent()+60) - { - if(!SetOrderTypeTime(ORDER_TIME_SPECIFIED)) - return(false); - m_order_expiration=order_expiration; - } - else - { - m_order_type_time=ORDER_TIME_GTC; - m_order_expiration=0; - } -//--- succeed - return(true); - } -//+------------------------------------------------------------------+ -//| Easy LONG trade operation | -//+------------------------------------------------------------------+ -bool CExpertTrade::Buy(double volume,double price,double sl,double tp,const string comment="") - { - double ask,stops_level; -//--- checking - if(m_symbol==NULL) - return(false); - string symbol=m_symbol.Name(); - if(symbol=="") - return(false); -//--- - ask=m_symbol.Ask(); - stops_level=m_symbol.StopsLevel()*m_symbol.Point(); - if(price!=0.0) - { - if(price>ask+stops_level) - { - //--- send "BUY_STOP" order - return(OrderOpen(symbol,ORDER_TYPE_BUY_STOP,volume,0.0,price,sl,tp, - m_order_type_time,m_order_expiration,comment)); - } - if(pricebid+stops_level) - { - //--- send "SELL_LIMIT" order - return(OrderOpen(symbol,ORDER_TYPE_SELL_LIMIT,volume,0.0,price,sl,tp, - m_order_type_time,m_order_expiration,comment)); - } - if(price -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Trading with fixed trade volume | -//| Type=Money | -//| Name=FixLot | -//| Class=CMoneyFixedLot | -//| Page= | -//| Parameter=Percent,double,10.0,Percent | -//| Parameter=Lots,double,0.1,Fixed volume | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CMoneyFixedLot. | -//| Purpose: Class of money management with fixed lot. | -//| Derives from class CExpertMoney. | -//+------------------------------------------------------------------+ -class CMoneyFixedLot : public CExpertMoney - { -protected: - //--- input parameters - double m_lots; - -public: - CMoneyFixedLot(void); - ~CMoneyFixedLot(void); - //--- - void Lots(double lots) { m_lots=lots; } - virtual bool ValidationSettings(void); - //--- - virtual double CheckOpenLong(double price,double sl) { return(m_lots); } - virtual double CheckOpenShort(double price,double sl) { return(m_lots); } - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -void CMoneyFixedLot::CMoneyFixedLot(void) : m_lots(0.1) - { - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -void CMoneyFixedLot::~CMoneyFixedLot(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CMoneyFixedLot::ValidationSettings(void) - { - if(!CExpertMoney::ValidationSettings()) - return(false); -//--- initial data checks - if(m_lotsm_symbol.LotsMax()) - { - printf(__FUNCTION__+": lots amount must be in the range from %f to %f",m_symbol.LotsMin(),m_symbol.LotsMax()); - return(false); - } - if(MathAbs(m_lots/m_symbol.LotsStep()-MathRound(m_lots/m_symbol.LotsStep()))>1.0E-10) - { - printf(__FUNCTION__+": lots amount is not corresponding with lot step %f",m_symbol.LotsStep()); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Money/MoneyFixedMargin.mqh b/Include/Expert/Money/MoneyFixedMargin.mqh deleted file mode 100644 index 18acb7e..0000000 --- a/Include/Expert/Money/MoneyFixedMargin.mqh +++ /dev/null @@ -1,76 +0,0 @@ -//+------------------------------------------------------------------+ -//| MoneyFixedMargin.mqh | -//| Copyright 2009-2017, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Trading with fixed margin | -//| Type=Money | -//| Name=FixMargin | -//| Class=CMoneyFixedMargin | -//| Page= | -//| Parameter=Percent,double,10.0,Percentage of margin | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CMoneyFixedMargin. | -//| Purpose: Class of money management with fixed percent margin. | -//| Derives from class CExpertMoney. | -//+------------------------------------------------------------------+ -class CMoneyFixedMargin : public CExpertMoney - { -public: - CMoneyFixedMargin(void); - ~CMoneyFixedMargin(void); - //--- - virtual double CheckOpenLong(double price,double sl); - virtual double CheckOpenShort(double price,double sl); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -void CMoneyFixedMargin::CMoneyFixedMargin(void) - { - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -void CMoneyFixedMargin::~CMoneyFixedMargin(void) - { - } -//+------------------------------------------------------------------+ -//| Getting lot size for open long position. | -//+------------------------------------------------------------------+ -double CMoneyFixedMargin::CheckOpenLong(double price,double sl) - { - if(m_symbol==NULL) - return(0.0); -//--- select lot size - double lot; - if(price==0.0) - lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_BUY,m_symbol.Ask(),m_percent); - else - lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_BUY,price,m_percent); -//--- return trading volume - return(lot); - } -//+------------------------------------------------------------------+ -//| Getting lot size for open short position. | -//+------------------------------------------------------------------+ -double CMoneyFixedMargin::CheckOpenShort(double price,double sl) - { - if(m_symbol==NULL) - return(0.0); -//--- select lot size - double lot; - if(price==0.0) - lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_SELL,m_symbol.Bid(),m_percent); - else - lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_SELL,price,m_percent); -//--- return trading volume - return(lot); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Money/MoneyFixedRisk.mqh b/Include/Expert/Money/MoneyFixedRisk.mqh deleted file mode 100644 index e022be0..0000000 --- a/Include/Expert/Money/MoneyFixedRisk.mqh +++ /dev/null @@ -1,109 +0,0 @@ -//+------------------------------------------------------------------+ -//| MoneyFixedRisk.mqh | -//| Copyright 2009-2017, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Trading with fixed risk | -//| Type=Money | -//| Name=FixRisk | -//| Class=CMoneyFixedRisk | -//| Page= | -//| Parameter=Percent,double,10.0,Risk percentage | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CMoneyFixedRisk. | -//| Purpose: Class of money management with fixed percent risk. | -//| Derives from class CExpertMoney. | -//+------------------------------------------------------------------+ -class CMoneyFixedRisk : public CExpertMoney - { -public: - CMoneyFixedRisk(void); - ~CMoneyFixedRisk(void); - //--- - virtual double CheckOpenLong(double price,double sl); - virtual double CheckOpenShort(double price,double sl); - virtual double CheckClose(CPositionInfo *position) { return(0.0); } - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -void CMoneyFixedRisk::CMoneyFixedRisk(void) - { - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -void CMoneyFixedRisk::~CMoneyFixedRisk(void) - { - } -//+------------------------------------------------------------------+ -//| Getting lot size for open long position. | -//+------------------------------------------------------------------+ -double CMoneyFixedRisk::CheckOpenLong(double price,double sl) - { - if(m_symbol==NULL) - return(0.0); -//--- select lot size - double lot; - double minvol=m_symbol.LotsMin(); - if(sl==0.0) - lot=minvol; - else - { - double loss; - if(price==0.0) - loss=-m_account.OrderProfitCheck(m_symbol.Name(),ORDER_TYPE_BUY,1.0,m_symbol.Ask(),sl); - else - loss=-m_account.OrderProfitCheck(m_symbol.Name(),ORDER_TYPE_BUY,1.0,price,sl); - double stepvol=m_symbol.LotsStep(); - lot=MathFloor(m_account.Balance()*m_percent/loss/100.0/stepvol)*stepvol; - } -//--- - if(lotmaxvol) - lot=maxvol; -//--- return trading volume - return(lot); - } -//+------------------------------------------------------------------+ -//| Getting lot size for open short position. | -//+------------------------------------------------------------------+ -double CMoneyFixedRisk::CheckOpenShort(double price,double sl) - { - if(m_symbol==NULL) - return(0.0); -//--- select lot size - double lot; - double minvol=m_symbol.LotsMin(); - if(sl==0.0) - lot=minvol; - else - { - double loss; - if(price==0.0) - loss=-m_account.OrderProfitCheck(m_symbol.Name(),ORDER_TYPE_SELL,1.0,m_symbol.Bid(),sl); - else - loss=-m_account.OrderProfitCheck(m_symbol.Name(),ORDER_TYPE_SELL,1.0,price,sl); - double stepvol=m_symbol.LotsStep(); - lot=MathFloor(m_account.Balance()*m_percent/loss/100.0/stepvol)*stepvol; - } -//--- - if(lotmaxvol) - lot=maxvol; -//--- return trading volume - return(lot); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Money/MoneyNone.mqh b/Include/Expert/Money/MoneyNone.mqh deleted file mode 100644 index d389c6e..0000000 --- a/Include/Expert/Money/MoneyNone.mqh +++ /dev/null @@ -1,71 +0,0 @@ -//+------------------------------------------------------------------+ -//| MoneyNone.mqh | -//| Copyright 2009-2017, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Trading with minimal allowed trade volume | -//| Type=Money | -//| Name=MinLot | -//| Class=CMoneyNone | -//| Page= | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CMoneyNone. | -//| Appointment: Class no money managment. | -//| Derives from class CExpertMoney. | -//+------------------------------------------------------------------+ -class CMoneyNone : public CExpertMoney - { -public: - CMoneyNone(void); - ~CMoneyNone(void); - //--- - virtual bool ValidationSettings(void); - //--- - virtual double CheckOpenLong(double price,double sl); - virtual double CheckOpenShort(double price,double sl); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -void CMoneyNone::CMoneyNone(void) - { - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -void CMoneyNone::~CMoneyNone(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CMoneyNone::ValidationSettings(void) - { - Percent(100.0); -//--- initial data checks - if(!CExpertMoney::ValidationSettings()) - return(false); -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Getting lot size for open long position. | -//+------------------------------------------------------------------+ -double CMoneyNone::CheckOpenLong(double price,double sl) - { - return(m_symbol.LotsMin()); - } -//+------------------------------------------------------------------+ -//| Getting lot size for open short position. | -//+------------------------------------------------------------------+ -double CMoneyNone::CheckOpenShort(double price,double sl) - { - return(m_symbol.LotsMin()); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Money/MoneySizeOptimized.mqh b/Include/Expert/Money/MoneySizeOptimized.mqh deleted file mode 100644 index 71a2628..0000000 --- a/Include/Expert/Money/MoneySizeOptimized.mqh +++ /dev/null @@ -1,155 +0,0 @@ -//+------------------------------------------------------------------+ -//| MoneySizeOptimized.mqh | -//| Copyright 2009-2017, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Trading with optimized trade volume | -//| Type=Money | -//| Name=SizeOptimized | -//| Class=CMoneySizeOptimized | -//| Page= | -//| Parameter=DecreaseFactor,double,3.0,Decrease factor | -//| Parameter=Percent,double,10.0,Percent | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CMoneySizeOptimized. | -//| Purpose: Class of money management with size optimized. | -//| Derives from class CExpertMoney. | -//+------------------------------------------------------------------+ -class CMoneySizeOptimized : public CExpertMoney - { -protected: - double m_decrease_factor; - -public: - CMoneySizeOptimized(void); - ~CMoneySizeOptimized(void); - //--- - void DecreaseFactor(double decrease_factor) { m_decrease_factor=decrease_factor; } - virtual bool ValidationSettings(void); - //--- - virtual double CheckOpenLong(double price,double sl); - virtual double CheckOpenShort(double price,double sl); - -protected: - double Optimize(double lots); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -void CMoneySizeOptimized::CMoneySizeOptimized(void) : m_decrease_factor(3.0) - { - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -void CMoneySizeOptimized::~CMoneySizeOptimized(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CMoneySizeOptimized::ValidationSettings(void) - { - if(!CExpertMoney::ValidationSettings()) - return(false); -//--- initial data checks - if(m_decrease_factor<=0.0) - { - printf(__FUNCTION__+": decrease factor must be greater then 0"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Getting lot size for open long position. | -//+------------------------------------------------------------------+ -double CMoneySizeOptimized::CheckOpenLong(double price,double sl) - { - if(m_symbol==NULL) - return(0.0); -//--- select lot size - double lot; - if(price==0.0) - lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_BUY,m_symbol.Ask(),m_percent); - else - lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_BUY,price,m_percent); -//--- return trading volume - return(Optimize(lot)); - } -//+------------------------------------------------------------------+ -//| Getting lot size for open short position. | -//+------------------------------------------------------------------+ -double CMoneySizeOptimized::CheckOpenShort(double price,double sl) - { - if(m_symbol==NULL) - return(0.0); -//--- select lot size - double lot; - if(price==0.0) - lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_SELL,m_symbol.Bid(),m_percent); - else - lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_SELL,price,m_percent); -//--- return trading volume - return(Optimize(lot)); - } -//+------------------------------------------------------------------+ -//| Optimizing lot size for open. | -//+------------------------------------------------------------------+ -double CMoneySizeOptimized::Optimize(double lots) - { - double lot=lots; -//--- calculate number of losses orders without a break - if(m_decrease_factor>0) - { - //--- select history for access - HistorySelect(0,TimeCurrent()); - //--- - int orders=HistoryDealsTotal(); // total history deals - int losses=0; // number of consequent losing orders - CDealInfo deal; - //--- - for(int i=orders-1;i>=0;i--) - { - deal.Ticket(HistoryDealGetTicket(i)); - if(deal.Ticket()==0) - { - Print("CMoneySizeOptimized::Optimize: HistoryDealGetTicket failed, no trade history"); - break; - } - //--- check symbol - if(deal.Symbol()!=m_symbol.Name()) - continue; - //--- check profit - double profit=deal.Profit(); - if(profit>0.0) - break; - if(profit<0.0) - losses++; - } - //--- - if(losses>1) - lot=NormalizeDouble(lot-lot*losses/m_decrease_factor,2); - } -//--- normalize and check limits - double stepvol=m_symbol.LotsStep(); - lot=stepvol*NormalizeDouble(lot/stepvol,0); -//--- - double minvol=m_symbol.LotsMin(); - if(lotmaxvol) - lot=maxvol; -//--- - return(lot); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Signal/SignalAC.mqh b/Include/Expert/Signal/SignalAC.mqh deleted file mode 100644 index 9565897..0000000 --- a/Include/Expert/Signal/SignalAC.mqh +++ /dev/null @@ -1,173 +0,0 @@ -//+------------------------------------------------------------------+ -//| SignalAC.mqh | -//| Copyright 2009-2013, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Signals of indicator 'Accelerator Oscillator' | -//| Type=SignalAdvanced | -//| Name=Accelerator Oscillator | -//| ShortName=AC | -//| Class=CSignalAC | -//| Page=signal_ac | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CSignalAC. | -//| Purpose: Class of generator of trade signals based on | -//| the 'Accelerator Oscillator' indicator. | -//| Is derived from the CExpertSignal class. | -//+------------------------------------------------------------------+ -class CSignalAC : public CExpertSignal - { -protected: - CiAC m_ac; // object-indicator - //--- "weights" of market models (0-100) - int m_pattern_0; // model 0 "first analyzed bar has required color" - int m_pattern_1; // model 1 "there is a condition for entering the market" - int m_pattern_2; // model 2 "condition for entering the market has just appeared" - -public: - CSignalAC(void); - ~CSignalAC(void); - //--- methods of adjusting "weights" of market models - void Pattern_0(int value) { m_pattern_0=value; } - void Pattern_1(int value) { m_pattern_1=value; } - void Pattern_2(int value) { m_pattern_2=value; } - //--- method of creating the indicator and timeseries - virtual bool InitIndicators(CIndicators *indicators); - //--- methods of checking if the market models are formed - virtual int LongCondition(void); - virtual int ShortCondition(void); - -protected: - //--- method of initialization of the indicator - bool InitAC(CIndicators *indicators); - //--- methods of getting data - double AC(int ind) { return(m_ac.Main(ind)); } - double DiffAC(int ind) { return(AC(ind)-AC(ind+1)); } - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CSignalAC::CSignalAC(void) : m_pattern_0(90), - m_pattern_1(50), - m_pattern_2(30) - { - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSignalAC::~CSignalAC(void) - { - } -//+------------------------------------------------------------------+ -//| Create indicators. | -//+------------------------------------------------------------------+ -bool CSignalAC::InitIndicators(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- initialization of indicators and timeseries of additional filters - if(!CExpertSignal::InitIndicators(indicators)) - return(false); -//--- create and initialize AC indicator - if(!InitAC(indicators)) - return(false); -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialize AC indicators. | -//+------------------------------------------------------------------+ -bool CSignalAC::InitAC(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- add object to collection - if(!indicators.Add(GetPointer(m_ac))) - { - printf(__FUNCTION__+": error adding object"); - return(false); - } -//--- initialize object - if(!m_ac.Create(m_symbol.Name(),m_period)) - { - printf(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will grow. | -//+------------------------------------------------------------------+ -int CSignalAC::LongCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- if the first analyzed bar is "red", don't "vote" for buying - if(DiffAC(idx++)<0.0) - return(result); -//--- first analyzed bar is "green" (the indicator has no objections to buying) - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; -//--- if the second analyzed bar is "red", there is no condition for buying - if(DiffAC(idx)<0.0) - return(result); -//--- second analyzed bar is "green" (the condition for buying may be fulfilled) -//--- if the second analyzed bar is less than zero, we need to analyzed the third bar - if(AC(idx++)<0.0) - { - //--- if the third analyzed bar is "red", there is no condition for buying - if(DiffAC(idx++)<0.0) - return(result); - } -//--- there is a condition for buying - if(IS_PATTERN_USAGE(1)) - result=m_pattern_1; -//--- if the previously analyzed bar is "red", the condition for buying has just been fulfilled - if(IS_PATTERN_USAGE(2) && DiffAC(idx)<0.0) - result=m_pattern_2; -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will fall. | -//+------------------------------------------------------------------+ -int CSignalAC::ShortCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- if the first analyzed bar is "green", don't "vote" for selling - if(DiffAC(idx++)>0.0) - return(result); -//--- first analyzed bar is "red" (the indicator has no objections to selling) - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; -//--- if the second analyzed bar is "green", there is no condition for selling - if(DiffAC(idx)>0.0) - return(result); -//--- second analyzed bar is "red" (the condition for selling may be fulfilled) -//--- if the second analyzed bar is greater than zero, we need to analyze the third bar - if(AC(idx++)>0.0) - { - //--- if the third analyzed bar is "green", there is no condition for selling - if(DiffAC(idx++)>0.0) - return(result); - } -//--- there us a condition for selling - if(IS_PATTERN_USAGE(1)) - result=m_pattern_1; -//--- if the previously analyzed bar is "green", the condition for selling has just been fulfilled - if(IS_PATTERN_USAGE(2) && DiffAC(idx)>0.0) - result=m_pattern_2; -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Signal/SignalAMA.mqh b/Include/Expert/Signal/SignalAMA.mqh deleted file mode 100644 index 3d968e3..0000000 --- a/Include/Expert/Signal/SignalAMA.mqh +++ /dev/null @@ -1,265 +0,0 @@ -//+------------------------------------------------------------------+ -//| SignalAMA.mqh | -//| Copyright 2009-2013, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Signals of indicator 'Adaptive Moving Average' | -//| Type=SignalAdvanced | -//| Name=Adaptive Moving Average | -//| ShortName=AMA | -//| Class=CSignalAMA | -//| Page=signal_ama | -//| Parameter=PeriodMA,int,10,Period of averaging | -//| Parameter=PeriodFast,int,2,Period of fast EMA | -//| Parameter=PeriodSlow,int,30,Period of slow EMA | -//| Parameter=Shift,int,0,Time shift | -//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CSignalAMA. | -//| Purpose: Class of generator of trade signals based on | -//| the 'Adaptive Moving Average' indicator. | -//| Is derived from the CExpertSignal class. | -//+------------------------------------------------------------------+ -class CSignalAMA : public CExpertSignal - { -protected: - CiAMA m_ma; // object-indicator - //--- adjusted parameters - int m_ma_period; // the "period of averaging" parameter of the indicator - int m_period_fast; // the "period of fast EMA" parameter of the indicator - int m_period_slow; // the "period of slow EMA" parameter of the indicator - int m_ma_shift; // the "time shift" parameter of the indicator - ENUM_APPLIED_PRICE m_ma_applied; // the "object of averaging" parameter" of the indicator - //--- "weights" of market models (0-100) - int m_pattern_0; // model 0 "price is on the necessary side from the indicator" - int m_pattern_1; // model 1 "price crossed the indicator with opposite direction" - int m_pattern_2; // model 2 "price crossed the indicator with the same direction" - int m_pattern_3; // model 3 "piercing" - -public: - CSignalAMA(void); - ~CSignalAMA(void); - //--- methods of setting adjustable parameters - void PeriodMA(int value) { m_ma_period=value; } - void PeriodFast(int value) { m_period_fast=value; } - void PeriodSlow(int value) { m_period_slow=value; } - void Shift(int value) { m_ma_shift=value; } - void Applied(ENUM_APPLIED_PRICE value) { m_ma_applied=value; } - //--- methods of adjusting "weights" of market models - void Pattern_0(int value) { m_pattern_0=value; } - void Pattern_1(int value) { m_pattern_1=value; } - void Pattern_2(int value) { m_pattern_2=value; } - void Pattern_3(int value) { m_pattern_3=value; } - //--- method of verification of settings - virtual bool ValidationSettings(void); - //--- method of creating the indicator and timeseries - virtual bool InitIndicators(CIndicators *indicators); - //--- methods of checking if the market models are formed - virtual int LongCondition(void); - virtual int ShortCondition(void); - -protected: - //--- method of initialization of the indicator - bool InitMA(CIndicators *indicators); - //--- methods of getting data - double MA(int ind) { return(m_ma.Main(ind)); } - double DiffMA(int ind) { return(MA(ind)-MA(ind+1)); } - double DiffOpenMA(int ind) { return(Open(ind)-MA(ind)); } - double DiffHighMA(int ind) { return(High(ind)-MA(ind)); } - double DiffLowMA(int ind) { return(Low(ind)-MA(ind)); } - double DiffCloseMA(int ind) { return(Close(ind)-MA(ind)); } - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CSignalAMA::CSignalAMA(void) : m_ma_period(10), - m_ma_shift(0), - m_period_fast(2), - m_period_slow(30), - m_ma_applied(PRICE_CLOSE), - m_pattern_0(10), - m_pattern_1(70), - m_pattern_2(100), - m_pattern_3(60) - { -//--- initialization of protected data - m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSignalAMA::~CSignalAMA(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CSignalAMA::ValidationSettings(void) - { -//--- call of the method of the parent class - if(!CExpertSignal::ValidationSettings()) - return(false); -//--- initial data checks - if(m_ma_period<=0) - { - printf(__FUNCTION__+": period MA must be greater than 0"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create indicators. | -//+------------------------------------------------------------------+ -bool CSignalAMA::InitIndicators(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- initialization of indicators and timeseries of additional filters - if(!CExpertSignal::InitIndicators(indicators)) - return(false); -//--- create and initialize AMA indicator - if(!InitMA(indicators)) - return(false); -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create MA indicators. | -//+------------------------------------------------------------------+ -bool CSignalAMA::InitMA(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- add object to collection - if(!indicators.Add(GetPointer(m_ma))) - { - printf(__FUNCTION__+": error adding object"); - return(false); - } -//--- initialize object - if(!m_ma.Create(m_symbol.Name(),m_period,m_ma_period,m_period_fast,m_period_slow,m_ma_shift,m_ma_applied)) - { - printf(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will grow. | -//+------------------------------------------------------------------+ -int CSignalAMA::LongCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- analyze positional relationship of the close price and the indicator at the first analyzed bar - if(DiffCloseMA(idx)<0.0) - { - //--- the close price is below the indicator - if(IS_PATTERN_USAGE(1) && DiffOpenMA(idx)>0.0 && DiffMA(idx)>0.0) - { - //--- the open price is above the indicator (i.e. there was an intersection), but the indicator is directed upwards - result=m_pattern_1; - //--- consider that this is an unformed "piercing" and suggest to enter the market at the current price - m_base_price=0.0; - } - } - else - { - //--- the close price is above the indicator (the indicator has no objections to buying) - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; - //--- if the indicator is directed upwards - if(DiffMA(idx)>0.0) - { - if(DiffOpenMA(idx)<0.0) - { - //--- if the model 2 is used - if(IS_PATTERN_USAGE(2)) - { - //--- the open price is below the indicator (i.e. there was an intersection) - result=m_pattern_2; - //--- suggest to enter the market at the "roll back" - m_base_price=m_symbol.NormalizePrice(MA(idx)); - } - } - else - { - //--- if the model 3 is used and the open price is above the indicator - if(IS_PATTERN_USAGE(3) && DiffLowMA(idx)<0.0) - { - //--- the low price is below the indicator - result=m_pattern_3; - //--- consider that this is a formed "piercing" and suggest to enter the market at the current price - m_base_price=0.0; - } - } - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will fall. | -//+------------------------------------------------------------------+ -int CSignalAMA::ShortCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- analyze positional relationship of the close price and the indicator at the first analyzed bar - if(DiffCloseMA(idx)>0.0) - { - //--- the close price is above the indicator - if(IS_PATTERN_USAGE(1) && DiffOpenMA(idx)<0.0 && DiffMA(idx)<0.0) - { - //--- the open price is below the indicator (i.e. there was an intersection), but the indicator is directed downwards - result=m_pattern_1; - //--- consider that this is an unformed "piercing" and suggest to enter the market at the current price - m_base_price=0.0; - } - } - else - { - //--- the close price is below the indicator (the indicator has no objections to buying) - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; - //--- the indicator is directed downwards - if(DiffMA(idx)<0.0) - { - if(DiffOpenMA(idx)>0.0) - { - //--- if the model 2 is used - if(IS_PATTERN_USAGE(2)) - { - //--- the open price is above the indicator (i.e. there was an intersection) - result=m_pattern_2; - //--- suggest to enter the market at the "roll back" - m_base_price=m_symbol.NormalizePrice(MA(idx)); - } - } - else - { - //--- if the model 3 is used and the open price is below the indicator - if(IS_PATTERN_USAGE(3) && DiffHighMA(idx)>0.0) - { - //--- the high price is above the indicator - result=m_pattern_3; - //--- consider that this is a formed "piercing" and suggest to enter the market at the current price - m_base_price=0.0; - } - } - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Signal/SignalAO.mqh b/Include/Expert/Signal/SignalAO.mqh deleted file mode 100644 index bfe0535..0000000 --- a/Include/Expert/Signal/SignalAO.mqh +++ /dev/null @@ -1,339 +0,0 @@ -//+------------------------------------------------------------------+ -//| SignalAO.mqh | -//| Copyright 2009-2013, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Signals of indicator 'Awesome Oscillator' | -//| Type=SignalAdvanced | -//| Name=Awesome Oscillator | -//| ShortName=AO | -//| Class=CSignalAO | -//| Page=signal_ao | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CSignalAO. | -//| Purpose: Class of generator of trade signals based on | -//| the 'Awesome Oscillator' indicator. | -//| Is derived from the CExpertSignal class. | -//+------------------------------------------------------------------+ -class CSignalAO : public CExpertSignal - { -protected: - CiAO m_ao; // object-indicator - //--- "weights" of market models (0-100) - int m_pattern_0; // model 0 "first analyzed bar has required color" - int m_pattern_1; // model 1 "the 'saucer' signal" - int m_pattern_2; // model 2 "the 'crossing of the zero line' signal" - int m_pattern_3; // model 2 "the 'divergence' signal" - //--- variables - double m_extr_osc[10]; // array of values of extremums of the oscillator - double m_extr_pr[10]; // array of values of the corresponding extremums of price - int m_extr_pos[10]; // array of shifts of extremums (in bars) - uint m_extr_map; // resulting bit-map of ratio of extremums of the oscillator and the price - -public: - CSignalAO(void); - ~CSignalAO(void); - //--- methods of adjusting "weights" of market models - void Pattern_0(int value) { m_pattern_0=value; } - void Pattern_1(int value) { m_pattern_1=value; } - void Pattern_2(int value) { m_pattern_2=value; } - void Pattern_3(int value) { m_pattern_3=value; } - //--- method of creating the indicator and timeseries - virtual bool InitIndicators(CIndicators *indicators); - //--- methods of checking if the market models are formed - virtual int LongCondition(void); - virtual int ShortCondition(void); - -protected: - //--- method of initialization of the indicator - bool InitAO(CIndicators *indicators); - //--- methods of getting data - double AO(int ind) { return(m_ao.Main(ind)); } - double DiffAO(int ind) { return(AO(ind)-AO(ind+1)); } - int StateAO(int ind); - bool ExtStateAO(int ind); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CSignalAO::CSignalAO(void) : m_pattern_0(30), - m_pattern_1(20), - m_pattern_2(70), - m_pattern_3(90) - { -//--- initialization of protected data - m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSignalAO::~CSignalAO(void) - { - } -//+------------------------------------------------------------------+ -//| Create indicators. | -//+------------------------------------------------------------------+ -bool CSignalAO::InitIndicators(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- initialization of indicators and timeseries of additional filters - if(!CExpertSignal::InitIndicators(indicators)) - return(false); -//--- create and initialize AO indicator - if(!InitAO(indicators)) - return(false); -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialize AO indicators. | -//+------------------------------------------------------------------+ -bool CSignalAO::InitAO(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- add object to collection - if(!indicators.Add(GetPointer(m_ao))) - { - printf(__FUNCTION__+": error adding object"); - return(false); - } -//--- initialize object - if(!m_ao.Create(m_symbol.Name(),m_period)) - { - printf(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Check of the indicator state. | -//+------------------------------------------------------------------+ -int CSignalAO::StateAO(int ind) - { - int res=0; - double var; -//--- - for(int i=ind;;i++) - { - if(AO(i+1)==EMPTY_VALUE) - break; - var=DiffAO(i); - if(res>0) - { - if(var<0) - break; - res++; - continue; - } - if(res<0) - { - if(var>0) - break; - res--; - continue; - } - if(var>0) - res++; - if(var<0) - res--; - } -//--- - return(res); - } -//+------------------------------------------------------------------+ -//| Extended check of the oscillator state consists | -//| in forming a bit-map according to certain rules, | -//| which shows ratios of extremums of the oscillator and price. | -//+------------------------------------------------------------------+ -bool CSignalAO::ExtStateAO(int ind) - { -//--- operation of this method results in a bit-map of extremums -//--- practically, the bit-map of extremums is an "array" of 4-bit fields -//--- each "element of the array" definitely describes the ratio -//--- of current extremums of the oscillator and the price with previous ones -//--- purpose of bits of an element of the analyzed bit-map -//--- bit 3 - not used (always 0) -//--- bit 2 - is equal to 1 if the current extremum of the oscillator is "more extreme" than the previous one -//--- (a higher peak or a deeper valley), otherwise - 0 -//--- bit 1 - not used (always 0) -//--- bit 0 - is equal to 1 if the current extremum of price is "more extreme" than the previous one -//--- (a higher peak or a deeper valley), otherwise - 0 -//--- in addition to them, the following is formed: -//--- array of values of extremums of the oscillator, -//--- array of values of price extremums and -//--- array of "distances" between extremums of the oscillator (in bars) -//--- it should be noted that when using the results of the extended check of state, -//--- you should consider, which extremum of the oscillator (peak or valley) -//--- is the "reference point" (i.e. was detected first during the analysis) -//--- if a peak is detected first then even elements of all arrays -//--- will contain information about peaks, and odd elements will contain information about valleys -//--- if a valley is detected first, then respectively in reverse - int pos=ind,off,index; - uint map; // intermediate bit-map for one extremum -//--- - m_extr_map=0; - for(int i=0;i<10;i++) - { - off=StateAO(pos); - if(off>0) - { - //--- minimum of the oscillator is detected - pos+=off; - m_extr_pos[i]=pos; - m_extr_osc[i]=AO(pos); - if(i>1) - { - m_extr_pr[i]=m_low.MinValue(pos-2,5,index); - //--- form the intermediate bit-map - map=0; - if(m_extr_pr[i-2]1) - { - m_extr_pr[i]=m_high.MaxValue(pos-2,5,index); - //--- form the intermediate bit-map - map=0; - if(m_extr_pr[i-2]>m_extr_pr[i]) - map+=1; // set bit 0 - if(m_extr_osc[i-2]>m_extr_osc[i]) - map+=4; // set bit 2 - //--- add the result - m_extr_map+=map<<(4*(i-2)); - } - else - m_extr_pr[i]=m_high.MaxValue(pos-1,4,index); - } - } -//--- - return(true); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will grow. | -//+------------------------------------------------------------------+ -int CSignalAO::LongCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- if the first analyzed bar is "red", don't "vote" for buying - if(DiffAO(idx)<0.0) - return(result); -//--- first analyzed bar is "green" (the indicator has no objections to buying) - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; - if(AO(idx++)>0.0) - { - //--- first analyzed bar is greater than zero, search for the "saucer" and "crosing of the zero line" signals - if(IS_PATTERN_USAGE(1) && DiffAO(idx)<0.0) - { - //--- the "saucer" signal - //--- there is a condition for buying - return(m_pattern_1); - } - if(IS_PATTERN_USAGE(2) && AO(idx)<0.0) - { - //--- the "crossing of the zero line" signal - //--- there is a condition for buying - return(m_pattern_2); - } - } - else - { - //--- first analyzed bar is less than zero, search for the "divergence" signal - //--- if the second analyzed bar is "red", the condition for buying may be fulfilled - if(IS_PATTERN_USAGE(3) && DiffAO(idx)<0.0) - { - idx=StartIndex(); - //--- search for the "divergence" signal - ExtStateAO(idx); - if((m_extr_map&0xF)==1) - { - if(m_extr_osc[0]<0.0 && m_extr_osc[1]<0.0 && m_extr_osc[2]<0.0) - { - //--- both valleys are below zero, the peak is between them and it hasn't raised above zero - //--- we suppose that this is "divergence" - return(m_pattern_3); - } - } - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will fall. | -//+------------------------------------------------------------------+ -int CSignalAO::ShortCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- if the first analyzed bar is "green", don't "vote" for selling - if(DiffAO(idx)>0.0) - return(result); -//--- first analyzed bar is "red" (the indicator has no objections to selling) - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; - if(AO(idx++)<0.0) - { - //--- first analyzed bar is below zero, search for the "saucer" and "crossing of the zero line" signals - if(IS_PATTERN_USAGE(1) && DiffAO(idx)>0.0) - { - //--- the "saucer" signal - //--- there is a condition for buying - return(m_pattern_1); - } - if(IS_PATTERN_USAGE(2) && AO(idx)>0.0) - { - //--- the "crossing of the zero line" signal - //--- there is a condition for buying - return(m_pattern_2); - } - } - else - { - //--- first analyzed bar is above zero, search for the "divergence" signal - //--- if the second analyzed bar is "green", the condition for buying may be fulfilled - if(IS_PATTERN_USAGE(3) && DiffAO(idx)>0.0) - { - idx=StartIndex(); - //--- search for the "divergence" signal - ExtStateAO(idx); - if((m_extr_map&0xF)==1) - { - if(m_extr_osc[0]>0.0 && m_extr_osc[1]>0.0 && m_extr_osc[2]>0.0) - { - //--- both peaks are above zero and the valley between them hasn't fallen below zero - //--- we suppose that this is "divergence" - return(m_pattern_3); - } - } - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Signal/SignalBearsPower.mqh b/Include/Expert/Signal/SignalBearsPower.mqh deleted file mode 100644 index df1b25d..0000000 --- a/Include/Expert/Signal/SignalBearsPower.mqh +++ /dev/null @@ -1,289 +0,0 @@ -//+------------------------------------------------------------------+ -//| SignalBearsPower.mqh | -//| Copyright 2009-2013, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Signals of oscillator 'Bears Power' | -//| Type=SignalAdvanced | -//| Name=Bears Power | -//| ShortName=BearsPower | -//| Class=CSignalBearsPower | -//| Page=signal_bears | -//| Parameter=PeriodBears,int,13,Period of calculation | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CSignalBearsPower. | -//| Purpose: Class of generator of trade signals based on | -//| the 'Bears Power' oscillator. | -//| Is derived from the CExpertSignal class. | -//+------------------------------------------------------------------+ -class CSignalBearsPower : public CExpertSignal - { -protected: - CiBearsPower m_bears; // object-oscillator - //--- adjusted parameters - int m_period_bears; // the "period of calculation" parameter of the oscillator - //--- "weights" of market models (0-100) - int m_pattern_0; // model 0 "reverse of the oscillator to required direction" - int m_pattern_1; // model 1 "divergence of the oscillator and price" - //--- variables - double m_extr_osc[10]; // array of values of extremums of the oscillator - double m_extr_pr[10]; // array of values of the corresponding extremums of price - int m_extr_pos[10]; // array of shifts of extremums (in bars) - uint m_extr_map; // resulting bit-map of ratio of extremums of the oscillator and the price - -public: - CSignalBearsPower(void); - ~CSignalBearsPower(void); - //--- methods of setting adjustable parameters - void PeriodBears(int value) { m_period_bears=value; } - //--- methods of adjusting "weights" of market models - void Pattern_0(int value) { m_pattern_0=value; } - void Pattern_1(int value) { m_pattern_1=value; } - //--- method of verification of settings - virtual bool ValidationSettings(void); - //--- method of creating the indicator and timeseries - virtual bool InitIndicators(CIndicators *indicators); - //--- methods of checking if the market models are formed - virtual int LongCondition(void); - //--- the oscillator doesn't identify conditions for selling - -protected: - //--- method of initialization of the oscillator - bool InitBears(CIndicators *indicators); - //--- methods of getting data - double Bears(int ind) { return(m_bears.Main(ind)); } - double DiffBears(int ind) { return(Bears(ind)-Bears(ind+1)); } - int StateBears(int ind); - bool ExtStateBears(int ind); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CSignalBearsPower::CSignalBearsPower(void) : m_period_bears(13), - m_pattern_0(20), - m_pattern_1(80) - { -//--- initialization of protected data - m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSignalBearsPower::~CSignalBearsPower(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CSignalBearsPower::ValidationSettings(void) - { -//--- validation settings of additional filters - if(!CExpertSignal::ValidationSettings()) - return(false); -//--- initial data checks - if(m_period_bears<=0) - { - printf(__FUNCTION__+": period Bears must be greater than 0"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create indicators. | -//+------------------------------------------------------------------+ -bool CSignalBearsPower::InitIndicators(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- initialization of indicators and timeseries of additional filters - if(!CExpertSignal::InitIndicators(indicators)) - return(false); -//--- create and initialize BearsPower oscillator - if(!InitBears(indicators)) - return(false); -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialize BearsPower oscillators. | -//+------------------------------------------------------------------+ -bool CSignalBearsPower::InitBears(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- add object to collection - if(!indicators.Add(GetPointer(m_bears))) - { - printf(__FUNCTION__+": error adding object"); - return(false); - } -//--- initialize object - if(!m_bears.Create(m_symbol.Name(),m_period,m_period_bears)) - { - printf(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Check of the oscillator state. | -//+------------------------------------------------------------------+ -int CSignalBearsPower::StateBears(int ind) - { - int res=0; - double var; -//--- - for(int i=ind;;i++) - { - if(Bears(i+1)==EMPTY_VALUE) - break; - var=DiffBears(i); - if(res>0) - { - if(var<0) - break; - res++; - continue; - } - if(res<0) - { - if(var>0) - break; - res--; - continue; - } - if(var>0) - res++; - if(var<0) - res--; - } -//--- return the result - return(res); - } -//+------------------------------------------------------------------+ -//| Extended check of the oscillator state consists | -//| in forming a bit-map according to certain rules, | -//| which shows ratios of extremums of the oscillator and price. | -//+------------------------------------------------------------------+ -bool CSignalBearsPower::ExtStateBears(int ind) - { -//--- operation of this method results in a bit-map of extremums -//--- practically, the bit-map of extremums is an "array" of 4-bit fields -//--- each "element of the array" definitely describes the ratio -//--- of current extremums of the oscillator and the price with previous ones -//--- purpose of bits of an element of the analyzed bit-map -//--- bit 3 - not used (always 0) -//--- bit 2 - is equal to 1 if the current extremum of the oscillator is "more extreme" than the previous one -//--- (a higher peak or a deeper valley), otherwise - 0 -//--- bit 1 - not used (always 0) -//--- bit 0 - is equal to 1 if the current extremum of price is "more extreme" than the previous one -//--- (a higher peak or a deeper valley), otherwise - 0 -//--- in addition to them, the following is formed: -//--- array of values of extremums of the oscillator, -//--- array of values of price extremums and -//--- array of "distances" between extremums of the oscillator (in bars) -//--- it should be noted that when using the results of the extended check of state, -//--- you should consider, which extremum of the oscillator (peak or valley) -//--- is the "reference point" (i.e. was detected first during the analysis) -//--- if a peak is detected first then even elements of all arrays -//--- will contain information about peaks, and odd elements will contain information about valleys -//--- if a valley is detected first, then respectively in reverse - int pos=ind,off,index; - uint map; // intermediate bit-map for one extremum -//--- - m_extr_map=0; - for(int i=0;i<10;i++) - { - off=StateBears(pos); - if(off>0) - { - //--- minimum of the oscillator is detected - pos+=off; - m_extr_pos[i]=pos; - m_extr_osc[i]=Bears(pos); - if(i>1) - { - m_extr_pr[i]=m_low.MinValue(pos-2,5,index); - //--- form the intermediate bit-map - map=0; - if(m_extr_pr[i-2]1) - { - m_extr_pr[i]=m_high.MaxValue(pos-2,5,index); - //--- form the intermediate bit-map - map=0; - if(m_extr_pr[i-2]>m_extr_pr[i]) - map+=1; // set bit 0 - if(m_extr_osc[i-2]>m_extr_osc[i]) - map+=4; // set bit 2 - //--- add the result - m_extr_map+=map<<(4*(i-2)); - } - else - m_extr_pr[i]=m_high.MaxValue(pos-1,4,index); - } - } -//--- - return(true); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will grow. | -//+------------------------------------------------------------------+ -int CSignalBearsPower::LongCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- if the oscillator is above zero, don't "vote" for buying - if(Bears(idx)>0.0) - return(result); -//--- the oscillator is below zero - if(StateBears(idx)>0) - { - //--- the oscillator has turned upwards at a previous bar - //--- there is a condition for buying - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; - //--- if the model 1 is used, search for the "divergence" signal - if(IS_PATTERN_USAGE(1)) - { - ExtStateBears(idx); - if((m_extr_map&0xF)==1) - { - if(m_extr_osc[0]<0.0 && m_extr_osc[2]<0.0) - { - //--- both valleys are below zero - //--- we suppose that this is "divergence" - result=m_pattern_1; - } - } - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Signal/SignalBullsPower.mqh b/Include/Expert/Signal/SignalBullsPower.mqh deleted file mode 100644 index 10c8ef7..0000000 --- a/Include/Expert/Signal/SignalBullsPower.mqh +++ /dev/null @@ -1,289 +0,0 @@ -//+------------------------------------------------------------------+ -//| SignalBullsPower.mqh | -//| Copyright 2009-2013, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Signals of oscillator 'Bulls Power' | -//| Type=SignalAdvanced | -//| Name=Bulls Power | -//| ShortName=BullsPower | -//| Class=CSignalBullsPower | -//| Page=signal_bulls | -//| Parameter=PeriodBulls,int,13,Period of calculation | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CSignalBullsPower. | -//| Purpose: Class of generator of trade signals based on | -//| the 'Bulls Power' oscillator. | -//| Is derived from the CExpertSignal class. | -//+------------------------------------------------------------------+ -class CSignalBullsPower : public CExpertSignal - { -protected: - CiBullsPower m_bulls; // object-oscillator - //--- adjusted parameters - int m_period_bulls; // the "period of calculation" parameter of the oscillator - //--- "weights" of market models (0-100) - int m_pattern_0; // model 0 "reverse of the oscillator to required direction" - int m_pattern_1; // model 1 "divergence of the oscillator and price" - //--- variables - double m_extr_osc[10]; // array of values of extremums of the oscillator - double m_extr_pr[10]; // array of values of the corresponding extremums of price - int m_extr_pos[10]; // array of shifts of extremums (in bars) - uint m_extr_map; // resulting bit-map of ratio of extremums of the oscillator and the price - -public: - CSignalBullsPower(void); - ~CSignalBullsPower(void); - //--- methods of setting adjustable parameters - void PeriodBulls(int value) { m_period_bulls=value; } - //--- methods of adjusting "weights" of market models - void Pattern_0(int value) { m_pattern_0=value; } - void Pattern_1(int value) { m_pattern_1=value; } - //--- method of verification of settings - virtual bool ValidationSettings(void); - //--- method of creating the indicator and timeseries - virtual bool InitIndicators(CIndicators *indicators); - //--- methods of checking if the market models are formed - virtual int ShortCondition(void); - //--- the oscillator doesn't identify conditions for buying - -protected: - //--- method of initialization of the oscillator - bool InitBears(CIndicators *indicators); - //--- methods of getting data - double Bulls(int ind) { return(m_bulls.Main(ind)); } - double DiffBulls(int ind) { return(Bulls(ind)-Bulls(ind+1)); } - int StateBulls(int ind); - bool ExtStateBulls(int ind); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CSignalBullsPower::CSignalBullsPower(void) : m_period_bulls(13), - m_pattern_0(20), - m_pattern_1(80) - { -//--- initialization of protected data - m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSignalBullsPower::~CSignalBullsPower(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CSignalBullsPower::ValidationSettings(void) - { -//--- validation settings of additional filters - if(!CExpertSignal::ValidationSettings()) - return(false); -//--- initial data checks - if(m_period_bulls<=0) - { - printf(__FUNCTION__+": period Bulls must be greater than 0"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create indicators. | -//+------------------------------------------------------------------+ -bool CSignalBullsPower::InitIndicators(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- initialization of indicators and timeseries of additional filters - if(!CExpertSignal::InitIndicators(indicators)) - return(false); -//--- create and initialize BullsPower oscillator - if(!InitBears(indicators)) - return(false); -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialize BearsPower oscillators. | -//+------------------------------------------------------------------+ -bool CSignalBullsPower::InitBears(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- add object to collection - if(!indicators.Add(GetPointer(m_bulls))) - { - printf(__FUNCTION__+": error adding object"); - return(false); - } -//--- initialize object - if(!m_bulls.Create(m_symbol.Name(),m_period,m_period_bulls)) - { - printf(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Check of the oscillator state. | -//+------------------------------------------------------------------+ -int CSignalBullsPower::StateBulls(int ind) - { - int res=0; - double var; -//--- - for(int i=ind;;i++) - { - if(Bulls(i+1)==EMPTY_VALUE) - break; - var=DiffBulls(i); - if(res>0) - { - if(var<0) - break; - res++; - continue; - } - if(res<0) - { - if(var>0) - break; - res--; - continue; - } - if(var>0) - res++; - if(var<0) - res--; - } -//--- return the result - return(res); - } -//+------------------------------------------------------------------+ -//| Extended check of the oscillator state consists | -//| in forming a bit-map according to certain rules, | -//| which shows ratios of extremums of the oscillator and price. | -//+------------------------------------------------------------------+ -bool CSignalBullsPower::ExtStateBulls(int ind) - { -//--- operation of this method results in a bit-map of extremums -//--- practically, the bit-map of extremums is an "array" of 4-bit fields -//--- each "element of the array" definitely describes the ratio -//--- of current extremums of the oscillator and the price with previous ones -//--- purpose of bits of an element of the analyzed bit-map -//--- bit 3 - not used (always 0) -//--- bit 2 - is equal to 1 if the current extremum of the oscillator is "more extreme" than the previous one -//--- (a higher peak or a deeper valley), otherwise - 0 -//--- bit 1 - not used (always 0) -//--- bit 0 - is equal to 1 if the current extremum of price is "more extreme" than the previous one -//--- (a higher peak or a deeper valley), otherwise - 0 -//--- in addition to them, the following is formed: -//--- array of values of extremums of the oscillator, -//--- array of values of price extremums and -//--- array of "distances" between extremums of the oscillator (in bars) -//--- it should be noted that when using the results of the extended check of state, -//--- you should consider, which extremum of the oscillator (peak or valley) -//--- is the "reference point" (i.e. was detected first during the analysis) -//--- if a peak is detected first then even elements of all arrays -//--- will contain information about peaks, and odd elements will contain information about valleys -//--- if a valley is detected first, then respectively in reverse - int pos=ind,off,index; - uint map; // intermediate bit-map for one extremum -//--- - m_extr_map=0; - for(int i=0;i<10;i++) - { - off=StateBulls(pos); - if(off>0) - { - //--- minimum of the oscillator is detected - pos+=off; - m_extr_pos[i]=pos; - m_extr_osc[i]=Bulls(pos); - if(i>1) - { - m_extr_pr[i]=m_low.MinValue(pos-2,5,index); - //--- form the intermediate bit-map - map=0; - if(m_extr_pr[i-2]1) - { - m_extr_pr[i]=m_high.MaxValue(pos-2,5,index); - //--- form the intermediate bit-map - map=0; - if(m_extr_pr[i-2]>m_extr_pr[i]) - map+=1; // set bit 0 - if(m_extr_osc[i-2]>m_extr_osc[i]) - map+=4; // set bit 2 - //--- add the result - m_extr_map+=map<<(4*(i-2)); - } - else - m_extr_pr[i]=m_high.MaxValue(pos-1,4,index); - } - } -//--- - return(true); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will fall. | -//+------------------------------------------------------------------+ -int CSignalBullsPower::ShortCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- if the oscillator is below zero, don't "vote" for selling - if(Bulls(idx)<0.0) - return(result); -//--- the oscillator is above zero - if(StateBulls(idx)<0) - { - //--- the oscillator has turned downwards at a previous bar - //--- there us a condition for selling - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; - //--- if the model 1 is used, search for the "divergence" signal - if(IS_PATTERN_USAGE(1)) - { - ExtStateBulls(idx); - if((m_extr_map&0xF)==1) - { - if(m_extr_osc[0]>0.0 && m_extr_osc[2]>0.0) - { - //--- both peaks are above zero - //--- we suppose that this is "divergence" - result=m_pattern_1; - } - } - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Signal/SignalCCI.mqh b/Include/Expert/Signal/SignalCCI.mqh deleted file mode 100644 index ed2caee..0000000 --- a/Include/Expert/Signal/SignalCCI.mqh +++ /dev/null @@ -1,382 +0,0 @@ -//+------------------------------------------------------------------+ -//| SignalCCI.mqh | -//| Copyright 2009-2013, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Signals of oscilator 'Commodity Channel Index' | -//| Type=SignalAdvanced | -//| Name=Commodity Channel Index | -//| ShortName=CCI | -//| Class=CSignalCCI | -//| Page=signal_cci | -//| Parameter=PeriodCCI,int,8,Period of calculation | -//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CSignalCCI. | -//| Purpose: Class of generator of trade signals based on | -//| the 'Commodity Channel Index' oscillator. | -//| Is derived from the CExpertSignal class. | -//+------------------------------------------------------------------+ -class CSignalCCI : public CExpertSignal - { -protected: - CiCCI m_cci; // object-oscillator - //--- adjusted parameters - int m_periodCCI; // the "period of calculation" parameter of the oscillator - ENUM_APPLIED_PRICE m_applied; // the "prices series" parameter of the oscillator - //--- "weights" of market models (0-100) - int m_pattern_0; // model 0 "the oscillator has required direction" - int m_pattern_1; // model 1 "reverse behind the level of overbuying/overselling" - int m_pattern_2; // model 2 "divergence of the oscillator and price" - int m_pattern_3; // model 3 "double divergence of the oscillator and price" - //--- variables - double m_extr_osc[10]; // array of values of extremums of the oscillator - double m_extr_pr[10]; // array of values of the corresponding extremums of price - int m_extr_pos[10]; // array of shifts of extremums (in bars) - uint m_extr_map; // resulting bit-map of ratio of extremums of the oscillator and the price - -public: - CSignalCCI(void); - ~CSignalCCI(void); - //--- methods of setting adjustable parameters - void PeriodCCI(int value) { m_periodCCI=value; } - void Applied(ENUM_APPLIED_PRICE value) { m_applied=value; } - //--- methods of adjusting "weights" of market models - void Pattern_0(int value) { m_pattern_0=value; } - void Pattern_1(int value) { m_pattern_1=value; } - void Pattern_2(int value) { m_pattern_2=value; } - void Pattern_3(int value) { m_pattern_3=value; } - //--- method of verification of settings - virtual bool ValidationSettings(void); - //--- method of creating the indicator and timeseries - virtual bool InitIndicators(CIndicators *indicators); - //--- methods of checking if the market models are formed - virtual int LongCondition(void); - virtual int ShortCondition(void); - -protected: - //--- method of initialization of the oscillator - bool InitStoch(CIndicators *indicators); - //--- methods of getting data - double CCI(int ind) { return(m_cci.Main(ind)); } - double Diff(int ind) { return(CCI(ind)-CCI(ind+1)); } - int State(int ind); - bool ExtState(int ind); - bool CompareMaps(int map,int count,bool minimax=false,int start=0); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CSignalCCI::CSignalCCI(void) : m_periodCCI(14), - m_applied(PRICE_CLOSE), - m_pattern_0(90), - m_pattern_1(60), - m_pattern_2(100), - m_pattern_3(50) - { -//--- initialization of protected data - m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSignalCCI::~CSignalCCI(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CSignalCCI::ValidationSettings(void) - { -//--- validation settings of additional filters - if(!CExpertSignal::ValidationSettings()) - return(false); -//--- initial data checks - if(m_periodCCI<=0) - { - printf(__FUNCTION__+": period of the CCI oscillator must be greater than 0"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create indicators. | -//+------------------------------------------------------------------+ -bool CSignalCCI::InitIndicators(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- initialization of indicators and timeseries of additional filters - if(!CExpertSignal::InitIndicators(indicators)) - return(false); -//--- create and initialize CCI oscillator - if(!InitStoch(indicators)) - return(false); -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialize CCI oscillators. | -//+------------------------------------------------------------------+ -bool CSignalCCI::InitStoch(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- add object to collection - if(!indicators.Add(GetPointer(m_cci))) - { - printf(__FUNCTION__+": error adding object"); - return(false); - } -//--- initialize object - if(!m_cci.Create(m_symbol.Name(),m_period,m_periodCCI,m_applied)) - { - printf(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Check of the oscillator state. | -//+------------------------------------------------------------------+ -int CSignalCCI::State(int ind) - { - int res=0; - double var; -//--- - for(int i=ind;;i++) - { - if(CCI(i+1)==EMPTY_VALUE) - break; - var=Diff(i); - if(res>0) - { - if(var<0) - break; - res++; - continue; - } - if(res<0) - { - if(var>0) - break; - res--; - continue; - } - if(var>0) - res++; - if(var<0) - res--; - } -//--- return the result - return(res); - } -//+------------------------------------------------------------------+ -//| Extended check of the oscillator state consists | -//| in forming a bit-map according to certain rules, | -//| which shows ratios of extremums of the oscillator and price. | -//+------------------------------------------------------------------+ -bool CSignalCCI::ExtState(int ind) - { -//--- operation of this method results in a bit-map of extremums -//--- practically, the bit-map of extremums is an "array" of 4-bit fields -//--- each "element of the array" definitely describes the ratio -//--- of current extremums of the oscillator and the price with previous ones -//--- purpose of bits of an element of the analyzed bit-map -//--- bit 3 - not used (always 0) -//--- bit 2 - is equal to 1 if the current extremum of the oscillator is "more extreme" than the previous one -//--- (a higher peak or a deeper valley), otherwise - 0 -//--- bit 1 - not used (always 0) -//--- bit 0 - is equal to 1 if the current extremum of price is "more extreme" than the previous one -//--- (a higher peak or a deeper valley), otherwise - 0 -//--- in addition to them, the following is formed: -//--- array of values of extremums of the oscillator, -//--- array of values of price extremums and -//--- array of "distances" between extremums of the oscillator (in bars) -//--- it should be noted that when using the results of the extended check of state, -//--- you should consider, which extremum of the oscillator (peak or valley) -//--- is the "reference point" (i.e. was detected first during the analysis) -//--- if a peak is detected first then even elements of all arrays -//--- will contain information about peaks, and odd elements will contain information about valleys -//--- if a valley is detected first, then respectively in reverse - int pos=ind,off,index; - uint map; // intermediate bit-map for one extremum -//--- - m_extr_map=0; - for(int i=0;i<10;i++) - { - off=State(pos); - if(off>0) - { - //--- minimum of the oscillator is detected - pos+=off; - m_extr_pos[i]=pos; - m_extr_osc[i]=CCI(pos); - if(i>1) - { - m_extr_pr[i]=m_low.MinValue(pos-2,5,index); - //--- form the intermediate bit-map - map=0; - if(m_extr_pr[i-2]1) - { - m_extr_pr[i]=m_high.MaxValue(pos-2,5,index); - //--- form the intermediate bit-map - map=0; - if(m_extr_pr[i-2]>m_extr_pr[i]) - map+=1; // set bit 0 - if(m_extr_osc[i-2]>m_extr_osc[i]) - map+=4; // set bit 2 - //--- add the result - m_extr_map+=map<<(4*(i-2)); - } - else - m_extr_pr[i]=m_high.MaxValue(pos-1,3,index); - } - } -//--- - return(true); - } -//+------------------------------------------------------------------+ -//| Comparing the bit-map of extremums with pattern. | -//+------------------------------------------------------------------+ -bool CSignalCCI::CompareMaps(int map,int count,bool minimax,int start) - { - int step =(minimax)?4:8; - int total=step*(start+count); -//--- check input parameters for a possible going out of range of the bit-map - if(total>32) - return(false); -//--- bit-map of the patter is an "array" of 4-bit fields -//--- each "element of the array" definitely describes the desired ratio -//--- of current extremums of the oscillator and the price with previous ones -//--- purpose of bits of an elements of the pattern of the bit-map pattern -//--- bit 3 - is equal to if the ratio of extremums of the oscillator is insignificant for us -//--- is equal to 0 if we want to "find" the ratio of extremums of the oscillator determined by the value of bit 2 -//--- bit 2 - is equal to 1 if we want to "discover" the situation when the current extremum of the "oscillator" is "more extreme" than the previous one -//--- (current peak is higher or current valley is deeper) -//--- is equal to 0 if we want to "discover" the situation when the current extremum of the oscillator is "less extreme" than the previous one -//--- (current peak is lower or current valley is less deep) -//--- bit 1 - is equal to 1 if the ratio of extremums is insignificant for us -//--- it is equal to 0 if we want to "find" the ratio of price extremums determined by the value of bit 0 -//--- bit 0 - is equal to 1 if we want to "discover" the situation when the current price extremum is "more extreme" than the previous one -//--- (current peak is higher or current valley is deeper) -//--- it is equal to 0 if we want to "discover" the situation when the current price extremum is "less extreme" than the previous one -//--- (current peak is lower or current valley is less deep) - uint inp_map,check_map; - int i,j; -//--- loop by extremums (4 minimums and 4 maximums) -//--- price and the oscillator are checked separately (thus, there are 16 checks) - for(i=step*start,j=0;i>j)&3; - //--- if the higher-order bit=1, then any ratio is suitable for us - if(inp_map<2) - { - //--- "take" two bits of the corresponding extremum of the price (higher-order bit is always 0) - check_map=(m_extr_map>>i)&3; - if(inp_map!=check_map) - return(false); - } - //--- "take" two bits - pattern of the corresponding oscillator extremum - inp_map=(map>>(j+2))&3; - //--- if the higher-order bit=1, then any ratio is suitable for us - if(inp_map>=2) - continue; - //--- "take" two bits of the corresponding oscillator extremum (higher-order bit is always 0) - check_map=(m_extr_map>>(i+2))&3; - if(inp_map!=check_map) - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will grow. | -//+------------------------------------------------------------------+ -int CSignalCCI::LongCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- - if(Diff(idx)>0.0) - { - //--- the oscillator is directed upwards confirming the possibility of price growth - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; // "confirming" signal number 0 - //--- if the model 1 is used, search for a reverse of the oscillator upwards behind the level of overselling - if(IS_PATTERN_USAGE(1) && Diff(idx+1)<0.0 && CCI(idx+1)<-100.0) - result=m_pattern_1; // signal number 1 - //--- if the model 2 or 3 is used, perform the extended analysis of the oscillator state - if(IS_PATTERN_USAGE(2) || IS_PATTERN_USAGE(3)) - { - ExtState(idx); - //--- if the model 2 is used, search for the "divergence" signal - if(IS_PATTERN_USAGE(2) && CompareMaps(1,1)) // 00000001b - result=m_pattern_2; // signal number 2 - //--- if the model 3 is used, search for the "double divergence" signal - if(IS_PATTERN_USAGE(3) && CompareMaps(0x11,2)) // 00010001b - return(m_pattern_3); // signal number 3 - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will fall. | -//+------------------------------------------------------------------+ -int CSignalCCI::ShortCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- - if(Diff(idx)<0.0) - { - //--- the oscillator is directed downwards confirming the possibility of falling of price - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; // "confirming" signal number 0 - //--- if the model 1 is used, search for a reverse of the oscillator downwards behind the level of overbuying - if(IS_PATTERN_USAGE(1) && Diff(idx+1)>0.0 && CCI(idx+1)>100.0) - result=m_pattern_1; // signal number 1 - //--- if the model 2 or 3 is used, perform the extended analysis of the oscillator state - if(IS_PATTERN_USAGE(2) || IS_PATTERN_USAGE(3)) - { - ExtState(idx); - //--- if the model 2 is used, search for the "divergence" signal - if(IS_PATTERN_USAGE(2) && CompareMaps(1,1)) // 00000001b - result=m_pattern_2; // signal number 2 - //--- if the model 3 is used, search for the "double divergence" signal - if(IS_PATTERN_USAGE(3) && CompareMaps(0x11,2)) // 00010001b - return(m_pattern_3); // signal number 3 - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Signal/SignalDEMA.mqh b/Include/Expert/Signal/SignalDEMA.mqh deleted file mode 100644 index 8cb1191..0000000 --- a/Include/Expert/Signal/SignalDEMA.mqh +++ /dev/null @@ -1,257 +0,0 @@ -//+------------------------------------------------------------------+ -//| SignalDEMA.mqh | -//| Copyright 2009-2013, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Signals of indicator 'Double Exponential Moving Average' | -//| Type=SignalAdvanced | -//| Name=Double Exponential Moving Average | -//| ShortName=DEMA | -//| Class=CSignalDEMA | -//| Page=signal_dema | -//| Parameter=PeriodMA,int,12,Period of averaging | -//| Parameter=Shift,int,0,Time shift | -//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CSignalDEMA. | -//| Purpose: Class of generator of trade signals based on | -//| the 'Double Exponential Moving Average' indicator. | -//| Is derived from the CExpertSignal class. | -//+------------------------------------------------------------------+ -class CSignalDEMA : public CExpertSignal - { -protected: - CiDEMA m_ma; // object-indicator - //--- adjusted parameters - int m_ma_period; // the "period of averaging" parameter of the indicator - int m_ma_shift; // the "time shift" parameter of the indicator - ENUM_APPLIED_PRICE m_ma_applied; // the "object of averaging" parameter" of the indicator - //--- "weights" of market models (0-100) - int m_pattern_0; // model 0 "price is on the necessary side from the indicator" - int m_pattern_1; // model 1 "price crossed the indicator with opposite direction" - int m_pattern_2; // model 2 "price crossed the indicator with the same direction" - int m_pattern_3; // model 3 "piercing" - -public: - CSignalDEMA(void); - ~CSignalDEMA(void); - //--- methods of setting adjustable parameters - void PeriodMA(int value) { m_ma_period=value; } - void Shift(int value) { m_ma_shift=value; } - void Applied(ENUM_APPLIED_PRICE value) { m_ma_applied=value; } - //--- methods of adjusting "weights" of market models - void Pattern_0(int value) { m_pattern_0=value; } - void Pattern_1(int value) { m_pattern_1=value; } - void Pattern_2(int value) { m_pattern_2=value; } - void Pattern_3(int value) { m_pattern_3=value; } - //--- method of verification of settings - virtual bool ValidationSettings(void); - //--- method of creating the indicator and timeseries - virtual bool InitIndicators(CIndicators *indicators); - //--- methods of checking if the market models are formed - virtual int LongCondition(void); - virtual int ShortCondition(void); - -protected: - //--- method of initialization of the indicator - bool InitMA(CIndicators *indicators); - //--- methods of getting data - double MA(int ind) { return(m_ma.Main(ind)); } - double DiffMA(int ind) { return(MA(ind)-MA(ind+1)); } - double DiffOpenMA(int ind) { return(Open(ind)-MA(ind)); } - double DiffHighMA(int ind) { return(High(ind)-MA(ind)); } - double DiffLowMA(int ind) { return(Low(ind)-MA(ind)); } - double DiffCloseMA(int ind) { return(Close(ind)-MA(ind)); } - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CSignalDEMA::CSignalDEMA(void) : m_ma_period(12), - m_ma_shift(0), - m_ma_applied(PRICE_CLOSE), - m_pattern_0(20), - m_pattern_1(60), - m_pattern_2(80), - m_pattern_3(60) - { -//--- initialization of protected data - m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSignalDEMA::~CSignalDEMA(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CSignalDEMA::ValidationSettings(void) - { -//--- call of the method of the parent class - if(!CExpertSignal::ValidationSettings()) - return(false); -//--- initial data checks - if(m_ma_period<=0) - { - printf(__FUNCTION__+": period MA must be greater than 0"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create indicators. | -//+------------------------------------------------------------------+ -bool CSignalDEMA::InitIndicators(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- initialization of indicators and timeseries of additional filters - if(!CExpertSignal::InitIndicators(indicators)) - return(false); -//--- create and initialize DEMA indicator - if(!InitMA(indicators)) - return(false); -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create MA indicators. | -//+------------------------------------------------------------------+ -bool CSignalDEMA::InitMA(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- add indicator to collection - if(!indicators.Add(GetPointer(m_ma))) - { - printf(__FUNCTION__+": error adding object"); - return(false); - } -//--- initialize indicator - if(!m_ma.Create(m_symbol.Name(),m_period,m_ma_period,m_ma_shift,m_ma_applied)) - { - printf(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will grow. | -//+------------------------------------------------------------------+ -int CSignalDEMA::LongCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- analyze positional relationship of the close price and the indicator at the first analyzed bar - if(DiffCloseMA(idx)<0.0) - { - //--- the close price is below the indicator - if(IS_PATTERN_USAGE(1) && DiffOpenMA(idx)>0.0 && DiffMA(idx)>0.0) - { - //--- the open price is above the indicator (i.e. there was an intersection), but the indicator is directed upwards - result=m_pattern_1; - //--- consider that this is an unformed "piercing" and suggest to enter the market at the current price - m_base_price=0.0; - } - } - else - { - //--- the close price is above the indicator (the indicator has no objections to buying) - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; - //--- if the indicator is directed upwards - if(DiffMA(idx)>0.0) - { - if(DiffOpenMA(idx)<0.0) - { - //--- if the model 2 is used - if(IS_PATTERN_USAGE(2)) - { - //--- the open price is below the indicator (i.e. there was an intersection) - result=m_pattern_2; - //--- suggest to enter the market at the "roll back" - m_base_price=m_symbol.NormalizePrice(MA(idx)); - } - } - else - { - //--- if the model 3 is used and the open price is above the indicator - if(IS_PATTERN_USAGE(3) && DiffLowMA(idx)<0.0) - { - //--- the low price is below the indicator - result=m_pattern_3; - //--- consider that this is a formed "piercing" and suggest to enter the market at the current price - m_base_price=0.0; - } - } - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will fall. | -//+------------------------------------------------------------------+ -int CSignalDEMA::ShortCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- analyze positional relationship of the close price and the indicator at the first analyzed bar - if(DiffCloseMA(idx)>0.0) - { - //--- the close price is above the indicator - if(IS_PATTERN_USAGE(1) && DiffOpenMA(idx)<0.0 && DiffMA(idx)<0.0) - { - //--- the open price is below the indicator (i.e. there was an intersection), but the indicator is directed downwards - result=m_pattern_1; - //--- consider that this is an unformed "piercing" and suggest to enter the market at the current price - m_base_price=0.0; - } - } - else - { - //--- the close price is below the indicator (the indicator has no objections to buying) - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; - //--- the indicator is directed downwards - if(DiffMA(idx)<0.0) - { - if(DiffOpenMA(idx)>0.0) - { - //--- if the model 2 is used - if(IS_PATTERN_USAGE(2)) - { - //--- the open price is above the indicator (i.e. there was an intersection) - result=m_pattern_2; - //--- suggest to enter the market at the "roll back" - m_base_price=m_symbol.NormalizePrice(MA(idx)); - } - } - else - { - //--- if the model 3 is used and the open price is below the indicator - if(IS_PATTERN_USAGE(3) && DiffHighMA(idx)>0.0) - { - //--- the high price is above the indicator - result=m_pattern_3; - //--- consider that this is a formed "piercing" and suggest to enter the market at the current price - m_base_price=0.0; - } - } - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Signal/SignalDeMarker.mqh b/Include/Expert/Signal/SignalDeMarker.mqh deleted file mode 100644 index 23af291..0000000 --- a/Include/Expert/Signal/SignalDeMarker.mqh +++ /dev/null @@ -1,378 +0,0 @@ -//+------------------------------------------------------------------+ -//| SignalDeMarker.mqh | -//| Copyright 2009-2013, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Signals of oscillator 'DeMarker' | -//| Type=SignalAdvanced | -//| Name=DeMarker | -//| ShortName=DeM | -//| Class=CSignalDeM | -//| Page=signal_demarker | -//| Parameter=PeriodDeM,int,8,Period of calculation | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CSignalDeM. | -//| Purpose: Class of generator of trade signals based on | -//| the 'Commodity Channel Index' oscillator. | -//| Is derived from the CExpertSignal class. | -//+------------------------------------------------------------------+ -class CSignalDeM : public CExpertSignal - { -protected: - CiDeMarker m_dem; // object-oscillator - //--- adjusted parameters - int m_periodDeM; // the "period of calculation" parameter of the oscillator - //--- "weights" of market models (0-100) - int m_pattern_0; // model 0 "the oscillator has required direction" - int m_pattern_1; // model 1 "reverse behind the level of overbuying/overselling" - int m_pattern_2; // model 2 "divergence of the oscillator and price" - int m_pattern_3; // model 3 "double divergence of the oscillator and price" - //--- variables - double m_extr_osc[10]; // array of values of extremums of the oscillator - double m_extr_pr[10]; // array of values of the corresponding extremums of price - int m_extr_pos[10]; // array of shifts of extremums (in bars) - uint m_extr_map; // resulting bit-map of ratio of extremums of the oscillator and the price - -public: - CSignalDeM(void); - ~CSignalDeM(void); - //--- methods of setting adjustable parameters - void PeriodDeM(int value) { m_periodDeM=value; } - //--- methods of adjusting "weights" of market models - void Pattern_0(int value) { m_pattern_0=value; } - void Pattern_1(int value) { m_pattern_1=value; } - void Pattern_2(int value) { m_pattern_2=value; } - void Pattern_3(int value) { m_pattern_3=value; } - //--- method of verification of settings - virtual bool ValidationSettings(void); - //--- method of creating the indicator and timeseries - virtual bool InitIndicators(CIndicators *indicators); - //--- methods of checking if the market models are formed - virtual int LongCondition(void); - virtual int ShortCondition(void); - -protected: - //--- method of initialization of the oscillator - bool InitStoch(CIndicators *indicators); - //--- methods of getting data - double DeM(int ind) { return(m_dem.Main(ind)); } - double DiffDeM(int ind) { return(DeM(ind)-DeM(ind+1)); } - int StateDeM(int ind); - bool ExtStateDeM(int ind); - bool CompareMaps(int map,int count,bool minimax=false,int start=0); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CSignalDeM::CSignalDeM(void) : m_periodDeM(14), - m_pattern_0(90), - m_pattern_1(60), - m_pattern_2(100), - m_pattern_3(80) - { -//--- initialization of protected data - m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSignalDeM::~CSignalDeM(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CSignalDeM::ValidationSettings(void) - { -//--- validation settings of additional filters - if(!CExpertSignal::ValidationSettings()) - return(false); -//--- initial data checks - if(m_periodDeM<=0) - { - printf(__FUNCTION__+": period of the DeMarker oscillator must be greater than 0"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create indicators. | -//+------------------------------------------------------------------+ -bool CSignalDeM::InitIndicators(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- initialization of indicators and timeseries of additional filters - if(!CExpertSignal::InitIndicators(indicators)) - return(false); -//--- create and initialize DeMarker oscillator - if(!InitStoch(indicators)) - return(false); -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialize DeMarker oscillators. | -//+------------------------------------------------------------------+ -bool CSignalDeM::InitStoch(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- add object to collection - if(!indicators.Add(GetPointer(m_dem))) - { - printf(__FUNCTION__+": error adding object"); - return(false); - } -//--- initialize object - if(!m_dem.Create(m_symbol.Name(),m_period,m_periodDeM)) - { - printf(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Check of the oscillator state. | -//+------------------------------------------------------------------+ -int CSignalDeM::StateDeM(int ind) - { - int res=0; - double var; -//--- - for(int i=ind;;i++) - { - if(DeM(i+1)==EMPTY_VALUE) - break; - var=DiffDeM(i); - if(res>0) - { - if(var<0) - break; - res++; - continue; - } - if(res<0) - { - if(var>0) - break; - res--; - continue; - } - if(var>0) - res++; - if(var<0) - res--; - } -//--- - return(res); - } -//+------------------------------------------------------------------+ -//| Extended check of the oscillator state consists | -//| in forming a bit-map according to certain rules, | -//| which shows ratios of extremums of the oscillator and price. | -//+------------------------------------------------------------------+ -bool CSignalDeM::ExtStateDeM(int ind) - { -//--- operation of this method results in a bit-map of extremums -//--- practically, the bit-map of extremums is an "array" of 4-bit fields -//--- each "element of the array" definitely describes the ratio -//--- of current extremums of the oscillator and the price with previous ones -//--- purpose of bits of an element of the analyzed bit-map -//--- bit 3 - not used (always 0) -//--- bit 2 - is equal to 1 if the current extremum of the oscillator is "more extreme" than the previous one -//--- (a higher peak or a deeper valley), otherwise - 0 -//--- bit 1 - not used (always 0) -//--- bit 0 - is equal to 1 if the current extremum of price is "more extreme" than the previous one -//--- (a higher peak or a deeper valley), otherwise - 0 -//--- in addition to them, the following is formed: -//--- array of values of extremums of the oscillator, -//--- array of values of price extremums and -//--- array of "distances" between extremums of the oscillator (in bars) -//--- it should be noted that when using the results of the extended check of state, -//--- you should consider, which extremum of the oscillator (peak or valley) -//--- is the "reference point" (i.e. was detected first during the analysis) -//--- if a peak is detected first then even elements of all arrays -//--- will contain information about peaks, and odd elements will contain information about valleys -//--- if a valley is detected first, then respectively in reverse - int pos=ind,off,index; - uint map; // intermediate bit-map for one extremum -//--- - m_extr_map=0; - for(int i=0;i<10;i++) - { - off=StateDeM(pos); - if(off>0) - { - //--- minimum of the oscillator is detected - pos+=off; - m_extr_pos[i]=pos; - m_extr_osc[i]=DeM(pos); - if(i>1) - { - m_extr_pr[i]=m_low.MinValue(pos-2,5,index); - //--- form the intermediate bit-map - map=0; - if(m_extr_pr[i-2]1) - { - m_extr_pr[i]=m_high.MaxValue(pos-2,5,index); - //--- form the intermediate bit-map - map=0; - if(m_extr_pr[i-2]>m_extr_pr[i]) - map+=1; // set bit 0 - if(m_extr_osc[i-2]>m_extr_osc[i]) - map+=4; // set bit 2 - //--- add the result - m_extr_map+=map<<(4*(i-2)); - } - else - m_extr_pr[i]=m_high.MaxValue(pos-1,4,index); - } - } -//--- - return(true); - } -//+------------------------------------------------------------------+ -//| Comparing the bit-map of extremums with pattern. | -//+------------------------------------------------------------------+ -bool CSignalDeM::CompareMaps(int map,int count,bool minimax,int start) - { - int step =(minimax)?4:8; - int total=step*(start+count); -//--- check input parameters for a possible going out of range of the bit-map - if(total>32) - return(false); -//--- bit-map of the patter is an "array" of 4-bit fields -//--- each "element of the array" definitely describes the desired ratio -//--- of current extremums of the oscillator and the price with previous ones -//--- purpose of bits of an elements of the pattern of the bit-map pattern -//--- bit 3 - is equal to if the ratio of extremums of the oscillator is insignificant for us -//--- is equal to 0 if we want to "find" the ratio of extremums of the oscillator determined by the value of bit 2 -//--- bit 2 - is equal to 1 if we want to "discover" the situation when the current extremum of the "oscillator" is "more extreme" than the previous one -//--- (current peak is higher or current valley is deeper) -//--- is equal to 0 if we want to "discover" the situation when the current extremum of the oscillator is "less extreme" than the previous one -//--- (current peak is lower or current valley is less deep) -//--- bit 1 - is equal to 1 if the ratio of extremums is insignificant for us -//--- it is equal to 0 if we want to "find" the ratio of price extremums determined by the value of bit 0 -//--- bit 0 - is equal to 1 if we want to "discover" the situation when the current price extremum is "more extreme" than the previous one -//--- (current peak is higher or current valley is deeper) -//--- it is equal to 0 if we want to "discover" the situation when the current price extremum is "less extreme" than the previous one -//--- (current peak is lower or current valley is less deep) - uint inp_map,check_map; - int i,j; -//--- loop by extremums (4 minimums and 4 maximums) -//--- price and the oscillator are checked separately (thus, there are 16 checks) - for(i=step*start,j=0;i>j)&3; - //--- if the higher-order bit=1, then any ratio is suitable for us - if(inp_map<2) - { - //--- "take" two bits of the corresponding extremum of the price (higher-order bit is always 0) - check_map=(m_extr_map>>i)&3; - if(inp_map!=check_map) - return(false); - } - //--- "take" two bits - pattern of the corresponding oscillator extremum - inp_map=(map>>(j+2))&3; - //--- if the higher-order bit=1, then any ratio is suitable for us - if(inp_map>=2) - continue; - //--- "take" two bits of the corresponding oscillator extremum (higher-order bit is always 0) - check_map=(m_extr_map>>(i+2))&3; - if(inp_map!=check_map) - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will grow. | -//+------------------------------------------------------------------+ -int CSignalDeM::LongCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- check direction of the main line - if(DiffDeM(idx)>0.0) - { - //--- the oscillator is directed upwards confirming the possibility of price growth - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; // "confirming" signal number 0 - //--- if the model 1 is used, search for a reverse of the oscillator upwards behind the level of overselling - if(IS_PATTERN_USAGE(1) && DiffDeM(idx+1)<0.0 && DeM(idx+1)<0.3) - result=m_pattern_1; // signal number 1 - //--- if the model 2 or 3 is used, perform the extended analysis of the oscillator state - if(IS_PATTERN_USAGE(2) || IS_PATTERN_USAGE(3)) - { - ExtStateDeM(idx); - //--- if the model 2 is used, search for the "divergence" signal - if(IS_PATTERN_USAGE(2) && CompareMaps(1,1)) // 00000001b - result=m_pattern_2; // signal number 2 - //--- if the model 3 is used, search for the "double divergence" signal - if(IS_PATTERN_USAGE(3) && CompareMaps(0x11,2)) // 00010001b - return(m_pattern_3); // signal number 3 - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will fall. | -//+------------------------------------------------------------------+ -int CSignalDeM::ShortCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- check direction of the main line - if(DiffDeM(idx)<0.0) - { - //--- the oscillator is directed downwards confirming the possibility of falling of price - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; // "confirming" signal number 0 - //--- if the model 1 is used, search for a reverse of the oscillator downwards behind the level of overbuying - if(IS_PATTERN_USAGE(1) && DiffDeM(idx+1)>0.0 && DeM(idx+1)>0.7) - result=m_pattern_1; // signal number 1 - //--- if the model 2 or 3 is used, perform the extended analysis of the oscillator state - if(IS_PATTERN_USAGE(2) || IS_PATTERN_USAGE(3)) - { - ExtStateDeM(idx); - //--- if the model 2 is used, search for the "divergence" signal - if(IS_PATTERN_USAGE(2) && CompareMaps(1,1)) // 00000001b - result=m_pattern_2; // signal number 2 - //--- if the model 3 is used, search for the "double divergence" signal - if(IS_PATTERN_USAGE(3) && CompareMaps(0x11,2)) // 00010001b - return(m_pattern_3); // signal number 3 - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Signal/SignalEnvelopes.mqh b/Include/Expert/Signal/SignalEnvelopes.mqh deleted file mode 100644 index e1f56e3..0000000 --- a/Include/Expert/Signal/SignalEnvelopes.mqh +++ /dev/null @@ -1,193 +0,0 @@ -//+------------------------------------------------------------------+ -//| SignalEnvelopes.mqh | -//| Copyright 2009-2013, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Signals of indicator 'Envelopes' | -//| Type=SignalAdvanced | -//| Name=Envelopes | -//| ShortName=Envelopes | -//| Class=CSignalEnvelopes | -//| Page=signal_envelopes | -//| Parameter=PeriodMA,int,45,Period of averaging | -//| Parameter=Shift,int,0,Time shift | -//| Parameter=Method,ENUM_MA_METHOD,MODE_SMA,Method of averaging | -//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series | -//| Parameter=Deviation,double,0.15,Deviation | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CSignalEnvelopes. | -//| Purpose: Class of generator of trade signals based on | -//| the 'Envelopes' indicator. | -//| Is derived from the CExpertSignal class. | -//+------------------------------------------------------------------+ -class CSignalEnvelopes : public CExpertSignal - { -protected: - CiEnvelopes m_env; // object-indicator - //--- adjusted parameters - int m_ma_period; // the "period of averaging" parameter of the indicator - int m_ma_shift; // the "time shift" parameter of the indicator - ENUM_MA_METHOD m_ma_method; // the "method of averaging" parameter of the indicator - ENUM_APPLIED_PRICE m_ma_applied; // the "object of averaging" parameter of the indicator - double m_deviation; // the "deviation" parameter of the indicator - double m_limit_in; // threshold sensitivity of the 'rollback zone' - double m_limit_out; // threshold sensitivity of the 'break through zone' - //--- "weights" of market models (0-100) - int m_pattern_0; // model 0 "price is near the necessary border of the envelope" - int m_pattern_1; // model 1 "price crossed a border of the envelope" - -public: - CSignalEnvelopes(void); - ~CSignalEnvelopes(void); - //--- methods of setting adjustable parameters - void PeriodMA(int value) { m_ma_period=value; } - void Shift(int value) { m_ma_shift=value; } - void Method(ENUM_MA_METHOD value) { m_ma_method=value; } - void Applied(ENUM_APPLIED_PRICE value) { m_ma_applied=value; } - void Deviation(double value) { m_deviation=value; } - void LimitIn(double value) { m_limit_in=value; } - void LimitOut(double value) { m_limit_out=value; } - //--- methods of adjusting "weights" of market models - void Pattern_0(int value) { m_pattern_0=value; } - void Pattern_1(int value) { m_pattern_1=value; } - //--- method of verification of settings - virtual bool ValidationSettings(void); - //--- method of creating the indicator and timeseries - virtual bool InitIndicators(CIndicators *indicators); - //--- methods of checking if the market models are formed - virtual int LongCondition(void); - virtual int ShortCondition(void); - -protected: - //--- method of initialization of the indicator - bool InitMA(CIndicators *indicators); - //--- methods of getting data - double Upper(int ind) { return(m_env.Upper(ind)); } - double Lower(int ind) { return(m_env.Lower(ind)); } - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CSignalEnvelopes::CSignalEnvelopes(void) : m_ma_period(45), - m_ma_shift(0), - m_ma_method(MODE_SMA), - m_ma_applied(PRICE_CLOSE), - m_deviation(0.15), - m_limit_in(0.2), - m_limit_out(0.2), - m_pattern_0(90), - m_pattern_1(70) - { -//--- initialization of protected data - m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSignalEnvelopes::~CSignalEnvelopes(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CSignalEnvelopes::ValidationSettings(void) - { -//--- validation settings of additional filters - if(!CExpertSignal::ValidationSettings()) - return(false); -//--- initial data checks - if(m_ma_period<=0) - { - printf(__FUNCTION__+": period MA must be greater than 0"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create indicators. | -//+------------------------------------------------------------------+ -bool CSignalEnvelopes::InitIndicators(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- initialization of indicators and timeseries of additional filters - if(!CExpertSignal::InitIndicators(indicators)) - return(false); -//--- create and initialize MA indicator - if(!InitMA(indicators)) - return(false); -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialize MA indicators. | -//+------------------------------------------------------------------+ -bool CSignalEnvelopes::InitMA(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- add object to collection - if(!indicators.Add(GetPointer(m_env))) - { - printf(__FUNCTION__+": error adding object"); - return(false); - } -//--- initialize object - if(!m_env.Create(m_symbol.Name(),m_period,m_ma_period,m_ma_shift,m_ma_method,m_ma_applied,m_deviation)) - { - printf(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will grow. | -//+------------------------------------------------------------------+ -int CSignalEnvelopes::LongCondition(void) - { - int result=0; - int idx =StartIndex(); - double close=Close(idx); - double upper=Upper(idx); - double lower=Lower(idx); - double width=upper-lower; -//--- if the model 0 is used and price is in the rollback zone, then there is a condition for buying - if(IS_PATTERN_USAGE(0) && closelower-m_limit_out*width) - result=m_pattern_0; -//--- if the model 1 is used and price is above the rollback zone, then there is a condition for buying - if(IS_PATTERN_USAGE(1) && close>upper+m_limit_out*width) - result=m_pattern_1; -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will fall. | -//+------------------------------------------------------------------+ -int CSignalEnvelopes::ShortCondition(void) - { - int result =0; - int idx =StartIndex(); - double close=Close(idx); - double upper=Upper(idx); - double lower=Lower(idx); - double width=upper-lower; -//--- if the model 0 is used and price is in the rollback zone, then there is a condition for selling - if(IS_PATTERN_USAGE(0) && close>upper-m_limit_in*width && close -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Signals of indicator 'Fractal Adaptive Moving Average' | -//| Type=SignalAdvanced | -//| Name=Fractal Adaptive Moving Average | -//| ShortName=FraMA | -//| Class=CSignalFrAMA | -//| Page=signal_frama | -//| Parameter=PeriodMA,int,12,Period of averaging | -//| Parameter=Shift,int,0,Time shift | -//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CSignalFrAMA. | -//| Purpose: Class of generator of trade signals based on | -//| the 'Fractal Adaptive Moving Average' indicator. | -//| Is derived from the CExpertSignal class. | -//+------------------------------------------------------------------+ -class CSignalFrAMA : public CExpertSignal - { -protected: - CiFrAMA m_ma; // object-indicator - //--- adjusted parameters - int m_ma_period; // the "period of averaging" parameter of the indicator - int m_ma_shift; // the "time shift" parameter of the indicator - ENUM_APPLIED_PRICE m_ma_applied; // the "object of averaging" parameter" of the indicator - //--- "weights" of market models (0-100) - int m_pattern_0; // model 0 "price is on the necessary side from the indicator" - int m_pattern_1; // model 1 "price crossed the indicator with opposite direction" - int m_pattern_2; // model 2 "price crossed the indicator with the same direction" - int m_pattern_3; // model 3 "piercing" - -public: - CSignalFrAMA(void); - ~CSignalFrAMA(void); - //--- methods of setting adjustable parameters - void PeriodMA(int value) { m_ma_period=value; } - void Shift(int value) { m_ma_shift=value; } - void Applied(ENUM_APPLIED_PRICE value) { m_ma_applied=value; } - //--- methods of adjusting "weights" of market models - void Pattern_0(int value) { m_pattern_0=value; } - void Pattern_1(int value) { m_pattern_1=value; } - void Pattern_2(int value) { m_pattern_2=value; } - void Pattern_3(int value) { m_pattern_3=value; } - //--- method of verification of settings - virtual bool ValidationSettings(void); - //--- method of creating the indicator and timeseries - virtual bool InitIndicators(CIndicators *indicators); - //--- methods of checking if the market models are formed - virtual int LongCondition(void); - virtual int ShortCondition(void); - -protected: - //--- method of initialization of the indicator - bool InitMA(CIndicators *indicators); - //--- methods of getting data - double MA(int ind) { return(m_ma.Main(ind)); } - double DiffMA(int ind) { return(MA(ind)-MA(ind+1)); } - double DiffOpenMA(int ind) { return(Open(ind)-MA(ind)); } - double DiffHighMA(int ind) { return(High(ind)-MA(ind)); } - double DiffLowMA(int ind) { return(Low(ind)-MA(ind)); } - double DiffCloseMA(int ind) { return(Close(ind)-MA(ind)); } - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CSignalFrAMA::CSignalFrAMA(void) : m_ma_period(12), - m_ma_shift(0), - m_ma_applied(PRICE_CLOSE), - m_pattern_0(90), - m_pattern_1(100), - m_pattern_2(80), - m_pattern_3(60) - { -//--- initialization of protected data - m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSignalFrAMA::~CSignalFrAMA(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CSignalFrAMA::ValidationSettings(void) - { -//--- call of the method of the parent class - if(!CExpertSignal::ValidationSettings()) - return(false); -//--- initial data checks - if(m_ma_period<=0) - { - printf(__FUNCTION__+": period MA must be greater than 0"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create indicators. | -//+------------------------------------------------------------------+ -bool CSignalFrAMA::InitIndicators(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- initialization of indicators and timeseries of additional filters - if(!CExpertSignal::InitIndicators(indicators)) - return(false); -//--- create and initialize FrAMA indicator - if(!InitMA(indicators)) - return(false); -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create MA indicators. | -//+------------------------------------------------------------------+ -bool CSignalFrAMA::InitMA(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- add indicator to collection - if(!indicators.Add(GetPointer(m_ma))) - { - printf(__FUNCTION__+": error adding object"); - return(false); - } -//--- initialize indicator - if(!m_ma.Create(m_symbol.Name(),m_period,m_ma_period,m_ma_shift,m_ma_applied)) - { - printf(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will grow. | -//+------------------------------------------------------------------+ -int CSignalFrAMA::LongCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- analyze positional relationship of the close price and the indicator at the first analyzed bar - if(DiffCloseMA(idx)<0.0) - { - //--- the close price is below the indicator - if(IS_PATTERN_USAGE(1) && DiffOpenMA(idx)>0.0 && DiffMA(idx)>0.0) - { - //--- the open price is above the indicator (i.e. there was an intersection), but the indicator is directed upwards - result=m_pattern_1; - //--- consider that this is an unformed "piercing" and suggest to enter the market at the current price - m_base_price=0.0; - } - } - else - { - //--- the close price is above the indicator (the indicator has no objections to buying) - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; - //--- if the indicator is directed upwards - if(DiffMA(idx)>0.0) - { - if(DiffOpenMA(idx)<0.0) - { - //--- if the model 2 is used - if(IS_PATTERN_USAGE(2)) - { - //--- the open price is below the indicator (i.e. there was an intersection) - result=m_pattern_2; - //--- suggest to enter the market at the "roll back" - m_base_price=m_symbol.NormalizePrice(MA(idx)); - } - } - else - { - //--- if the model 3 is used and the open price is above the indicator - if(IS_PATTERN_USAGE(3) && DiffLowMA(idx)<0.0) - { - //--- the low price is below the indicator - result=m_pattern_3; - //--- consider that this is a formed "piercing" and suggest to enter the market at the current price - m_base_price=0.0; - } - } - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will fall. | -//+------------------------------------------------------------------+ -int CSignalFrAMA::ShortCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- analyze positional relationship of the close price and the indicator at the first analyzed bar - if(DiffCloseMA(idx)>0.0) - { - //--- the close price is above the indicator - if(IS_PATTERN_USAGE(1) && DiffOpenMA(idx)<0.0 && DiffMA(idx)<0.0) - { - //--- the open price is below the indicator (i.e. there was an intersection), but the indicator is directed downwards - result=m_pattern_1; - //--- consider that this is an unformed "piercing" and suggest to enter the market at the current price - m_base_price=0.0; - } - } - else - { - //--- the close price is below the indicator (the indicator has no objections to buying) - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; - //--- the indicator is directed downwards - if(DiffMA(idx)<0.0) - { - if(DiffOpenMA(idx)>0.0) - { - //--- if the model 2 is used - if(IS_PATTERN_USAGE(2)) - { - //--- the open price is above the indicator (i.e. there was an intersection) - result=m_pattern_2; - //--- suggest to enter the market at the "roll back" - m_base_price=m_symbol.NormalizePrice(MA(idx)); - } - } - else - { - //--- if the model 3 is used and the open price is below the indicator - if(IS_PATTERN_USAGE(3) && DiffHighMA(idx)>0.0) - { - //--- the high price is above the indicator - result=m_pattern_3; - //--- consider that this is a formed "piercing" and suggest to enter the market at the current price - m_base_price=0.0; - } - } - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Signal/SignalITF.mqh b/Include/Expert/Signal/SignalITF.mqh deleted file mode 100644 index b10c760..0000000 --- a/Include/Expert/Signal/SignalITF.mqh +++ /dev/null @@ -1,91 +0,0 @@ -//+------------------------------------------------------------------+ -//| SignalITF.mqh | -//| Copyright 2009-2013, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Signals of intraday time filter | -//| Type=SignalAdvanced | -//| Name=IntradayTimeFilter | -//| ShortName=ITF | -//| Class=CSignalITF | -//| Page=signal_time_filter | -//| Parameter=GoodHourOfDay,int,-1,Good hour | -//| Parameter=BadHoursOfDay,int,0,Bad hours (bit-map) | -//| Parameter=GoodDayOfWeek,int,-1,Good day of week | -//| Parameter=BadDaysOfWeek,int,0,Bad days of week (bit-map) | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CSignalITF. | -//| Appointment: Class trading signals time filter. | -//| Derives from class CExpertSignal. | -//+------------------------------------------------------------------+ -class CSignalITF : public CExpertSignal - { -protected: - //--- input parameters - int m_good_minute_of_hour; - long m_bad_minutes_of_hour; - int m_good_hour_of_day; - int m_bad_hours_of_day; - int m_good_day_of_week; - int m_bad_days_of_week; - -public: - CSignalITF(void); - ~CSignalITF(void); - //--- methods initialize protected data - void GoodMinuteOfHour(int value) { m_good_minute_of_hour=value; } - void BadMinutesOfHour(long value) { m_bad_minutes_of_hour=value; } - void GoodHourOfDay(int value) { m_good_hour_of_day=value; } - void BadHoursOfDay(int value) { m_bad_hours_of_day=value; } - void GoodDayOfWeek(int value) { m_good_day_of_week=value; } - void BadDaysOfWeek(int value) { m_bad_days_of_week=value; } - //--- methods of checking conditions of entering the market - virtual double Direction(void); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CSignalITF::CSignalITF(void) : m_good_minute_of_hour(-1), - m_bad_minutes_of_hour(0), - m_good_hour_of_day(-1), - m_bad_hours_of_day(0), - m_good_day_of_week(-1), - m_bad_days_of_week(0) - { - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSignalITF::~CSignalITF(void) - { - } -//+------------------------------------------------------------------+ -//| Check conditions for time filter. | -//+------------------------------------------------------------------+ -double CSignalITF::Direction(void) - { - MqlDateTime s_time; -//--- - TimeCurrent(s_time); -//--- check days conditions - if(!((m_good_day_of_week==-1 || m_good_day_of_week==s_time.day_of_week) && - !(m_bad_days_of_week&(1< -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Signals of indicator 'Moving Average' | -//| Type=SignalAdvanced | -//| Name=Moving Average | -//| ShortName=MA | -//| Class=CSignalMA | -//| Page=signal_ma | -//| Parameter=PeriodMA,int,12,Period of averaging | -//| Parameter=Shift,int,0,Time shift | -//| Parameter=Method,ENUM_MA_METHOD,MODE_SMA,Method of averaging | -//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CSignalMA. | -//| Purpose: Class of generator of trade signals based on | -//| the 'Moving Average' indicator. | -//| Is derived from the CExpertSignal class. | -//+------------------------------------------------------------------+ -class CSignalMA : public CExpertSignal - { -protected: - CiMA m_ma; // object-indicator - //--- adjusted parameters - int m_ma_period; // the "period of averaging" parameter of the indicator - int m_ma_shift; // the "time shift" parameter of the indicator - ENUM_MA_METHOD m_ma_method; // the "method of averaging" parameter of the indicator - ENUM_APPLIED_PRICE m_ma_applied; // the "object of averaging" parameter of the indicator - //--- "weights" of market models (0-100) - int m_pattern_0; // model 0 "price is on the necessary side from the indicator" - int m_pattern_1; // model 1 "price crossed the indicator with opposite direction" - int m_pattern_2; // model 2 "price crossed the indicator with the same direction" - int m_pattern_3; // model 3 "piercing" - -public: - CSignalMA(void); - ~CSignalMA(void); - //--- methods of setting adjustable parameters - void PeriodMA(int value) { m_ma_period=value; } - void Shift(int value) { m_ma_shift=value; } - void Method(ENUM_MA_METHOD value) { m_ma_method=value; } - void Applied(ENUM_APPLIED_PRICE value) { m_ma_applied=value; } - //--- methods of adjusting "weights" of market models - void Pattern_0(int value) { m_pattern_0=value; } - void Pattern_1(int value) { m_pattern_1=value; } - void Pattern_2(int value) { m_pattern_2=value; } - void Pattern_3(int value) { m_pattern_3=value; } - //--- method of verification of settings - virtual bool ValidationSettings(void); - //--- method of creating the indicator and timeseries - virtual bool InitIndicators(CIndicators *indicators); - //--- methods of checking if the market models are formed - virtual int LongCondition(void); - virtual int ShortCondition(void); - -protected: - //--- method of initialization of the indicator - bool InitMA(CIndicators *indicators); - //--- methods of getting data - double MA(int ind) { return(m_ma.Main(ind)); } - double DiffMA(int ind) { return(MA(ind)-MA(ind+1)); } - double DiffOpenMA(int ind) { return(Open(ind)-MA(ind)); } - double DiffHighMA(int ind) { return(High(ind)-MA(ind)); } - double DiffLowMA(int ind) { return(Low(ind)-MA(ind)); } - double DiffCloseMA(int ind) { return(Close(ind)-MA(ind)); } - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CSignalMA::CSignalMA(void) : m_ma_period(12), - m_ma_shift(0), - m_ma_method(MODE_SMA), - m_ma_applied(PRICE_CLOSE), - m_pattern_0(80), - m_pattern_1(10), - m_pattern_2(60), - m_pattern_3(60) - { -//--- initialization of protected data - m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSignalMA::~CSignalMA(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CSignalMA::ValidationSettings(void) - { -//--- validation settings of additional filters - if(!CExpertSignal::ValidationSettings()) - return(false); -//--- initial data checks - if(m_ma_period<=0) - { - printf(__FUNCTION__+": period MA must be greater than 0"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create indicators. | -//+------------------------------------------------------------------+ -bool CSignalMA::InitIndicators(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- initialization of indicators and timeseries of additional filters - if(!CExpertSignal::InitIndicators(indicators)) - return(false); -//--- create and initialize MA indicator - if(!InitMA(indicators)) - return(false); -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialize MA indicators. | -//+------------------------------------------------------------------+ -bool CSignalMA::InitMA(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- add object to collection - if(!indicators.Add(GetPointer(m_ma))) - { - printf(__FUNCTION__+": error adding object"); - return(false); - } -//--- initialize object - if(!m_ma.Create(m_symbol.Name(),m_period,m_ma_period,m_ma_shift,m_ma_method,m_ma_applied)) - { - printf(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will grow. | -//+------------------------------------------------------------------+ -int CSignalMA::LongCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- analyze positional relationship of the close price and the indicator at the first analyzed bar - if(DiffCloseMA(idx)<0.0) - { - //--- the close price is below the indicator - if(IS_PATTERN_USAGE(1) && DiffOpenMA(idx)>0.0 && DiffMA(idx)>0.0) - { - //--- the open price is above the indicator (i.e. there was an intersection), but the indicator is directed upwards - result=m_pattern_1; - //--- consider that this is an unformed "piercing" and suggest to enter the market at the current price - m_base_price=0.0; - } - } - else - { - //--- the close price is above the indicator (the indicator has no objections to buying) - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; - //--- if the indicator is directed upwards - if(DiffMA(idx)>0.0) - { - if(DiffOpenMA(idx)<0.0) - { - //--- if the model 2 is used - if(IS_PATTERN_USAGE(2)) - { - //--- the open price is below the indicator (i.e. there was an intersection) - result=m_pattern_2; - //--- suggest to enter the market at the "roll back" - m_base_price=m_symbol.NormalizePrice(MA(idx)); - } - } - else - { - //--- if the model 3 is used and the open price is above the indicator - if(IS_PATTERN_USAGE(3) && DiffLowMA(idx)<0.0) - { - //--- the low price is below the indicator - result=m_pattern_3; - //--- consider that this is a formed "piercing" and suggest to enter the market at the current price - m_base_price=0.0; - } - } - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will fall. | -//+------------------------------------------------------------------+ -int CSignalMA::ShortCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- analyze positional relationship of the close price and the indicator at the first analyzed bar - if(DiffCloseMA(idx)>0.0) - { - //--- the close price is above the indicator - if(IS_PATTERN_USAGE(1) && DiffOpenMA(idx)<0.0 && DiffMA(idx)<0.0) - { - //--- the open price is below the indicator (i.e. there was an intersection), but the indicator is directed downwards - result=m_pattern_1; - //--- consider that this is an unformed "piercing" and suggest to enter the market at the current price - m_base_price=0.0; - } - } - else - { - //--- the close price is below the indicator (the indicator has no objections to buying) - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; - //--- the indicator is directed downwards - if(DiffMA(idx)<0.0) - { - if(DiffOpenMA(idx)>0.0) - { - //--- if the model 2 is used - if(IS_PATTERN_USAGE(2)) - { - //--- the open price is above the indicator (i.e. there was an intersection) - result=m_pattern_2; - //--- suggest to enter the market at the "roll back" - m_base_price=m_symbol.NormalizePrice(MA(idx)); - } - } - else - { - //--- if the model 3 is used and the open price is below the indicator - if(IS_PATTERN_USAGE(3) && DiffHighMA(idx)>0.0) - { - //--- the high price is above the indicator - result=m_pattern_3; - //--- consider that this is a formed "piercing" and suggest to enter the market at the current price - m_base_price=0.0; - } - } - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Signal/SignalMACD.mqh b/Include/Expert/Signal/SignalMACD.mqh deleted file mode 100644 index 01ee550..0000000 --- a/Include/Expert/Signal/SignalMACD.mqh +++ /dev/null @@ -1,408 +0,0 @@ -//+------------------------------------------------------------------+ -//| SignalMACD.mqh | -//| Copyright 2009-2013, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Signals of oscillator 'MACD' | -//| Type=SignalAdvanced | -//| Name=MACD | -//| ShortName=MACD | -//| Class=CSignalMACD | -//| Page=signal_macd | -//| Parameter=PeriodFast,int,12,Period of fast EMA | -//| Parameter=PeriodSlow,int,24,Period of slow EMA | -//| Parameter=PeriodSignal,int,9,Period of averaging of difference | -//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CSignalMACD. | -//| Purpose: Class of generator of trade signals based on | -//| the 'Moving Average Convergence/Divergence' oscillator. | -//| Is derived from the CExpertSignal class. | -//+------------------------------------------------------------------+ -class CSignalMACD : public CExpertSignal - { -protected: - CiMACD m_MACD; // object-oscillator - //--- adjusted parameters - int m_period_fast; // the "period of fast EMA" parameter of the oscillator - int m_period_slow; // the "period of slow EMA" parameter of the oscillator - int m_period_signal; // the "period of averaging of difference" parameter of the oscillator - ENUM_APPLIED_PRICE m_applied; // the "price series" parameter of the oscillator - //--- "weights" of market models (0-100) - int m_pattern_0; // model 0 "the oscillator has required direction" - int m_pattern_1; // model 1 "reverse of the oscillator to required direction" - int m_pattern_2; // model 2 "crossing of main and signal line" - int m_pattern_3; // model 3 "crossing of main line an the zero level" - int m_pattern_4; // model 4 "divergence of the oscillator and price" - int m_pattern_5; // model 5 "double divergence of the oscillator and price" - //--- variables - double m_extr_osc[10]; // array of values of extremums of the oscillator - double m_extr_pr[10]; // array of values of the corresponding extremums of price - int m_extr_pos[10]; // array of shifts of extremums (in bars) - uint m_extr_map; // resulting bit-map of ratio of extremums of the oscillator and the price - -public: - CSignalMACD(void); - ~CSignalMACD(void); - //--- methods of setting adjustable parameters - void PeriodFast(int value) { m_period_fast=value; } - void PeriodSlow(int value) { m_period_slow=value; } - void PeriodSignal(int value) { m_period_signal=value; } - void Applied(ENUM_APPLIED_PRICE value) { m_applied=value; } - //--- methods of adjusting "weights" of market models - void Pattern_0(int value) { m_pattern_0=value; } - void Pattern_1(int value) { m_pattern_1=value; } - void Pattern_2(int value) { m_pattern_2=value; } - void Pattern_3(int value) { m_pattern_3=value; } - void Pattern_4(int value) { m_pattern_4=value; } - void Pattern_5(int value) { m_pattern_5=value; } - //--- method of verification of settings - virtual bool ValidationSettings(void); - //--- method of creating the indicator and timeseries - virtual bool InitIndicators(CIndicators *indicators); - //--- methods of checking if the market models are formed - virtual int LongCondition(void); - virtual int ShortCondition(void); - -protected: - //--- method of initialization of the oscillator - bool InitMACD(CIndicators *indicators); - //--- methods of getting data - double Main(int ind) { return(m_MACD.Main(ind)); } - double Signal(int ind) { return(m_MACD.Signal(ind)); } - double DiffMain(int ind) { return(Main(ind)-Main(ind+1)); } - int StateMain(int ind); - double State(int ind) { return(Main(ind)-Signal(ind)); } - bool ExtState(int ind); - bool CompareMaps(int map,int count,bool minimax=false,int start=0); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CSignalMACD::CSignalMACD(void) : m_period_fast(12), - m_period_slow(24), - m_period_signal(9), - m_applied(PRICE_CLOSE), - m_pattern_0(10), - m_pattern_1(30), - m_pattern_2(80), - m_pattern_3(50), - m_pattern_4(60), - m_pattern_5(100) - { -//--- initialization of protected data - m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSignalMACD::~CSignalMACD(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CSignalMACD::ValidationSettings(void) - { -//--- validation settings of additional filters - if(!CExpertSignal::ValidationSettings()) - return(false); -//--- initial data checks - if(m_period_fast>=m_period_slow) - { - printf(__FUNCTION__+": slow period must be greater than fast period"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create indicators. | -//+------------------------------------------------------------------+ -bool CSignalMACD::InitIndicators(CIndicators *indicators) - { -//--- check of pointer is performed in the method of the parent class -//--- -//--- initialization of indicators and timeseries of additional filters - if(!CExpertSignal::InitIndicators(indicators)) - return(false); -//--- create and initialize MACD oscilator - if(!InitMACD(indicators)) - return(false); -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialize MACD oscillators. | -//+------------------------------------------------------------------+ -bool CSignalMACD::InitMACD(CIndicators *indicators) - { -//--- add object to collection - if(!indicators.Add(GetPointer(m_MACD))) - { - printf(__FUNCTION__+": error adding object"); - return(false); - } -//--- initialize object - if(!m_MACD.Create(m_symbol.Name(),m_period,m_period_fast,m_period_slow,m_period_signal,m_applied)) - { - printf(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Check of the oscillator state. | -//+------------------------------------------------------------------+ -int CSignalMACD::StateMain(int ind) - { - int res=0; - double var; -//--- - for(int i=ind;;i++) - { - if(Main(i+1)==EMPTY_VALUE) - break; - var=DiffMain(i); - if(res>0) - { - if(var<0) - break; - res++; - continue; - } - if(res<0) - { - if(var>0) - break; - res--; - continue; - } - if(var>0) - res++; - if(var<0) - res--; - } -//--- - return(res); - } -//+------------------------------------------------------------------+ -//| Extended check of the oscillator state consists | -//| in forming a bit-map according to certain rules, | -//| which shows ratios of extremums of the oscillator and price. | -//+------------------------------------------------------------------+ -bool CSignalMACD::ExtState(int ind) - { -//--- operation of this method results in a bit-map of extremums -//--- practically, the bit-map of extremums is an "array" of 4-bit fields -//--- each "element of the array" definitely describes the ratio -//--- of current extremums of the oscillator and the price with previous ones -//--- purpose of bits of an element of the analyzed bit-map -//--- bit 3 - not used (always 0) -//--- bit 2 - is equal to 1 if the current extremum of the oscillator is "more extreme" than the previous one -//--- (a higher peak or a deeper valley), otherwise - 0 -//--- bit 1 - not used (always 0) -//--- bit 0 - is equal to 1 if the current extremum of price is "more extreme" than the previous one -//--- (a higher peak or a deeper valley), otherwise - 0 -//--- in addition to them, the following is formed: -//--- array of values of extremums of the oscillator, -//--- array of values of price extremums and -//--- array of "distances" between extremums of the oscillator (in bars) -//--- it should be noted that when using the results of the extended check of state, -//--- you should consider, which extremum of the oscillator (peak or valley) -//--- is the "reference point" (i.e. was detected first during the analysis) -//--- if a peak is detected first then even elements of all arrays -//--- will contain information about peaks, and odd elements will contain information about valleys -//--- if a valley is detected first, then respectively in reverse - int pos=ind,off,index; - uint map; // intermediate bit-map for one extremum -//--- - m_extr_map=0; - for(int i=0;i<10;i++) - { - off=StateMain(pos); - if(off>0) - { - //--- minimum of the oscillator is detected - pos+=off; - m_extr_pos[i]=pos; - m_extr_osc[i]=Main(pos); - if(i>1) - { - m_extr_pr[i]=m_low.MinValue(pos-2,5,index); - //--- form the intermediate bit-map - map=0; - if(m_extr_pr[i-2]1) - { - m_extr_pr[i]=m_high.MaxValue(pos-2,5,index); - //--- form the intermediate bit-map - map=0; - if(m_extr_pr[i-2]>m_extr_pr[i]) - map+=1; // set bit 0 - if(m_extr_osc[i-2]>m_extr_osc[i]) - map+=4; // set bit 2 - //--- add the result - m_extr_map+=map<<(4*(i-2)); - } - else - m_extr_pr[i]=m_high.MaxValue(pos-1,4,index); - } - } -//--- - return(true); - } -//+------------------------------------------------------------------+ -//| Comparing the bit-map of extremums with pattern. | -//+------------------------------------------------------------------+ -bool CSignalMACD::CompareMaps(int map,int count,bool minimax,int start) - { - int step =(minimax)?4:8; - int total=step*(start+count); -//--- check input parameters for a possible going out of range of the bit-map - if(total>32) - return(false); -//--- bit-map of the patter is an "array" of 4-bit fields -//--- each "element of the array" definitely describes the desired ratio -//--- of current extremums of the oscillator and the price with previous ones -//--- purpose of bits of an elements of the pattern of the bit-map pattern -//--- bit 3 - is equal to if the ratio of extremums of the oscillator is insignificant for us -//--- is equal to 0 if we want to "find" the ratio of extremums of the oscillator determined by the value of bit 2 -//--- bit 2 - is equal to 1 if we want to "discover" the situation when the current extremum of the "oscillator" is "more extreme" than the previous one -//--- (current peak is higher or current valley is deeper) -//--- is equal to 0 if we want to "discover" the situation when the current extremum of the oscillator is "less extreme" than the previous one -//--- (current peak is lower or current valley is less deep) -//--- bit 1 - is equal to 1 if the ratio of extremums is insignificant for us -//--- it is equal to 0 if we want to "find" the ratio of price extremums determined by the value of bit 0 -//--- bit 0 - is equal to 1 if we want to "discover" the situation when the current price extremum is "more extreme" than the previous one -//--- (current peak is higher or current valley is deeper) -//--- it is equal to 0 if we want to "discover" the situation when the current price extremum is "less extreme" than the previous one -//--- (current peak is lower or current valley is less deep) - uint inp_map,check_map; - int i,j; -//--- loop by extremums (4 minimums and 4 maximums) -//--- price and the oscillator are checked separately (thus, there are 16 checks) - for(i=step*start,j=0;i>j)&3; - //--- if the higher-order bit=1, then any ratio is suitable for us - if(inp_map<2) - { - //--- "take" two bits of the corresponding extremum of the price (higher-order bit is always 0) - check_map=(m_extr_map>>i)&3; - if(inp_map!=check_map) - return(false); - } - //--- "take" two bits - pattern of the corresponding oscillator extremum - inp_map=(map>>(j+2))&3; - //--- if the higher-order bit=1, then any ratio is suitable for us - if(inp_map>=2) - continue; - //--- "take" two bits of the corresponding oscillator extremum (higher-order bit is always 0) - check_map=(m_extr_map>>(i+2))&3; - if(inp_map!=check_map) - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will grow. | -//+------------------------------------------------------------------+ -int CSignalMACD::LongCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- check direction of the main line - if(DiffMain(idx)>0.0) - { - //--- the main line is directed upwards, and it confirms the possibility of price growth - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; // "confirming" signal number 0 - //--- if the model 1 is used, look for a reverse of the main line - if(IS_PATTERN_USAGE(1) && DiffMain(idx+1)<0.0) - result=m_pattern_1; // signal number 1 - //--- if the model 2 is used, look for an intersection of the main and signal line - if(IS_PATTERN_USAGE(2) && State(idx)>0.0 && State(idx+1)<0.0) - result=m_pattern_2; // signal number 2 - //--- if the model 3 is used, look for an intersection of the main line and the zero level - if(IS_PATTERN_USAGE(3) && Main(idx)>0.0 && Main(idx+1)<0.0) - result=m_pattern_3; // signal number 3 - //--- if the models 4 or 5 are used and the main line turned upwards below the zero level, look for divergences - if((IS_PATTERN_USAGE(4) || IS_PATTERN_USAGE(5)) && Main(idx)<0.0) - { - //--- perform the extended analysis of the oscillator state - ExtState(idx); - //--- if the model 4 is used, look for the "divergence" signal - if(IS_PATTERN_USAGE(4) && CompareMaps(1,1)) // 0000 0001b - result=m_pattern_4; // signal number 4 - //--- if the model 5 is used, look for the "double divergence" signal - if(IS_PATTERN_USAGE(5) && CompareMaps(0x11,2)) // 0001 0001b - return(m_pattern_5); // signal number 5 - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will fall. | -//+------------------------------------------------------------------+ -int CSignalMACD::ShortCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- check direction of the main line - if(DiffMain(idx)<0.0) - { - //--- main line is directed downwards, confirming a possibility of falling of price - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; // "confirming" signal number 0 - //--- if the model 1 is used, look for a reverse of the main line - if(IS_PATTERN_USAGE(1) && DiffMain(idx+1)>0.0) - result=m_pattern_1; // signal number 1 - //--- if the model 2 is used, look for an intersection of the main and signal line - if(IS_PATTERN_USAGE(2) && State(idx)<0.0 && State(idx+1)>0.0) - result=m_pattern_2; // signal number 2 - //--- if the model 3 is used, look for an intersection of the main line and the zero level - if(IS_PATTERN_USAGE(3) && Main(idx)<0.0 && Main(idx+1)>0.0) - result=m_pattern_3; // signal number 3 - //--- if the models 4 or 5 are used and the main line turned downwards above the zero level, look for divergences - if((IS_PATTERN_USAGE(4) || IS_PATTERN_USAGE(5)) && Main(idx)>0.0) - { - //--- perform the extended analysis of the oscillator state - ExtState(idx); - //--- if the model 4 is used, look for the "divergence" signal - if(IS_PATTERN_USAGE(4) && CompareMaps(1,1)) // 0000 0001b - result=m_pattern_4; // signal number 4 - //--- if the model 5 is used, look for the "double divergence" signal - if(IS_PATTERN_USAGE(5) && CompareMaps(0x11,2)) // 0001 0001b - return(m_pattern_5); // signal number 5 - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Signal/SignalRSI.mqh b/Include/Expert/Signal/SignalRSI.mqh deleted file mode 100644 index 2506abf..0000000 --- a/Include/Expert/Signal/SignalRSI.mqh +++ /dev/null @@ -1,400 +0,0 @@ -//+------------------------------------------------------------------+ -//| SignalRSI.mqh | -//| Copyright 2009-2013, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Signals of oscillator 'Relative Strength Index' | -//| Type=SignalAdvanced | -//| Name=Relative Strength Index | -//| ShortName=RSI | -//| Class=CSignalRSI | -//| Page=signal_rsi | -//| Parameter=PeriodRSI,int,8,Period of calculation | -//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CSignalRSI. | -//| Purpose: Class of generator of trade signals based on | -//| the 'Relative Strength Index' oscillator. | -//| Is derived from the CExpertSignal class. | -//+------------------------------------------------------------------+ -class CSignalRSI : public CExpertSignal - { -protected: - CiRSI m_rsi; // object-oscillator - //--- adjusted parameters - int m_periodRSI; // the "period of calculation" parameter of the oscillator - ENUM_APPLIED_PRICE m_applied; // the "prices series" parameter of the oscillator - //--- "weights" of market models (0-100) - int m_pattern_0; // model 0 "the oscillator has required direction" - int m_pattern_1; // model 1 "reverse behind the level of overbuying/overselling" - int m_pattern_2; // model 2 "failed swing" - int m_pattern_3; // model 3 "divergence of the oscillator and price" - int m_pattern_4; // model 4 "double divergence of the oscillator and price" - int m_pattern_5; // model 5 "head/shoulders" - //--- variables - double m_extr_osc[10]; // array of values of extremums of the oscillator - double m_extr_pr[10]; // array of values of the corresponding extremums of price - int m_extr_pos[10]; // array of shifts of extremums (in bars) - uint m_extr_map; // resulting bit-map of ratio of extremums of the oscillator and the price - -public: - CSignalRSI(void); - ~CSignalRSI(void); - //--- methods of setting adjustable parameters - void PeriodRSI(int value) { m_periodRSI=value; } - void Applied(ENUM_APPLIED_PRICE value) { m_applied=value; } - //--- methods of adjusting "weights" of market models - void Pattern_0(int value) { m_pattern_0=value; } - void Pattern_1(int value) { m_pattern_1=value; } - void Pattern_2(int value) { m_pattern_2=value; } - void Pattern_3(int value) { m_pattern_3=value; } - void Pattern_4(int value) { m_pattern_4=value; } - void Pattern_5(int value) { m_pattern_5=value; } - //--- method of verification of settings - virtual bool ValidationSettings(void); - //--- method of creating the indicator and timeseries - virtual bool InitIndicators(CIndicators *indicators); - //--- methods of checking if the market models are formed - virtual int LongCondition(void); - virtual int ShortCondition(void); - -protected: - //--- method of initialization of the oscillator - bool InitRSI(CIndicators *indicators); - //--- methods of getting data - double RSI(int ind) { return(m_rsi.Main(ind)); } - double DiffRSI(int ind) { return(RSI(ind)-RSI(ind+1)); } - int StateRSI(int ind); - bool ExtStateRSI(int ind); - bool CompareMaps(int map,int count,bool minimax=false,int start=0); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CSignalRSI::CSignalRSI(void) : m_periodRSI(14), - m_applied(PRICE_CLOSE), - m_pattern_0(70), - m_pattern_1(100), - m_pattern_2(90), - m_pattern_3(80), - m_pattern_4(100), - m_pattern_5(20) - { -//--- initialization of protected data - m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSignalRSI::~CSignalRSI(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CSignalRSI::ValidationSettings(void) - { -//--- validation settings of additional filters - if(!CExpertSignal::ValidationSettings()) - return(false); -//--- initial data checks - if(m_periodRSI<=0) - { - printf(__FUNCTION__+": period of the RSI oscillator must be greater than 0"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create indicators. | -//+------------------------------------------------------------------+ -bool CSignalRSI::InitIndicators(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- initialization of indicators and timeseries of additional filters - if(!CExpertSignal::InitIndicators(indicators)) - return(false); -//--- create and initialize RSI oscillator - if(!InitRSI(indicators)) - return(false); -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialize RSI oscillators. | -//+------------------------------------------------------------------+ -bool CSignalRSI::InitRSI(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- add object to collection - if(!indicators.Add(GetPointer(m_rsi))) - { - printf(__FUNCTION__+": error adding object"); - return(false); - } -//--- initialize object - if(!m_rsi.Create(m_symbol.Name(),m_period,m_periodRSI,m_applied)) - { - printf(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Check of the oscillator state. | -//+------------------------------------------------------------------+ -int CSignalRSI::StateRSI(int ind) - { - int res=0; - double var; -//--- - for(int i=ind;;i++) - { - if(RSI(i+1)==EMPTY_VALUE) - break; - var=DiffRSI(i); - if(res>0) - { - if(var<0) - break; - res++; - continue; - } - if(res<0) - { - if(var>0) - break; - res--; - continue; - } - if(var>0) - res++; - if(var<0) - res--; - } -//--- - return(res); - } -//+------------------------------------------------------------------+ -//| Extended check of the oscillator state consists | -//| in forming a bit-map according to certain rules, | -//| which shows ratios of extremums of the oscillator and price. | -//+------------------------------------------------------------------+ -bool CSignalRSI::ExtStateRSI(int ind) - { -//--- operation of this method results in a bit-map of extremums -//--- practically, the bit-map of extremums is an "array" of 4-bit fields -//--- each "element of the array" definitely describes the ratio -//--- of current extremums of the oscillator and the price with previous ones -//--- purpose of bits of an element of the analyzed bit-map -//--- bit 3 - not used (always 0) -//--- bit 2 - is equal to 1 if the current extremum of the oscillator is "more extreme" than the previous one -//--- (a higher peak or a deeper valley), otherwise - 0 -//--- bit 1 - not used (always 0) -//--- bit 0 - is equal to 1 if the current extremum of price is "more extreme" than the previous one -//--- (a higher peak or a deeper valley), otherwise - 0 -//--- in addition to them, the following is formed: -//--- array of values of extremums of the oscillator, -//--- array of values of price extremums and -//--- array of "distances" between extremums of the oscillator (in bars) -//--- it should be noted that when using the results of the extended check of state, -//--- you should consider, which extremum of the oscillator (peak or valley) -//--- is the "reference point" (i.e. was detected first during the analysis) -//--- if a peak is detected first then even elements of all arrays -//--- will contain information about peaks, and odd elements will contain information about valleys -//--- if a valley is detected first, then respectively in reverse - int pos=ind,off,index; - uint map; // intermediate bit-map for one extremum -//--- - m_extr_map=0; - for(int i=0;i<10;i++) - { - off=StateRSI(pos); - if(off>0) - { - //--- minimum of the oscillator is detected - pos+=off; - m_extr_pos[i]=pos; - m_extr_osc[i]=RSI(pos); - if(i>1) - { - m_extr_pr[i]=m_low.MinValue(pos-2,5,index); - //--- form the intermediate bit-map - map=0; - if(m_extr_pr[i-2]1) - { - m_extr_pr[i]=m_high.MaxValue(pos-2,5,index); - //--- form the intermediate bit-map - map=0; - if(m_extr_pr[i-2]>m_extr_pr[i]) - map+=1; // set bit 0 - if(m_extr_osc[i-2]>m_extr_osc[i]) - map+=4; // set bit 2 - //--- add the result - m_extr_map+=map<<(4*(i-2)); - } - else - m_extr_pr[i]=m_high.MaxValue(pos-1,4,index); - } - } -//--- - return(true); - } -//+------------------------------------------------------------------+ -//| Comparing the bit-map of extremums with pattern. | -//+------------------------------------------------------------------+ -bool CSignalRSI::CompareMaps(int map,int count,bool minimax,int start) - { - int step =(minimax)?4:8; - int total=step*(start+count); -//--- check input parameters for a possible going out of range of the bit-map - if(total>32) - return(false); -//--- bit-map of the patter is an "array" of 4-bit fields -//--- each "element of the array" definitely describes the desired ratio -//--- of current extremums of the oscillator and the price with previous ones -//--- purpose of bits of an elements of the pattern of the bit-map pattern -//--- bit 3 - is equal to if the ratio of extremums of the oscillator is insignificant for us -//--- is equal to 0 if we want to "find" the ratio of extremums of the oscillator determined by the value of bit 2 -//--- bit 2 - is equal to 1 if we want to "discover" the situation when the current extremum of the "oscillator" is "more extreme" than the previous one -//--- (current peak is higher or current valley is deeper) -//--- is equal to 0 if we want to "discover" the situation when the current extremum of the oscillator is "less extreme" than the previous one -//--- (current peak is lower or current valley is less deep) -//--- bit 1 - is equal to 1 if the ratio of extremums is insignificant for us -//--- it is equal to 0 if we want to "find" the ratio of price extremums determined by the value of bit 0 -//--- bit 0 - is equal to 1 if we want to "discover" the situation when the current price extremum is "more extreme" than the previous one -//--- (current peak is higher or current valley is deeper) -//--- it is equal to 0 if we want to "discover" the situation when the current price extremum is "less extreme" than the previous one -//--- (current peak is lower or current valley is less deep) - uint inp_map,check_map; - int i,j; -//--- loop by extremums (4 minimums and 4 maximums) -//--- price and the oscillator are checked separately (thus, there are 16 checks) - for(i=step*start,j=0;i>j)&3; - //--- if the higher-order bit=1, then any ratio is suitable for us - if(inp_map<2) - { - //--- "take" two bits of the corresponding extremum of the price (higher-order bit is always 0) - check_map=(m_extr_map>>i)&3; - if(inp_map!=check_map) - return(false); - } - //--- "take" two bits - pattern of the corresponding oscillator extremum - inp_map=(map>>(j+2))&3; - //--- if the higher-order bit=1, then any ratio is suitable for us - if(inp_map>=2) - continue; - //--- "take" two bits of the corresponding oscillator extremum (higher-order bit is always 0) - check_map=(m_extr_map>>(i+2))&3; - if(inp_map!=check_map) - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will grow. | -//+------------------------------------------------------------------+ -int CSignalRSI::LongCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- - if(DiffRSI(idx)>0.0) - { - //--- the oscillator is directed upwards confirming the possibility of price growth - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; // "confirming" signal number 0 - //--- if the model 1 is used, search for a reverse of the oscillator upwards behind the level of overselling - if(IS_PATTERN_USAGE(1) && DiffRSI(idx+1)<0.0 && RSI(idx+1)<30.0) - result=m_pattern_1; // signal number 1 - //--- if the model 2, 3, 4 or 5 is used, perform the extended analysis of the oscillator state - if(IS_PATTERN_USAGE(2) || IS_PATTERN_USAGE(3) || IS_PATTERN_USAGE(4) || IS_PATTERN_USAGE(5)) - { - ExtStateRSI(idx); - //--- search for the "failed swing" signal - if(IS_PATTERN_USAGE(2) && RSI(idx)>m_extr_osc[1]) - result=m_pattern_2; // signal number 2 - //--- search for the "divergence" signal - if(IS_PATTERN_USAGE(3) && CompareMaps(1,1)) // 0000 0001b - result=m_pattern_3; // signal number 3 - //--- search for the "double divergence" signal - if(IS_PATTERN_USAGE(4) && CompareMaps(0x11,2)) // 0001 0001b - return(m_pattern_4); // signal number 4 - //--- search for the "head/shoulders" signal - if(IS_PATTERN_USAGE(5) && CompareMaps(0x62662,5,true) && RSI(idx)>m_extr_osc[1]) // 01100010011001100010b - result=m_pattern_5; // signal number 5 - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will fall. | -//+------------------------------------------------------------------+ -int CSignalRSI::ShortCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- - if(DiffRSI(idx)<0.0) - { - //--- the oscillator is directed downwards confirming the possibility of falling of price - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; // "confirming" signal number 0 - //--- if the model 1 is used, search for a reverse of the oscillator downwards behind the level of overbuying - if(IS_PATTERN_USAGE(1) && DiffRSI(idx+1)>0.0 && RSI(idx+1)>70.0) - result=m_pattern_1; // signal number 1 - //--- if the model 2, 3, 4 or 5 is used, perform the extended analysis of the oscillator state - if(IS_PATTERN_USAGE(2) || IS_PATTERN_USAGE(3) || IS_PATTERN_USAGE(4) || IS_PATTERN_USAGE(5)) - { - ExtStateRSI(idx); - //--- search for the "failed swing" signal - if(IS_PATTERN_USAGE(2) && RSI(idx) -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Signals of oscillator 'Relative Vigor Index' | -//| Type=SignalAdvanced | -//| Name=Relative Vigor Index | -//| ShortName=RVI | -//| Class=CSignalRVI | -//| Page=signal_rvi | -//| Parameter=PeriodRVI,int,10,Period of calculation | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CSignalRVI. | -//| Purpose: Class of generator of trade signals based on | -//| the 'Relative Vigor Index' oscillator. | -//| Is derived from the CExpertSignal class. | -//+------------------------------------------------------------------+ -class CSignalRVI : public CExpertSignal - { -protected: - CiRVI m_rvi; // object-oscillator - //--- adjusted parameters - int m_periodRVI; // the "period of calculation" parameter of the oscillator - //--- "weights" of market models (0-100) - int m_pattern_0; // model 0 "the oscillator has required direction" - int m_pattern_1; // model 1 "crossing of main and signal line" - -public: - CSignalRVI(void); - ~CSignalRVI(void); - //--- methods of setting adjustable parameters - void PeriodRVI(int value) { m_periodRVI=value; } - //--- methods of adjusting "weights" of market models - void Pattern_0(int value) { m_pattern_0=value; } - void Pattern_1(int value) { m_pattern_1=value; } - //--- method of verification of settings - virtual bool ValidationSettings(void); - //--- method of creating the indicator and timeseries - virtual bool InitIndicators(CIndicators *indicators); - //--- methods of checking if the market models are formed - virtual int LongCondition(void); - virtual int ShortCondition(void); - -protected: - //--- method of initialization of the oscillator - bool InitRVI(CIndicators *indicators); - //--- methods of getting data - double Main(int ind) { return(m_rvi.Main(ind)); } - double DiffMain(int ind) { return(Main(ind)-Main(ind+1)); } - double Signal(int ind) { return(m_rvi.Signal(ind)); } - double DiffSignal(int ind) { return(Signal(ind)-Signal(ind+1)); } - double DiffMainSignal(int ind) { return(Main(ind)-Signal(ind)); } - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CSignalRVI::CSignalRVI(void) : m_periodRVI(10), - m_pattern_0(60), - m_pattern_1(100) - { - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSignalRVI::~CSignalRVI(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CSignalRVI::ValidationSettings(void) - { -//--- validation settings of additional filters - if(!CExpertSignal::ValidationSettings()) - return(false); -//--- initial data checks - if(m_periodRVI<=0) - { - printf(__FUNCTION__+": the period of calculation of the RVI oscillator must be greater than 0"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create indicators. | -//+------------------------------------------------------------------+ -bool CSignalRVI::InitIndicators(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- initialization of indicators and timeseries of additional filters - if(!CExpertSignal::InitIndicators(indicators)) - return(false); -//--- create and initialize RVI oscillator - if(!InitRVI(indicators)) - return(false); -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialize RVI oscillators. | -//+------------------------------------------------------------------+ -bool CSignalRVI::InitRVI(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- add object to collection - if(!indicators.Add(GetPointer(m_rvi))) - { - printf(__FUNCTION__+": error adding object"); - return(false); - } -//--- initialize object - if(!m_rvi.Create(m_symbol.Name(),m_period,m_periodRVI)) - { - printf(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will grow. | -//+------------------------------------------------------------------+ -int CSignalRVI::LongCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- - if(DiffMain(idx)>0.0) - { - //--- the main line of the oscillator is directed upwards confirming the possibility of price growth - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; // "confirming" signal - //--- if the main line crosses the signal line upwards, this is a signal for buying - if(DiffMainSignal(idx)>0 && DiffMainSignal(idx+1)<0) - { - //--- the main line of the oscillator has crossed the signal line upwards (signal for buying) - if(IS_PATTERN_USAGE(1)) - result=m_pattern_1; // signal number 1 - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will fall. | -//+------------------------------------------------------------------+ -int CSignalRVI::ShortCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- - if(DiffMain(idx)<0.0) - { - //--- the main line of the oscillator is directed downwards confirming the possibility of falling of price - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; // "confirming" signal - //--- if the main line crosses the signal line from top downwards, this is a signal for selling - if(DiffMainSignal(idx)<0 && DiffMainSignal(idx+1)>0) - { - //--- the main line of the oscillator has crossed the signal line from top downwards (signal for selling) - if(IS_PATTERN_USAGE(1)) - result=m_pattern_1; // signal number 1 - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Signal/SignalSAR.mqh b/Include/Expert/Signal/SignalSAR.mqh deleted file mode 100644 index b0cbda9..0000000 --- a/Include/Expert/Signal/SignalSAR.mqh +++ /dev/null @@ -1,168 +0,0 @@ -//+------------------------------------------------------------------+ -//| SignalSAR.mqh | -//| Copyright 2009-2013, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Signals of indicator 'Parabolic SAR' | -//| Type=SignalAdvanced | -//| Name=Parabolic SAR | -//| ShortName=SAR | -//| Class=CSignalSAR | -//| Page=signal_sar | -//| Parameter=Step,double,0.02,Speed increment | -//| Parameter=Maximum,double,0.2,Maximum rate | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CSignalSAR. | -//| Purpose: Class of generator of trade signals based on | -//| the 'Parabolic SAR' indicator. | -//| Is derived from the CExpertSignal class. | -//+------------------------------------------------------------------+ -class CSignalSAR : public CExpertSignal - { -protected: - CiSAR m_sar; // object-indicator - //--- adjusted parameters - double m_step; // the "speed increment" parameter of the indicator - double m_maximum; // the "maximum rate" parameter of the indicator - //--- "weights" of market models (0-100) - int m_pattern_0; // model 0 "the parabolic is on the necessary side from the price" - int m_pattern_1; // model 1 "the parabolic has 'switched'" - -public: - CSignalSAR(void); - ~CSignalSAR(void); - //--- methods of setting adjustable parameters - void Step(double value) { m_step=value; } - void Maximum(double value) { m_maximum=value; } - //--- methods of adjusting "weights" of market models - void Pattern_0(int value) { m_pattern_0=value; } - void Pattern_1(int value) { m_pattern_1=value; } - //--- method of verification of settings - virtual bool ValidationSettings(void); - //--- method of creating the indicator and timeseries - virtual bool InitIndicators(CIndicators *indicators); - //--- methods of checking if the market models are formed - virtual int LongCondition(void); - virtual int ShortCondition(void); - -protected: - //--- method of initialization of the indicator - bool InitSAR(CIndicators *indicators); - //--- methods of getting data - double SAR(int ind) { return(m_sar.Main(ind)); } - double Close(int ind) { return(m_close.GetData(ind)); } - double DiffClose(int ind) { return(Close(ind)-SAR(ind)); } - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CSignalSAR::CSignalSAR(void) : m_step(0.02), - m_maximum(0.2), - m_pattern_0(40), - m_pattern_1(90) - { -//--- initialization of protected data - m_used_series=USE_SERIES_CLOSE; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSignalSAR::~CSignalSAR(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CSignalSAR::ValidationSettings(void) - { -//--- call of the method of the parent class - if(!CExpertSignal::ValidationSettings()) - return(false); -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create indicators. | -//+------------------------------------------------------------------+ -bool CSignalSAR::InitIndicators(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- initialization of indicators and timeseries of additional filters - if(!CExpertSignal::InitIndicators(indicators)) - return(false); -//--- create and initialize SAR indicator - if(!InitSAR(indicators)) - return(false); -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create SAR indicators. | -//+------------------------------------------------------------------+ -bool CSignalSAR::InitSAR(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- add object to collection - if(!indicators.Add(GetPointer(m_sar))) - { - printf(__FUNCTION__+": error adding object"); - return(false); - } -//--- initialize object - if(!m_sar.Create(m_symbol.Name(),m_period,m_step,m_maximum)) - { - printf(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will grow. | -//+------------------------------------------------------------------+ -int CSignalSAR::LongCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- if the indicator is above the price at the first analyzed bar, don't 'vote' buying - if(DiffClose(idx++)<0.0) - return(result); -//--- the indicator is below the price at the first analyzed bar (the indicator has no objections to buying) - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; -//--- if the indicator is above the price at the second analyzed bar, then there is a condition for buying - if(IS_PATTERN_USAGE(1) && DiffClose(idx)<0.0) - return(m_pattern_1); -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will fall. | -//+------------------------------------------------------------------+ -int CSignalSAR::ShortCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- if the indicator is below the price at the first analyzed bar, don't "vote" for selling - if(DiffClose(idx++)>0.0) - return(result); -//--- the indicator is above the price at the first analyzed bar (the indicator has no objections to selling) - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; -//--- if the indicator is below the price at the second analyzed bar, then there is a condition for selling - if(IS_PATTERN_USAGE(1) && DiffClose(idx)>0.0) - return(m_pattern_1); -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Signal/SignalStoch.mqh b/Include/Expert/Signal/SignalStoch.mqh deleted file mode 100644 index 51c1e1a..0000000 --- a/Include/Expert/Signal/SignalStoch.mqh +++ /dev/null @@ -1,426 +0,0 @@ -//+------------------------------------------------------------------+ -//| SignalStoch.mqh | -//| Copyright 2009-2013, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Signals of oscillator 'Stochastic' | -//| Type=SignalAdvanced | -//| Name=Stochastic | -//| ShortName=Stoch | -//| Class=CSignalStoch | -//| Page=signal_stochastic | -//| Parameter=PeriodK,int,8,K-period | -//| Parameter=PeriodD,int,3,D-period | -//| Parameter=PeriodSlow,int,3,Period of slowing | -//| Parameter=Applied,ENUM_STO_PRICE,STO_LOWHIGH,Prices to apply to | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CSignalStoch. | -//| Purpose: Class of generator of trade signals based on | -//| the 'Stochastic' oscillator. | -//| Is derived from the CExpertSignal class. | -//+------------------------------------------------------------------+ -class CSignalStoch : public CExpertSignal - { -protected: - CiStochastic m_stoch; // object-oscillator - CPriceSeries *m_app_price_high; // pointer to the object-timeseries for determining divergences directed downwards - CPriceSeries *m_app_price_low; // pointer to the object-timeseries for determining divergences directed upwards - //--- adjusted parameters - int m_periodK; // the "period %K" parameter of the oscillator - int m_periodD; // the "period %D" parameter of the oscillator - int m_period_slow; // the "period of slowing" parameter of the oscillator - ENUM_STO_PRICE m_applied; // the "apply to" parameter of the oscillator - //--- "weights" of market models (0-100) - int m_pattern_0; // model 0 "the oscillator has required direction" - int m_pattern_1; // model 1 "reverse of the oscillator to required direction" - int m_pattern_2; // model 2 "crossing of main and signal line" - int m_pattern_3; // model 3 "divergence of the oscillator and price" - int m_pattern_4; // model 4 "double divergence of the oscillator and price" - //--- variables - double m_extr_osc[10]; // array of values of extremums of the oscillator - double m_extr_pr[10]; // array of values of the corresponding extremums of price - int m_extr_pos[10]; // array of shifts of extremums (in bars) - uint m_extr_map; // resulting bit-map of ratio of extremums of the oscillator and the price - -public: - CSignalStoch(void); - ~CSignalStoch(void); - //--- methods of setting adjustable parameters - void PeriodK(int value) { m_periodK=value; } - void PeriodD(int value) { m_periodD=value; } - void PeriodSlow(int value) { m_period_slow=value; } - void Applied(ENUM_STO_PRICE value) { m_applied=value; } - //--- methods of adjusting "weights" of market models - void Pattern_0(int value) { m_pattern_0=value; } - void Pattern_1(int value) { m_pattern_1=value; } - void Pattern_2(int value) { m_pattern_2=value; } - void Pattern_3(int value) { m_pattern_3=value; } - void Pattern_4(int value) { m_pattern_4=value; } - //--- method of verification of settings - virtual bool ValidationSettings(void); - //--- method of creating the indicator and timeseries - virtual bool InitIndicators(CIndicators *indicators); - //--- methods of checking if the market models are formed - virtual int LongCondition(void); - virtual int ShortCondition(void); - -protected: - //--- method of initialization of the oscillator - bool InitStoch(CIndicators *indicators); - //--- methods of getting data - double Main(int ind) { return(m_stoch.Main(ind)); } - double DiffMain(int ind) { return(Main(ind)-Main(ind+1)); } - double Signal(int ind) { return(m_stoch.Signal(ind)); } - double DiffSignal(int ind) { return(Signal(ind)-Signal(ind+1)); } - double DiffMainSignal(int ind) { return(Main(ind)-Signal(ind)); } - int StateStoch(int ind); - bool ExtStateStoch(int ind); - bool CompareMaps(int map,int count,bool minimax=false,int start=0); - void DiverDebugPrint(); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CSignalStoch::CSignalStoch(void) : m_periodK(8), - m_periodD(3), - m_period_slow(3), - m_applied(STO_LOWHIGH), - m_pattern_0(30), - m_pattern_1(60), - m_pattern_2(50), - m_pattern_3(100), - m_pattern_4(90) - { -//--- initialization of protected data - m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSignalStoch::~CSignalStoch(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CSignalStoch::ValidationSettings(void) - { -//--- validation settings of additional filters - if(!CExpertSignal::ValidationSettings()) - return(false); -//--- initial data checks - if(m_periodK<=0) - { - printf(__FUNCTION__+": the period %K of the Stochastic oscillator must be greater than 0"); - return(false); - } - if(m_periodD<=0) - { - printf(__FUNCTION__+": the period %D of the Stochastic oscillator must be greater than 0"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create indicators. | -//+------------------------------------------------------------------+ -bool CSignalStoch::InitIndicators(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- initialization of indicators and timeseries of additional filters - if(!CExpertSignal::InitIndicators(indicators)) - return(false); -//--- create and initialize Stochastic oscillator - if(!InitStoch(indicators)) - return(false); - if(m_applied==STO_CLOSECLOSE) - { - //--- copying the Close timeseries - m_app_price_high=GetPointer(m_close); - //--- copying the Close timeseries - m_app_price_low=GetPointer(m_close); - } - else - { - //--- copying the High timeseries - m_app_price_high=GetPointer(m_high); - //--- copying the Low timeseries - m_app_price_low=GetPointer(m_low); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialize Stochastic oscillators. | -//+------------------------------------------------------------------+ -bool CSignalStoch::InitStoch(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- add object to collection - if(!indicators.Add(GetPointer(m_stoch))) - { - printf(__FUNCTION__+": error adding object"); - return(false); - } -//--- initialize object - if(!m_stoch.Create(m_symbol.Name(),m_period,m_periodK,m_periodD,m_period_slow,MODE_SMA,m_applied)) - { - printf(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Check of the oscillator state. | -//+------------------------------------------------------------------+ -int CSignalStoch::StateStoch(int ind) - { - int res=0; - double var; -//--- - for(int i=ind;;i++) - { - if(Main(i+1)==EMPTY_VALUE) - break; - var=DiffMain(i); - if(res>0) - { - if(var<0) - break; - res++; - continue; - } - if(res<0) - { - if(var>0) - break; - res--; - continue; - } - if(var>0) - res++; - if(var<0) - res--; - } -//--- - return(res); - } -//+------------------------------------------------------------------+ -//| Extended check of the oscillator state consists | -//| in forming a bit-map according to certain rules, | -//| which shows ratios of extremums of the oscillator and price. | -//+------------------------------------------------------------------+ -bool CSignalStoch::ExtStateStoch(int ind) - { -//--- operation of this method results in a bit-map of extremums -//--- practically, the bit-map of extremums is an "array" of 4-bit fields -//--- each "element of the array" definitely describes the ratio -//--- of current extremums of the oscillator and the price with previous ones -//--- purpose of bits of an element of the analyzed bit-map -//--- bit 3 - not used (always 0) -//--- bit 2 - is equal to 1 if the current extremum of the oscillator is "more extreme" than the previous one -//--- (a higher peak or a deeper valley), otherwise - 0 -//--- bit 1 - not used (always 0) -//--- bit 0 - is equal to 1 if the current extremum of price is "more extreme" than the previous one -//--- (a higher peak or a deeper valley), otherwise - 0 -//--- in addition to them, the following is formed: -//--- array of values of extremums of the oscillator, -//--- array of values of price extremums and -//--- array of "distances" between extremums of the oscillator (in bars) -//--- it should be noted that when using the results of the extended check of state, -//--- you should consider, which extremum of the oscillator (peak or valley) -//--- is the "reference point" (i.e. was detected first during the analysis) -//--- if a peak is detected first then even elements of all arrays -//--- will contain information about peaks, and odd elements will contain information about valleys -//--- if a valley is detected first, then respectively in reverse - int pos=ind,off,index; - uint map; // intermediate bit-map for one extremum -//--- - m_extr_map=0; - for(int i=0;i<10;i++) - { - off=StateStoch(pos); - if(off>0) - { - //--- minimum of the oscillator is detected - pos+=off; - m_extr_pos[i]=pos; - m_extr_osc[i]=Main(pos); - if(i>1) - { - m_extr_pr[i]=m_low.MinValue(pos-2,5,index); - //--- form the intermediate bit-map - map=0; - if(m_extr_pr[i-2]1) - { - m_extr_pr[i]=m_high.MaxValue(pos-2,5,index); - //--- form the intermediate bit-map - map=0; - if(m_extr_pr[i-2]>m_extr_pr[i]) - map+=1; // set bit 0 - if(m_extr_osc[i-2]>m_extr_osc[i]) - map+=4; // set bit 2 - //--- add the result - m_extr_map+=map<<(4*(i-2)); - } - else - m_extr_pr[i]=m_high.MaxValue(pos-1,4,index); - } - } -//--- - return(true); - } -//+------------------------------------------------------------------+ -//| Comparing the bit-map of extremums with pattern. | -//+------------------------------------------------------------------+ -bool CSignalStoch::CompareMaps(int map,int count,bool minimax=false,int start=0) - { - int step =(minimax)?4:8; - int total=step*(start+count); -//--- check input parameters for a possible going out of range of the bit-map - if(total>32) - return(false); -//--- bit-map of the patter is an "array" of 4-bit fields -//--- each "element of the array" definitely describes the desired ratio -//--- of current extremums of the oscillator and the price with previous ones -//--- purpose of bits of an elements of the pattern of the bit-map pattern -//--- bit 3 - is equal to if the ratio of extremums of the oscillator is insignificant for us -//--- is equal to 0 if we want to "find" the ratio of extremums of the oscillator determined by the value of bit 2 -//--- bit 2 - is equal to 1 if we want to "discover" the situation when the current extremum of the "oscillator" is "more extreme" than the previous one -//--- (current peak is higher or current valley is deeper) -//--- is equal to 0 if we want to "discover" the situation when the current extremum of the oscillator is "less extreme" than the previous one -//--- (current peak is lower or current valley is less deep) -//--- bit 1 - is equal to 1 if the ratio of extremums is insignificant for us -//--- it is equal to 0 if we want to "find" the ratio of price extremums determined by the value of bit 0 -//--- bit 0 - is equal to 1 if we want to "discover" the situation when the current price extremum is "more extreme" than the previous one -//--- (current peak is higher or current valley is deeper) -//--- it is equal to 0 if we want to "discover" the situation when the current price extremum is "less extreme" than the previous one -//--- (current peak is lower or current valley is less deep) - uint inp_map,check_map; - int i,j; -//--- loop by extremums (4 minimums and 4 maximums) -//--- price and the oscillator are checked separately (thus, there are 16 checks) - for(i=step*start,j=0;i>j)&3; - //--- if the higher-order bit=1, then any ratio is suitable for us - if(inp_map<2) - { - //--- "take" two bits of the corresponding extremum of the price (higher-order bit is always 0) - check_map=(m_extr_map>>i)&3; - if(inp_map!=check_map) - return(false); - } - //--- "take" two bits - pattern of the corresponding oscillator extremum - inp_map=(map>>(j+2))&3; - //--- if the higher-order bit=1, then any ratio is suitable for us - if(inp_map>=2) - continue; - //--- "take" two bits of the corresponding oscillator extremum (higher-order bit is always 0) - check_map=(m_extr_map>>(i+2))&3; - if(inp_map!=check_map) - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will grow. | -//+------------------------------------------------------------------+ -int CSignalStoch::LongCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- check direction of the main line - if(DiffMain(idx)>0.0) - { - //--- the main line is directed upwards, and it confirms the possibility of price growth - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; // "confirming" signal number 0 - //--- if the model 1 is used, look for a reverse of the main line - if(IS_PATTERN_USAGE(1) && DiffMain(idx+1)<0.0) - result=m_pattern_1; // signal number 1 - //--- if the model 2 is used, look for an intersection of the main and signal line - if(IS_PATTERN_USAGE(2) && DiffMainSignal(idx)>0.0 && DiffMainSignal(idx+1)<0.0) - result=m_pattern_2; // signal number 2 - //--- if the models 3 or 4 are used, look for divergences - if((IS_PATTERN_USAGE(3) || IS_PATTERN_USAGE(4))) - { - //--- perform the extended analysis of the oscillator state - ExtStateStoch(idx); - //--- if the model 3 is used, look for the "divergence" signal - if(IS_PATTERN_USAGE(3) && CompareMaps(1,1)) // 0000 0001b - result=m_pattern_3; // signal number 3 - //--- if the model 4 is used, look for the "double divergence" signal - if(IS_PATTERN_USAGE(4) && CompareMaps(0x11,2)) // 0001 0001b - return(m_pattern_4); // signal number 4 - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will fall. | -//+------------------------------------------------------------------+ -int CSignalStoch::ShortCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- check direction of the main line - if(DiffMain(idx)<0.0) - { - //--- main line is directed downwards, confirming a possibility of falling of price - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; // "confirming" signal number 0 - //--- if the model 1 is used, look for a reverse of the main line - if(IS_PATTERN_USAGE(1) && DiffMain(idx+1)>0.0) - result=m_pattern_1; // signal number 1 - //--- if the model 2 is used, look for an intersection of the main and signal line - if(IS_PATTERN_USAGE(2) && DiffMainSignal(idx)<0.0 && DiffMainSignal(idx+1)>0.0) - result=m_pattern_2; // signal number 2 - //--- if the models 3 or 4 are used, look for divergences - if((IS_PATTERN_USAGE(3) || IS_PATTERN_USAGE(4))) - { - //--- perform the extended analysis of the oscillator state - ExtStateStoch(idx); - //--- if the model 3 is used, look for the "divergence" signal - if(IS_PATTERN_USAGE(3) && CompareMaps(1,1)) // 0000 0001b - result=m_pattern_3; // signal number 3 - //--- if the model 4 is used, look for the "double divergence" signal - if(IS_PATTERN_USAGE(4) && CompareMaps(0x11,2)) // 0001 0001b - return(m_pattern_4); // signal number 4 - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Signal/SignalTEMA.mqh b/Include/Expert/Signal/SignalTEMA.mqh deleted file mode 100644 index 0c47d3b..0000000 --- a/Include/Expert/Signal/SignalTEMA.mqh +++ /dev/null @@ -1,257 +0,0 @@ -//+------------------------------------------------------------------+ -//| SignalTEMA.mqh | -//| Copyright 2009-2013, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Signals of indicator 'Triple Exponential Moving Average' | -//| Type=SignalAdvanced | -//| Name=Triple Exponential Moving Average | -//| ShortName=TEMA | -//| Class=CSignalTEMA | -//| Page=signal_tema | -//| Parameter=PeriodMA,int,12,Period of averaging | -//| Parameter=Shift,int,0,Time shift | -//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CSignalTEMA. | -//| Purpose: Class of generator of trade signals based on | -//| the 'Triple Exponential Moving Average' indicator. | -//| Is derived from the CExpertSignal class. | -//+------------------------------------------------------------------+ -class CSignalTEMA : public CExpertSignal - { -protected: - CiTEMA m_ma; // object-indicator - //--- adjusted parameters - int m_ma_period; // the "period of averaging" parameter of the indicator - int m_ma_shift; // the "time shift" parameter of the indicator - ENUM_APPLIED_PRICE m_ma_applied; // the "object of averaging" parameter" of the indicator - //--- "weights" of market models (0-100) - int m_pattern_0; // model 0 "price is on the necessary side from the indicator" - int m_pattern_1; // model 1 "price crossed the indicator with opposite direction" - int m_pattern_2; // model 2 "price crossed the indicator with the same direction" - int m_pattern_3; // model 3 "piercing" - -public: - CSignalTEMA(void); - ~CSignalTEMA(void); - //--- methods of setting adjustable parameters - void PeriodMA(int value) { m_ma_period=value; } - void Shift(int value) { m_ma_shift=value; } - void Applied(ENUM_APPLIED_PRICE value) { m_ma_applied=value; } - //--- methods of adjusting "weights" of market models - void Pattern_0(int value) { m_pattern_0=value; } - void Pattern_1(int value) { m_pattern_1=value; } - void Pattern_2(int value) { m_pattern_2=value; } - void Pattern_3(int value) { m_pattern_3=value; } - //--- method of verification of settings - virtual bool ValidationSettings(void); - //--- method of creating the indicator and timeseries - virtual bool InitIndicators(CIndicators *indicators); - //--- methods of checking if the market models are formed - virtual int LongCondition(void); - virtual int ShortCondition(void); - -protected: - //--- method of initialization of the indicator - bool InitMA(CIndicators *indicators); - //--- methods of getting data - double MA(int ind) { return(m_ma.Main(ind)); } - double DiffMA(int ind) { return(MA(ind)-MA(ind+1)); } - double DiffOpenMA(int ind) { return(Open(ind)-MA(ind)); } - double DiffHighMA(int ind) { return(High(ind)-MA(ind)); } - double DiffLowMA(int ind) { return(Low(ind)-MA(ind)); } - double DiffCloseMA(int ind) { return(Close(ind)-MA(ind)); } - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CSignalTEMA::CSignalTEMA(void) : m_ma_period(12), - m_ma_shift(0), - m_ma_applied(PRICE_CLOSE), - m_pattern_0(50), - m_pattern_1(10), - m_pattern_2(60), - m_pattern_3(60) - { -//--- initialization of protected data - m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSignalTEMA::~CSignalTEMA(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CSignalTEMA::ValidationSettings(void) - { -//--- call of the method of the parent class - if(!CExpertSignal::ValidationSettings()) - return(false); -//--- initial data checks - if(m_ma_period<=0) - { - printf(__FUNCTION__+": period MA must be greater than 0"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create indicators. | -//+------------------------------------------------------------------+ -bool CSignalTEMA::InitIndicators(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- initialization of indicators and timeseries of additional filters - if(!CExpertSignal::InitIndicators(indicators)) - return(false); -//--- create and initialize TEMA indicator - if(!InitMA(indicators)) - return(false); -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create MA indicators. | -//+------------------------------------------------------------------+ -bool CSignalTEMA::InitMA(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- add object to collection - if(!indicators.Add(GetPointer(m_ma))) - { - printf(__FUNCTION__+": error adding object"); - return(false); - } -//--- initialize object - if(!m_ma.Create(m_symbol.Name(),m_period,m_ma_period,m_ma_shift,m_ma_applied)) - { - printf(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will grow. | -//+------------------------------------------------------------------+ -int CSignalTEMA::LongCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- analyze positional relationship of the close price and the indicator at the first analyzed bar - if(DiffCloseMA(idx)<0.0) - { - //--- the close price is below the indicator - if(IS_PATTERN_USAGE(1) && DiffOpenMA(idx)>0.0 && DiffMA(idx)>0.0) - { - //--- the open price is above the indicator (i.e. there was an intersection), but the indicator is directed upwards - result=m_pattern_1; - //--- consider that this is an unformed "piercing" and suggest to enter the market at the current price - m_base_price=0.0; - } - } - else - { - //--- the close price is above the indicator (the indicator has no objections to buying) - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; - //--- if the indicator is directed upwards - if(DiffMA(idx)>0.0) - { - if(DiffOpenMA(idx)<0.0) - { - //--- if the model 2 is used - if(IS_PATTERN_USAGE(2)) - { - //--- the open price is below the indicator (i.e. there was an intersection) - result=m_pattern_2; - //--- suggest to enter the market at the "roll back" - m_base_price=m_symbol.NormalizePrice(MA(idx)); - } - } - else - { - //--- if the model 3 is used and the open price is above the indicator - if(IS_PATTERN_USAGE(3) && DiffLowMA(idx)<0.0) - { - //--- the low price is below the indicator - result=m_pattern_3; - //--- consider that this is a formed "piercing" and suggest to enter the market at the current price - m_base_price=0.0; - } - } - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will fall. | -//+------------------------------------------------------------------+ -int CSignalTEMA::ShortCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- analyze positional relationship of the close price and the indicator at the first analyzed bar - if(DiffCloseMA(idx)>0.0) - { - //--- the close price is above the indicator - if(IS_PATTERN_USAGE(1) && DiffOpenMA(idx)<0.0 && DiffMA(idx)<0.0) - { - //--- the open price is below the indicator (i.e. there was an intersection), but the indicator is directed downwards - result=m_pattern_1; - //--- consider that this is an unformed "piercing" and suggest to enter the market at the current price - m_base_price=0.0; - } - } - else - { - //--- the close price is below the indicator (the indicator has no objections to buying) - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; - //--- the indicator is directed downwards - if(DiffMA(idx)<0.0) - { - if(DiffOpenMA(idx)>0.0) - { - //--- if the model 2 is used - if(IS_PATTERN_USAGE(2)) - { - //--- the open price is above the indicator (i.e. there was an intersection) - result=m_pattern_2; - //--- suggest to enter the market at the "roll back" - m_base_price=m_symbol.NormalizePrice(MA(idx)); - } - } - else - { - //--- if the model 3 is used and the open price is below the indicator - if(IS_PATTERN_USAGE(3) && DiffHighMA(idx)>0.0) - { - //--- the high price is above the indicator - result=m_pattern_3; - //--- consider that this is a formed "piercing" and suggest to enter the market at the current price - m_base_price=0.0; - } - } - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Signal/SignalTRIX.mqh b/Include/Expert/Signal/SignalTRIX.mqh deleted file mode 100644 index 4a5391b..0000000 --- a/Include/Expert/Signal/SignalTRIX.mqh +++ /dev/null @@ -1,395 +0,0 @@ -//+------------------------------------------------------------------+ -//| SignalTRIX.mqh | -//| Copyright 2009-2013, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Signals of oscillator 'Triple Exponential Average' | -//| Type=SignalAdvanced | -//| Name=Triple Exponential Average | -//| ShortName=TriX | -//| Class=CSignalTriX | -//| Page=signal_trix | -//| Parameter=PeriodTriX,int,14,Period of calculation | -//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CSignalTriX. | -//| Purpose: Class of generator of trade signals based on | -//| the 'Triple Exponential Average' oscillator. | -//| Is derived from the CExpertSignal class. | -//+------------------------------------------------------------------+ -class CSignalTriX : public CExpertSignal - { -protected: - CiTriX m_trix; // object-oscillator - //--- adjusted parameters - int m_period_trix; // the "period of calculation" parameter of the oscillator - ENUM_APPLIED_PRICE m_applied; // the "price series" parameter of the oscillator - //--- "weights" of market models (0-100) - int m_pattern_0; // model 0 "the oscillator has required direction" - int m_pattern_1; // model 1 "reverse of the oscillator to required direction" - int m_pattern_2; // model 2 "crossing of main line an the zero level" - int m_pattern_3; // model 3 "divergence of the oscillator and price" - //--- variables - double m_extr_osc[10]; // array of values of extremums of the oscillator - double m_extr_pr[10]; // array of values of the corresponding extremums of price - int m_extr_pos[10]; // array of shifts of extremums (in bars) - uint m_extr_map; // resulting bit-map of ratio of extremums of the oscillator and the price - -public: - CSignalTriX(void); - ~CSignalTriX(void); - //--- methods of setting adjustable parameters - void PeriodTriX(int value) { m_period_trix=value; } - void Applied(ENUM_APPLIED_PRICE value) { m_applied=value; } - //--- methods of adjusting "weights" of market models - void Pattern_0(int value) { m_pattern_0=value; } - void Pattern_1(int value) { m_pattern_1=value; } - void Pattern_2(int value) { m_pattern_2=value; } - void Pattern_3(int value) { m_pattern_3=value; } - //--- method of verification of settings - virtual bool ValidationSettings(void); - //--- method of creating the indicator and timeseries - virtual bool InitIndicators(CIndicators *indicators); - //--- methods of checking if the market models are formed - virtual int LongCondition(void); - virtual int ShortCondition(void); - -protected: - //--- method of initialization of the oscillator - bool InitTriX(CIndicators *indicators); - //--- methods of getting data - double TriX(int ind) { return(m_trix.Main(ind)); } - double DiffTriX(int ind) { return(TriX(ind)-TriX(ind+1)); } - int State(int ind); - bool ExtState(int ind); - bool CompareMaps(int map,int count,bool minimax=false,int start=0); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CSignalTriX::CSignalTriX(void) : m_period_trix(12), - m_applied(PRICE_CLOSE), - m_pattern_0(20), - m_pattern_1(80), - m_pattern_2(100), - m_pattern_3(70) - { -//--- initialization of protected data - m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSignalTriX::~CSignalTriX(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CSignalTriX::ValidationSettings(void) - { - if(!CExpertSignal::ValidationSettings()) - return(false); -//--- - if(m_period_trix<=0) - { - printf(__FUNCTION__+": period must be greater than 0"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create indicators. | -//+------------------------------------------------------------------+ -bool CSignalTriX::InitIndicators(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- initialization of indicators and timeseries of additional filters - if(!CExpertSignal::InitIndicators(indicators)) - return(false); -//--- create and initialize TriX oscilator - if(!InitTriX(indicators)) - return(false); -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialize TriX oscillators. | -//+------------------------------------------------------------------+ -bool CSignalTriX::InitTriX(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- add object to collection - if(!indicators.Add(GetPointer(m_trix))) - { - printf(__FUNCTION__+": error adding object"); - return(false); - } -//--- initialize object - if(!m_trix.Create(m_symbol.Name(),m_period,m_period_trix,m_applied)) - { - printf(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Check of the oscillator state. | -//+------------------------------------------------------------------+ -int CSignalTriX::State(int ind) - { - int res=0; - double var; -//--- - for(int i=ind;;i++) - { - if(TriX(i+1)==EMPTY_VALUE) - break; - var=DiffTriX(i); - if(res>0) - { - if(var<0) - break; - res++; - continue; - } - if(res<0) - { - if(var>0) - break; - res--; - continue; - } - if(var>0) - res++; - if(var<0) - res--; - } -//--- - return(res); - } -//+------------------------------------------------------------------+ -//| Extended check of the oscillator state consists | -//| in forming a bit-map according to certain rules, | -//| which shows ratios of extremums of the oscillator and price. | -//+------------------------------------------------------------------+ -bool CSignalTriX::ExtState(int ind) - { -//--- operation of this method results in a bit-map of extremums -//--- practically, the bit-map of extremums is an "array" of 4-bit fields -//--- each "element of the array" definitely describes the ratio -//--- of current extremums of the oscillator and the price with previous ones -//--- purpose of bits of an element of the analyzed bit-map -//--- bit 3 - not used (always 0) -//--- bit 2 - is equal to 1 if the current extremum of the oscillator is "more extreme" than the previous one -//--- (a higher peak or a deeper valley), otherwise - 0 -//--- bit 1 - not used (always 0) -//--- bit 0 - is equal to 1 if the current extremum of price is "more extreme" than the previous one -//--- (a higher peak or a deeper valley), otherwise - 0 -//--- in addition to them, the following is formed: -//--- array of values of extremums of the oscillator, -//--- array of values of price extremums and -//--- array of "distances" between extremums of the oscillator (in bars) -//--- it should be noted that when using the results of the extended check of state, -//--- you should consider, which extremum of the oscillator (peak or valley) -//--- is the "reference point" (i.e. was detected first during the analysis) -//--- if a peak is detected first then even elements of all arrays -//--- will contain information about peaks, and odd elements will contain information about valleys -//--- if a valley is detected first, then respectively in reverse - int pos=ind,off,index; - uint map; // intermediate bit-map for one extremum -//--- - m_extr_map=0; - for(int i=0;i<10;i++) - { - off=State(pos); - if(off>0) - { - //--- minimum of the oscillator is detected - pos+=off; - m_extr_pos[i]=pos; - m_extr_osc[i]=TriX(pos); - if(i>1) - { - m_extr_pr[i]=m_low.MinValue(pos-2,5,index); - //--- form the intermediate bit-map - map=0; - if(m_extr_pr[i-2]1) - { - m_extr_pr[i]=m_high.MaxValue(pos-2,5,index); - //--- form the intermediate bit-map - map=0; - if(m_extr_pr[i-2]>m_extr_pr[i]) - map+=1; // set bit 0 - if(m_extr_osc[i-2]>m_extr_osc[i]) - map+=4; // set bit 2 - //--- add the result - m_extr_map+=map<<(4*(i-2)); - } - else - m_extr_pr[i]=m_high.MaxValue(pos-1,4,index); - } - } -//--- - return(true); - } -//+------------------------------------------------------------------+ -//| Comparing the bit-map of extremums with pattern. | -//+------------------------------------------------------------------+ -bool CSignalTriX::CompareMaps(int map,int count,bool minimax,int start) - { - int step =(minimax)?4:8; - int total=step*(start+count); -//--- check input parameters for a possible going out of range of the bit-map - if(total>32) - return(false); -//--- bit-map of the patter is an "array" of 4-bit fields -//--- each "element of the array" definitely describes the desired ratio -//--- of current extremums of the oscillator and the price with previous ones -//--- purpose of bits of an elements of the pattern of the bit-map pattern -//--- bit 3 - is equal to if the ratio of extremums of the oscillator is insignificant for us -//--- is equal to 0 if we want to "find" the ratio of extremums of the oscillator determined by the value of bit 2 -//--- bit 2 - is equal to 1 if we want to "discover" the situation when the current extremum of the "oscillator" is "more extreme" than the previous one -//--- (current peak is higher or current valley is deeper) -//--- is equal to 0 if we want to "discover" the situation when the current extremum of the oscillator is "less extreme" than the previous one -//--- (current peak is lower or current valley is less deep) -//--- bit 1 - is equal to 1 if the ratio of extremums is insignificant for us -//--- it is equal to 0 if we want to "find" the ratio of price extremums determined by the value of bit 0 -//--- bit 0 - is equal to 1 if we want to "discover" the situation when the current price extremum is "more extreme" than the previous one -//--- (current peak is higher or current valley is deeper) -//--- it is equal to 0 if we want to "discover" the situation when the current price extremum is "less extreme" than the previous one -//--- (current peak is lower or current valley is less deep) - uint inp_map,check_map; - int i,j; -//--- loop by extremums (4 minimums and 4 maximums) -//--- price and the oscillator are checked separately (thus, there are 16 checks) - for(i=step*start,j=0;i>j)&3; - //--- if the higher-order bit=1, then any ratio is suitable for us - if(inp_map<2) - { - //--- "take" two bits of the corresponding extremum of the price (higher-order bit is always 0) - check_map=(m_extr_map>>i)&3; - if(inp_map!=check_map) - return(false); - } - //--- "take" two bits - pattern of the corresponding oscillator extremum - inp_map=(map>>(j+2))&3; - //--- if the higher-order bit=1, then any ratio is suitable for us - if(inp_map>=2) - continue; - //--- "take" two bits of the corresponding oscillator extremum (higher-order bit is always 0) - check_map=(m_extr_map>>(i+2))&3; - if(inp_map!=check_map) - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will grow. | -//+------------------------------------------------------------------+ -int CSignalTriX::LongCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- check direction of the oscillator - if(DiffTriX(idx)>0.0) - { - //--- the oscillator is directed upwards confirming the possibility of price growth - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; // "confirming" signal number 0 - //--- if the model 1 is used, search for a reverse of the oscillator - if(IS_PATTERN_USAGE(1) && DiffTriX(idx)>0.0 && DiffTriX(idx+1)<0.0) - result=m_pattern_1; // signal number 1 - //--- if the model 2 is used, search for an intersection of the oscillator line and the zero level - if(IS_PATTERN_USAGE(2) && TriX(idx)>0.0 && TriX(idx+1)<0.0) - result=m_pattern_2; // signal number 2 - //--- if the model 3 is used, and the oscillator turned up below the zero level, search for the divergence - if(IS_PATTERN_USAGE(3) && TriX(idx)<0.0) - { - //--- perform the extended analysis of the oscillator state - ExtState(idx); - //--- search for the "divergence" signal - if(CompareMaps(1,1)) // 0000 0001b - { - if(m_extr_osc[0]<0.0 && m_extr_osc[1]<0.0 && m_extr_osc[2]<0.0) - { - //--- both valleys of the oscillator are below zero and the peak between them hasn't raised above zero - result=m_pattern_3; // signal number 3 - } - } - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will fall. | -//+------------------------------------------------------------------+ -int CSignalTriX::ShortCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- check direction of the main line - if(DiffTriX(idx)<0.0) - { - //--- main line is directed downwards, confirming a possibility of falling of price - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; // "confirming" signal number 0 - //--- if the model 1 is used, search for a reverse of the main line - if(IS_PATTERN_USAGE(1) && DiffTriX(idx)<0.0 && DiffTriX(idx+1)>0.0) - result=m_pattern_1; // signal number 1 - //--- if the model 2 is used, search for an intersection of the main line and the zero level - if(IS_PATTERN_USAGE(2) && TriX(idx)<0.0 && TriX(idx+1)>0.0) - result=m_pattern_2; // signal number 2 - //--- if the model 3 is used and the main line turned down above the zero level, search for the divergence - if(IS_PATTERN_USAGE(3) && TriX(idx)>0.0) - { - //--- perform the extended analysis of the oscillator state - ExtState(idx); - //--- search for the "divergence" signal - if(CompareMaps(1,1)) // 0000 0001b - { - if(m_extr_osc[0]>0.0 && m_extr_osc[1]>0.0 && m_extr_osc[2]>0.0) - { - //--- both peaks of the oscillator are above zero and the valley between them hasn't fallen below zero - result=m_pattern_3; // signal number 3 - } - } - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Signal/SignalWPR.mqh b/Include/Expert/Signal/SignalWPR.mqh deleted file mode 100644 index 170aca9..0000000 --- a/Include/Expert/Signal/SignalWPR.mqh +++ /dev/null @@ -1,371 +0,0 @@ -//+------------------------------------------------------------------+ -//| SignalWPR.mqh | -//| Copyright 2009-2013, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Signals of oscillator 'Williams Percent Range' | -//| Type=SignalAdvanced | -//| Name=Williams Percent Range | -//| ShortName=WPR | -//| Class=CSignalWPR | -//| Page=signal_wpr | -//| Parameter=PeriodWPR,int,8,Period of calculation | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CSignalWPR. | -//| Purpose: Class of generator of trade signals based on | -//| the 'Williams Percent Range' oscillator. | -//| Is derived from the CExpertSignal class. | -//+------------------------------------------------------------------+ -class CSignalWPR : public CExpertSignal - { -protected: - CiWPR m_wpr; // object-oscillator - //--- adjusted parameters - int m_period_wpr; // the "period of calculation" parameter of the oscillator - //--- "weights" of market models (0-100) - int m_pattern_0; // model 0 "the oscillator has required direction" - int m_pattern_1; // model 1 "reverse behind the level of overbuying/overselling" - int m_pattern_2; // model 2 "divergence of the oscillator and price" - //--- variables - double m_extr_osc[10]; // array of values of extremums of the oscillator - double m_extr_pr[10]; // array of values of the corresponding extremums of price - int m_extr_pos[10]; // array of shifts of extremums (in bars) - uint m_extr_map; // resulting bit-map of ratio of extremums of the oscillator and the price - -public: - CSignalWPR(void); - ~CSignalWPR(void); - //--- methods of setting adjustable parameters - void PeriodWPR(int value) { m_period_wpr=value; } - //--- methods of adjusting "weights" of market models - void Pattern_0(int value) { m_pattern_0=value; } - void Pattern_1(int value) { m_pattern_1=value; } - void Pattern_2(int value) { m_pattern_2=value; } - //--- method of verification of settings - virtual bool ValidationSettings(void); - //--- method of creating the indicator and timeseries - virtual bool InitIndicators(CIndicators *indicators); - //--- methods of checking if the market models are formed - virtual int LongCondition(void); - virtual int ShortCondition(void); - -protected: - //--- method of initialization of the oscillator - bool InitWPR(CIndicators *indicators); - //--- methods of getting data - // double WPR(int ind); - double WPR(int ind) { return(m_wpr.Main(ind)); } - double Diff(int ind) { return(WPR(ind)-WPR(ind+1)); } - int State(int ind); - bool ExtState(int ind); - bool CompareMaps(int map,int count,bool minimax=false,int start=0); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CSignalWPR::CSignalWPR(void) : m_period_wpr(14), - m_pattern_0(80), - m_pattern_1(70), - m_pattern_2(90) - { -//--- initialization of protected data - m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSignalWPR::~CSignalWPR(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CSignalWPR::ValidationSettings(void) - { -//--- validation settings of additional filters - if(!CExpertSignal::ValidationSettings()) - return(false); -//--- initial data checks - if(m_period_wpr<=0) - { - printf(__FUNCTION__+": period of the WPR oscillator must be greater than 0"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Create indicators. | -//+------------------------------------------------------------------+ -bool CSignalWPR::InitIndicators(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- initialization of indicators and timeseries of additional filters - if(!CExpertSignal::InitIndicators(indicators)) - return(false); -//--- create and initialize WPR oscillator - if(!InitWPR(indicators)) - return(false); -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Initialize WPR oscillators. | -//+------------------------------------------------------------------+ -bool CSignalWPR::InitWPR(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) return(false); -//--- add object to collection - if(!indicators.Add(GetPointer(m_wpr))) - { - printf(__FUNCTION__+": error adding object"); - return(false); - } -//--- initialize object - if(!m_wpr.Create(m_symbol.Name(),m_period,m_period_wpr)) - { - printf(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Check of the oscillator state. | -//+------------------------------------------------------------------+ -int CSignalWPR::State(int ind) - { - int res=0; - double var; -//--- - for(int i=ind;;i++) - { - if(WPR(i+1)==EMPTY_VALUE) - break; - var=Diff(i); - if(res>0) - { - if(var<0) - break; - res++; - continue; - } - if(res<0) - { - if(var>0) - break; - res--; - continue; - } - if(var>0) - res++; - if(var<0) - res--; - } -//--- - return(res); - } -//+------------------------------------------------------------------+ -//| Extended check of the oscillator state consists | -//| in forming a bit-map according to certain rules, | -//| which shows ratios of extremums of the oscillator and price. | -//+------------------------------------------------------------------+ -bool CSignalWPR::ExtState(int ind) - { -//--- operation of this method results in a bit-map of extremums -//--- practically, the bit-map of extremums is an "array" of 4-bit fields -//--- each "element of the array" definitely describes the ratio -//--- of current extremums of the oscillator and the price with previous ones -//--- purpose of bits of an element of the analyzed bit-map -//--- bit 3 - not used (always 0) -//--- bit 2 - is equal to 1 if the current extremum of the oscillator is "more extreme" than the previous one -//--- (a higher peak or a deeper valley), otherwise - 0 -//--- bit 1 - not used (always 0) -//--- bit 0 - is equal to 1 if the current extremum of price is "more extreme" than the previous one -//--- (a higher peak or a deeper valley), otherwise - 0 -//--- in addition to them, the following is formed: -//--- array of values of extremums of the oscillator, -//--- array of values of price extremums and -//--- array of "distances" between extremums of the oscillator (in bars) -//--- it should be noted that when using the results of the extended check of state, -//--- you should consider, which extremum of the oscillator (peak or valley) -//--- is the "reference point" (i.e. was detected first during the analysis) -//--- if a peak is detected first then even elements of all arrays -//--- will contain information about peaks, and odd elements will contain information about valleys -//--- if a valley is detected first, then respectively in reverse - int pos=ind,off,index; - uint map; // intermediate bit-map for one extremum -//--- - m_extr_map=0; - for(int i=0;i<10;i++) - { - off=State(pos); - if(off>0) - { - //--- minimum of the oscillator is detected - pos+=off; - m_extr_pos[i]=pos; - m_extr_osc[i]=WPR(pos); - if(i>1) - { - m_extr_pr[i]=m_low.MinValue(pos-2,5,index); - //--- form the intermediate bit-map - map=0; - if(m_extr_pr[i-2]1) - { - m_extr_pr[i]=m_high.MaxValue(pos-2,5,index); - //--- form the intermediate bit-map - map=0; - if(m_extr_pr[i-2]>m_extr_pr[i]) - map+=1; // set bit 0 - if(m_extr_osc[i-2]>m_extr_osc[i]) - map+=4; // set bit 2 - //--- add the result - m_extr_map+=map<<(4*(i-2)); - } - else - m_extr_pr[i]=m_high.MaxValue(pos-1,4,index); - } - } -//--- - return(true); - } -//+------------------------------------------------------------------+ -//| Comparing the bit-map of extremums with pattern. | -//+------------------------------------------------------------------+ -bool CSignalWPR::CompareMaps(int map,int count,bool minimax,int start) - { - int step =(minimax)?4:8; - int total=step*(start+count); -//--- check input parameters for a possible going out of range of the bit-map - if(total>32) - return(false); -//--- bit-map of the patter is an "array" of 4-bit fields -//--- each "element of the array" definitely describes the desired ratio -//--- of current extremums of the oscillator and the price with previous ones -//--- purpose of bits of an elements of the pattern of the bit-map pattern -//--- bit 3 - is equal to if the ratio of extremums of the oscillator is insignificant for us -//--- is equal to 0 if we want to "find" the ratio of extremums of the oscillator determined by the value of bit 2 -//--- bit 2 - is equal to 1 if we want to "discover" the situation when the current extremum of the "oscillator" is "more extreme" than the previous one -//--- (current peak is higher or current valley is deeper) -//--- is equal to 0 if we want to "discover" the situation when the current extremum of the oscillator is "less extreme" than the previous one -//--- (current peak is lower or current valley is less deep) -//--- bit 1 - is equal to 1 if the ratio of extremums is insignificant for us -//--- it is equal to 0 if we want to "find" the ratio of price extremums determined by the value of bit 0 -//--- bit 0 - is equal to 1 if we want to "discover" the situation when the current price extremum is "more extreme" than the previous one -//--- (current peak is higher or current valley is deeper) -//--- it is equal to 0 if we want to "discover" the situation when the current price extremum is "less extreme" than the previous one -//--- (current peak is lower or current valley is less deep) - uint inp_map,check_map; - int i,j; -//--- loop by extremums (4 minimums and 4 maximums) -//--- price and the oscillator are checked separately (thus, there are 16 checks) - for(i=step*start,j=0;i>i)&3; - //--- if the higher-order bit=1, then any ratio is suitable for us - if(inp_map<2) - { - //--- "take" two bits of the corresponding extremum of the oscillator (higher-order bit is always 0) - check_map=(m_extr_map>>j)&3; - if(inp_map!=check_map) - return(false); - } - //--- "take" two bits - pattern of the corresponding price extremum - inp_map=(map>>(i+2))&3; - //--- if the higher-order bit=1, then any ratio is suitable for us - if(inp_map>=2) - continue; - //--- "take" two bits of the corresponding price extremum (higher-order bit is always 0) - check_map=(m_extr_map>>(j+2))&3; - if(inp_map!=check_map) - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will grow. | -//+------------------------------------------------------------------+ -int CSignalWPR::LongCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- - if(Diff(idx)>0.0) - { - //--- the oscillator is directed upwards confirming the possibility of price growth - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; // "confirming" signal number 0 - //--- if the model 1 is used, search for a reverse of the oscillator upwards behind the level of overselling - if(IS_PATTERN_USAGE(1) && Diff(idx+1)<0.0 && WPR(idx+1)>-80.0) - result=m_pattern_1; // signal number 1 - //--- if the model 2 or 3 is used, search for the divergences - if(IS_PATTERN_USAGE(2)) - { - //--- perform the extended analysis of the oscillator state - ExtState(idx); - //--- if the model 2 is used, search for the "divergence" signal - if(CompareMaps(1,1)) // 00000001b - result=m_pattern_2; // signal number 2 - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ -//| "Voting" that price will fall. | -//+------------------------------------------------------------------+ -int CSignalWPR::ShortCondition(void) - { - int result=0; - int idx =StartIndex(); -//--- - if(Diff(idx)<0.0) - { - //--- the oscillator is directed downwards confirming the possibility of falling of price - if(IS_PATTERN_USAGE(0)) - result=m_pattern_0; // "confirming" signal number 0 - //--- if the model 1 is used, search for a reverse of the oscillator downwards behind the level of overbuying - if(IS_PATTERN_USAGE(1) && Diff(idx+1)>0.0 && WPR(idx+1)<-20.0) - result=m_pattern_1; // signal number 1 - //--- if the model 2 or 3 is used, search for the divergences - if(IS_PATTERN_USAGE(2)) - { - //--- perform the extended analysis of the oscillator state - ExtState(idx); - //--- if the model 2 is used, search for the "divergence" signal - if(CompareMaps(1,1)) // 00000001b - result=m_pattern_2; // signal number 2 - } - } -//--- return the result - return(result); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Trailing/TrailingFixedPips.mqh b/Include/Expert/Trailing/TrailingFixedPips.mqh deleted file mode 100644 index a854312..0000000 --- a/Include/Expert/Trailing/TrailingFixedPips.mqh +++ /dev/null @@ -1,132 +0,0 @@ -//+------------------------------------------------------------------+ -//| TrailingFixedPips.mqh | -//| Copyright 2009-2016, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+----------------------------------------------------------------------+ -//| Description of the class | -//| Title=Trailing Stop based on fixed Stop Level | -//| Type=Trailing | -//| Name=FixedPips | -//| Class=CTrailingFixedPips | -//| Page= | -//| Parameter=StopLevel,int,30,Stop Loss trailing level (in points) | -//| Parameter=ProfitLevel,int,50,Take Profit trailing level (in points) | -//+----------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CTrailingFixedPips. | -//| Purpose: Class of trailing stops with fixed stop level in pips. | -//| Derives from class CExpertTrailing. | -//+------------------------------------------------------------------+ -class CTrailingFixedPips : public CExpertTrailing - { -protected: - //--- input parameters - int m_stop_level; - int m_profit_level; - -public: - CTrailingFixedPips(void); - ~CTrailingFixedPips(void); - //--- methods of initialization of protected data - void StopLevel(int stop_level) { m_stop_level=stop_level; } - void ProfitLevel(int profit_level) { m_profit_level=profit_level; } - virtual bool ValidationSettings(void); - //--- - virtual bool CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp); - virtual bool CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -void CTrailingFixedPips::CTrailingFixedPips(void) : m_stop_level(30), - m_profit_level(50) - { - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CTrailingFixedPips::~CTrailingFixedPips(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CTrailingFixedPips::ValidationSettings(void) - { - if(!CExpertTrailing::ValidationSettings()) - return(false); -//--- initial data checks - if(m_profit_level!=0 && m_profit_level*(m_adjusted_point/m_symbol.Point())delta) - { - sl=price-delta; - if(m_profit_level!=0) - tp=price+m_profit_level*m_adjusted_point; - } -//--- - return(sl!=EMPTY_VALUE); - } -//+------------------------------------------------------------------+ -//| Checking trailing stop and/or profit for short position. | -//+------------------------------------------------------------------+ -bool CTrailingFixedPips::CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp) - { -//--- check - if(position==NULL) - return(false); - if(m_stop_level==0) - return(false); -//--- - double delta; - double pos_sl=position.StopLoss(); - double base =(pos_sl==0.0) ? position.PriceOpen() : pos_sl; - double price =m_symbol.Ask(); -//--- - sl=EMPTY_VALUE; - tp=EMPTY_VALUE; - delta=m_stop_level*m_adjusted_point; - if(base-price>delta) - { - sl=price+delta; - if(m_profit_level!=0) - tp=price-m_profit_level*m_adjusted_point; - } -//--- - return(sl!=EMPTY_VALUE); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Trailing/TrailingMA.mqh b/Include/Expert/Trailing/TrailingMA.mqh deleted file mode 100644 index 34e97de..0000000 --- a/Include/Expert/Trailing/TrailingMA.mqh +++ /dev/null @@ -1,157 +0,0 @@ -//+------------------------------------------------------------------+ -//| TrailingMA.mqh | -//| Copyright 2009-2013, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Trailing Stop based on MA | -//| Type=Trailing | -//| Name=MA | -//| Class=CTrailingMA | -//| Page= | -//| Parameter=Period,int,12,Period of MA | -//| Parameter=Shift,int,0,Shift of MA | -//| Parameter=Method,ENUM_MA_METHOD,MODE_SMA,Method of averaging | -//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CTrailingMA. | -//| Purpose: Class of trailing stops based on MA. | -//| Derives from class CExpertTrailing. | -//+------------------------------------------------------------------+ -class CTrailingMA : public CExpertTrailing - { -protected: - CiMA *m_MA; - //--- input parameters - int m_ma_period; - int m_ma_shift; - ENUM_MA_METHOD m_ma_method; - ENUM_APPLIED_PRICE m_ma_applied; - -public: - CTrailingMA(void); - ~CTrailingMA(void); - //--- methods of initialization of protected data - void Period(int period) { m_ma_period=period; } - void Shift(int shift) { m_ma_shift=shift; } - - void Method(ENUM_MA_METHOD method) { m_ma_method=method; } - void Applied(ENUM_APPLIED_PRICE applied) { m_ma_applied=applied; } - virtual bool InitIndicators(CIndicators *indicators); - virtual bool ValidationSettings(void); - //--- - virtual bool CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp); - virtual bool CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -void CTrailingMA::CTrailingMA(void) : m_MA(NULL), - m_ma_period(12), - m_ma_shift(0), - m_ma_method(MODE_SMA), - m_ma_applied(PRICE_CLOSE) - { - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -void CTrailingMA::~CTrailingMA(void) - { - } -//+------------------------------------------------------------------+ -//| Validation settings protected data. | -//+------------------------------------------------------------------+ -bool CTrailingMA::ValidationSettings(void) - { - if(!CExpertTrailing::ValidationSettings()) - return(false); -//--- initial data checks - if(m_ma_period<=0) - { - printf(__FUNCTION__+": period MA must be greater than 0"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Checking for input parameters and setting protected data. | -//+------------------------------------------------------------------+ -bool CTrailingMA::InitIndicators(CIndicators *indicators) - { -//--- check - if(indicators==NULL) - return(false); -//--- create MA indicator - if(m_MA==NULL) - if((m_MA=new CiMA)==NULL) - { - printf(__FUNCTION__+": error creating object"); - return(false); - } -//--- add MA indicator to collection - if(!indicators.Add(m_MA)) - { - printf(__FUNCTION__+": error adding object"); - delete m_MA; - return(false); - } -//--- initialize MA indicator - if(!m_MA.Create(m_symbol.Name(),m_period,m_ma_period,m_ma_shift,m_ma_method,m_ma_applied)) - { - printf(__FUNCTION__+": error initializing object"); - return(false); - } - m_MA.BufferResize(3+m_ma_shift); -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Checking trailing stop and/or profit for long position. | -//+------------------------------------------------------------------+ -bool CTrailingMA::CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp) - { -//--- check - if(position==NULL) - return(false); -//--- - double level =NormalizeDouble(m_symbol.Bid()-m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits()); - double new_sl=NormalizeDouble(m_MA.Main(1),m_symbol.Digits()); - double pos_sl=position.StopLoss(); - double base =(pos_sl==0.0) ? position.PriceOpen() : pos_sl; -//--- - sl=EMPTY_VALUE; - tp=EMPTY_VALUE; - if(new_sl>base && new_sllevel) - sl=new_sl; -//--- - return(sl!=EMPTY_VALUE); - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Trailing/TrailingNone.mqh b/Include/Expert/Trailing/TrailingNone.mqh deleted file mode 100644 index 53b626a..0000000 --- a/Include/Expert/Trailing/TrailingNone.mqh +++ /dev/null @@ -1,40 +0,0 @@ -//+------------------------------------------------------------------+ -//| TrailingNone.mqh | -//| Copyright 2009-2013, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Trailing Stop not used | -//| Type=Trailing | -//| Name=None | -//| Class=CTrailingNone | -//| Page= | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CTrailingNone. | -//| Appointment: Class no traling stops. | -//| Derives from class CExpertTrailing. | -//+------------------------------------------------------------------+ -class CTrailingNone : public CExpertTrailing - { -public: - CTrailingNone(void); - ~CTrailingNone(void); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CTrailingNone::CTrailingNone(void) - { - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CTrailingNone::~CTrailingNone(void) - { - } -//+------------------------------------------------------------------+ diff --git a/Include/Expert/Trailing/TrailingParabolicSAR.mqh b/Include/Expert/Trailing/TrailingParabolicSAR.mqh deleted file mode 100644 index 588f02c..0000000 --- a/Include/Expert/Trailing/TrailingParabolicSAR.mqh +++ /dev/null @@ -1,123 +0,0 @@ -//+------------------------------------------------------------------+ -//| TrailingParabolicSAR.mqh | -//| Copyright 2009-2013, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -// wizard description start -//+------------------------------------------------------------------+ -//| Description of the class | -//| Title=Trailing Stop based on Parabolic SAR | -//| Type=Trailing | -//| Name=ParabolicSAR | -//| Class=CTrailingPSAR | -//| Page= | -//| Parameter=Step,double,0.02,Speed increment | -//| Parameter=Maximum,double,0.2,Maximum rate | -//+------------------------------------------------------------------+ -// wizard description end -//+------------------------------------------------------------------+ -//| Class CTrailingPSAR. | -//| Appointment: Class traling stops with Parabolic SAR. | -//| Derives from class CExpertTrailing. | -//+------------------------------------------------------------------+ -class CTrailingPSAR : public CExpertTrailing - { -protected: - CiSAR m_sar; // object-indicator - //--- adjusted parameters - double m_step; // the "speed increment" parameter of the indicator - double m_maximum; // the "maximum rate" parameter of the indicator - -public: - CTrailingPSAR(void); - ~CTrailingPSAR(void); - //--- methods of setting adjustable parameters - void Step(double step) { m_step=step; } - void Maximum(double maximum) { m_maximum=maximum; } - //--- method of creating the indicator and timeseries - virtual bool InitIndicators(CIndicators *indicators); - //--- - virtual bool CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp); - virtual bool CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -void CTrailingPSAR::CTrailingPSAR(void) : m_step(0.02), - m_maximum(0.2) - - { - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -void CTrailingPSAR::~CTrailingPSAR(void) - { - } -//+------------------------------------------------------------------+ -//| Create indicators. | -//+------------------------------------------------------------------+ -bool CTrailingPSAR::InitIndicators(CIndicators *indicators) - { -//--- check pointer - if(indicators==NULL) - return(false); -//--- add object to collection - if(!indicators.Add(GetPointer(m_sar))) - { - printf(__FUNCTION__+": error adding object"); - return(false); - } -//--- initialize object - if(!m_sar.Create(m_symbol.Name(),m_period,m_step,m_maximum)) - { - printf(__FUNCTION__+": error initializing object"); - return(false); - } -//--- ok - return(true); - } -//+------------------------------------------------------------------+ -//| Checking trailing stop and/or profit for long position. | -//+------------------------------------------------------------------+ -bool CTrailingPSAR::CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp) - { -//--- check - if(position==NULL) - return(false); -//--- - double level =NormalizeDouble(m_symbol.Bid()-m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits()); - double new_sl=NormalizeDouble(m_sar.Main(1),m_symbol.Digits()); - double pos_sl=position.StopLoss(); - double base =(pos_sl==0.0) ? position.PriceOpen() : pos_sl; -//--- - sl=EMPTY_VALUE; - tp=EMPTY_VALUE; - if(new_sl>base && new_sllevel) - sl=new_sl; -//--- - return(sl!=EMPTY_VALUE); - } -//+------------------------------------------------------------------+ diff --git a/Include/ExpertBase.mqh b/Include/ExpertBase.mqh deleted file mode 100644 index e5afc1d..0000000 --- a/Include/ExpertBase.mqh +++ /dev/null @@ -1,380 +0,0 @@ -/* - ExpertBase.mqh - - Copyright 2013-2020, Orchard Forex - https://www.orchardforex.com - -*/ - - -#include "CommonBase.mqh" -#include "SignalBase.mqh" -#include "TPSLBase.mqh" -#include "Trade/Trade.mqh" - -class CExpertBase : public CCommonBase { - -protected: - - int mMagicNumber; - string mTradeComment; - - double mVolume; - - datetime mLastBarTime; - datetime mBarTime; - - ////Changed - // Arrays to hold the signal objects - CSignalBase *mEntrySignals[]; - CSignalBase *mExitSignals[]; - ////CSignalBase *mEntrySignal; - ////CSignalBase *mExitSignal; - - double mTakeProfitValue; - double mStopLossValue; - CTPSLBase *mTakeProfitObj; - CTPSLBase *mStopLossObj; - - CTradeCustom Trade; - -private: - -protected: - - virtual bool LoopMain(bool newBar, bool firstTime); - -protected: - - int Init(int magicNumber, string tradeComment); - -public: - - // - // Constructors - // - CExpertBase() : CCommonBase() - { Init(0, ""); } - CExpertBase(string symbol, int timeframe, int magicNumber, string tradeComment) - : CCommonBase(symbol, timeframe) - { Init(magicNumber, tradeComment); } - CExpertBase(string symbol, ENUM_TIMEFRAMES timeframe, int magicNumber, string tradeComment) - : CCommonBase(symbol, timeframe) - { Init(magicNumber, tradeComment); } - CExpertBase(int magicNumber, string tradeComment) - : CCommonBase() - { Init(magicNumber, tradeComment); } - - // - // Destructors - // - ~CExpertBase(); - -public: // Default properties - - // - // Assign the default values to the expert - // - virtual void SetVolume(double volume) { mVolume = volume; } - - virtual void SetTakeProfitValue(int takeProfitPoints) - { mTakeProfitValue = PointsToDouble(takeProfitPoints); } - virtual void SetTakeProfitObj(CTPSLBase *takeProfitObj) - { mTakeProfitObj = takeProfitObj; } - - virtual void SetStopLossValue(int stopLossPoints) - { mStopLossValue = PointsToDouble(stopLossPoints); } - virtual void SetStopLossObj(CTPSLBase *stopLossObj) - { mStopLossObj = stopLossObj; } - - virtual void SetTradeComment(string comment) { mTradeComment = comment; } - virtual void SetMagic(int magicNumber) { mMagicNumber = magicNumber; - Trade.SetExpertMagicNumber(magicNumber); } - -public: // Setup - - ////Changed - virtual void AddEntrySignal(CSignalBase *signal) { AddSignal(signal, mEntrySignals); } - virtual void AddExitSignal(CSignalBase *signal) { AddSignal(signal, mExitSignals); } - virtual void AddSignal(CSignalBase *signal, CSignalBase* &signals[]); - ////virtual void AddEntrySignal(CSignalBase *signal) { mEntrySignal=signal; } - ////virtual void AddExitSignal(CSignalBase *signal) { mExitSignal=signal; } - -public: // Event handlers - - virtual int OnInit(); - virtual void OnTick(); - virtual void OnTimer() { return; } - virtual double OnTester() { return(0.0); } - virtual void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {}; - -#ifdef __MQL5__ - virtual void OnTrade() { return; } - virtual void OnTradeTransaction(const MqlTradeTransaction& trans, - const MqlTradeRequest& request, - const MqlTradeResult& result) - { return; } - virtual int OnTesterInit() { return(INIT_SUCCEEDED); } - virtual void OnTesterPass() { return; } - virtual void OnTesterDeinit() { return; } - virtual void OnBookEvent() { return; } -#endif - -public: // Functions - - virtual void GetMarketPrices(ENUM_ORDER_TYPE orderType, MqlTradeRequest &request); - ////New - virtual ENUM_OFX_SIGNAL_DIRECTION GetCurrentSignal(CSignalBase* &signals[], - ENUM_OFX_SIGNAL_TYPE signalType); - -}; - -CExpertBase::~CExpertBase() { - -} - -int CExpertBase::OnInit() { - - int i = 0; - for (i=ArraySize(mEntrySignals)-1; i>=0; i--) { - if (mEntrySignals[i].InitResult()!=INIT_SUCCEEDED) return(mEntrySignals[i].InitResult()); - } - for (i=ArraySize(mExitSignals)-1; i>=0; i--) { - if (mExitSignals[i].InitResult()!=INIT_SUCCEEDED) return(mExitSignals[i].InitResult()); - } - if (mTakeProfitObj!=NULL) { - if (mTakeProfitObj.InitResult()!=INIT_SUCCEEDED) return(mTakeProfitObj.InitResult()); - } - if (mStopLossObj!=NULL) { - if (mStopLossObj.InitResult()!=INIT_SUCCEEDED) return(mStopLossObj.InitResult()); - } - - return(INIT_SUCCEEDED); - -} - -int CExpertBase::Init(int magicNumber, string tradeComment) { - - if (mInitResult!=INIT_SUCCEEDED) return(mInitResult); - - mTradeComment = tradeComment; - SetMagic(magicNumber); - - mTakeProfitValue = 0.0; - mStopLossValue = 0.0; - - mLastBarTime = 0; - - ////New - ArrayResize(mEntrySignals, 0); // Just make sure these are initialised - ArrayResize(mExitSignals, 0); - - return(INIT_SUCCEEDED); - -} - -void CExpertBase::OnTick(void) { - - if (!TradeAllowed()) return; - - mBarTime = iTime(mSymbol, mTimeframe, 0); - - bool firstTime = (mLastBarTime==0); - bool newBar = (mBarTime!=mLastBarTime); - - if (LoopMain(newBar, firstTime)) { - mLastBarTime = mBarTime; - } - - return; - -} - -bool CExpertBase::LoopMain(bool newBar,bool firstTime) { - - // - // To start I will only trade on a new bar - // and not on the first bar after start - // - if (!newBar) return(true); - if (firstTime) return(true); - - // - // Update the signals - // - ////Changed - ENUM_OFX_SIGNAL_DIRECTION entrySignal = GetCurrentSignal(mEntrySignals, OFX_ENTRY_SIGNAL); - ENUM_OFX_SIGNAL_DIRECTION exitSignal = GetCurrentSignal(mExitSignals, OFX_EXIT_SIGNAL); - ////if (mEntrySignal!=NULL) mEntrySignal.UpdateSignal(); - ////if (mEntrySignal!=mExitSignal) { - //// if (mExitSignal!=NULL) mExitSignal.UpdateSignal(); - ////} - - // - // Should any trades be closed - // - ////Changed - if (exitSignal==OFX_SIGNAL_BOTH) { - Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY); - Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL); - } else - if (exitSignal==OFX_SIGNAL_BUY) { - Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY); - } else - if (exitSignal==OFX_SIGNAL_SELL) { - Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL); - } - ////if (mExitSignal!=NULL) { - //// if (mExitSignal.ExitSignal()==OFX_SIGNAL_BOTH) { - //// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY); - //// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL); - //// } else - //// if (mExitSignal.ExitSignal()==OFX_SIGNAL_BUY) { - //// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_BUY); - //// } else - //// if (mExitSignal.ExitSignal()==OFX_SIGNAL_SELL) { - //// Trade.PositionCloseByType(mSymbol, POSITION_TYPE_SELL); - //// } - ////} - - // - // Should a trade be opened - // - MqlTradeRequest request = {}; // Just initialising - ////Changed - if (entrySignal==OFX_SIGNAL_BOTH) { - - GetMarketPrices(ORDER_TYPE_BUY, request); - Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp); - - GetMarketPrices(ORDER_TYPE_SELL, request); - Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp); - - } else - if (entrySignal==OFX_SIGNAL_BUY) { - - GetMarketPrices(ORDER_TYPE_BUY, request); - Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp); - - } else - if (entrySignal==OFX_SIGNAL_SELL) { - - GetMarketPrices(ORDER_TYPE_SELL, request); - Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp); - - } -//// if (mEntrySignal!=NULL) { -//// if (mEntrySignal.EntrySignal()==OFX_SIGNAL_BOTH) { -//// -//// GetMarketPrices(ORDER_TYPE_BUY, request); -//// Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp); -//// -//// GetMarketPrices(ORDER_TYPE_SELL, request); -//// Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp); -//// -//// } else -//// if (mEntrySignal.EntrySignal()==OFX_SIGNAL_BUY) { -//// -//// GetMarketPrices(ORDER_TYPE_BUY, request); -//// Trade.Buy(mVolume, mSymbol, request.price, request.sl, request.tp); -//// -//// } else -//// if (mEntrySignal.EntrySignal()==OFX_SIGNAL_SELL) { -//// -//// GetMarketPrices(ORDER_TYPE_SELL, request); -//// Trade.Sell(mVolume, mSymbol, request.price, request.sl, request.tp); -//// -//// } -//// } - - return(true); - -} - -void CExpertBase::GetMarketPrices(ENUM_ORDER_TYPE orderType, MqlTradeRequest &request) { - - double sl = (mStopLossObj==NULL) ? mStopLossValue : mStopLossObj.GetStopLoss(); - double tp = (mTakeProfitObj==NULL) ? mTakeProfitValue : mTakeProfitObj.GetTakeProfit(); - - if (orderType==ORDER_TYPE_BUY) { - if (request.price==0.0) request.price = SymbolInfoDouble(mSymbol, SYMBOL_ASK); - request.tp = (tp==0.0) ? 0.0 : NormalizeDouble(request.price+tp, mDigits); - request.sl = (sl==0.0) ? 0.0 : NormalizeDouble(request.price-sl, mDigits); - } - - if (orderType==ORDER_TYPE_SELL) { - if (request.price==0.0) request.price = SymbolInfoDouble(mSymbol, SYMBOL_BID); - request.tp = (tp==0.0) ? 0.0 : NormalizeDouble(request.price-tp, mDigits); - request.sl = (sl==0.0) ? 0.0 : NormalizeDouble(request.price+sl, mDigits); - } - - return; - -} - -////New -void CExpertBase::AddSignal(CSignalBase *signal, CSignalBase* &signals[]) { - - int index = ArraySize(signals); - ArrayResize(signals, index+1); - signals[index] = signal; - -} - -////New -ENUM_OFX_SIGNAL_DIRECTION CExpertBase::GetCurrentSignal(CSignalBase* &signals[], - ENUM_OFX_SIGNAL_TYPE signalType) { - - ENUM_OFX_SIGNAL_DIRECTION result = OFX_SIGNAL_NONE; - ENUM_OFX_SIGNAL_DIRECTION r2 = OFX_SIGNAL_NONE; // Just working value - int index = ArraySize(signals); - - if (index<=0) { - - return(result); - - } else { - - signals[0].UpdateSignal(); - result = signals[0].GetSignal(signalType); - - // I have chosen to update all signals in case there is some - // behavour that needs it. The penalty is some performance - // If performance is an issue just add an exit inside the loop - // as the commented line - for (int i = 1; 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 aHfulnnsTyicU2=%ThW&MOyqLbCjJkBz}V;j diff --git a/Include/Generic/HashMap.mqh b/Include/Generic/HashMap.mqh deleted file mode 100644 index 5ae3f60..0000000 --- a/Include/Generic/HashMap.mqh +++ /dev/null @@ -1,617 +0,0 @@ -//+------------------------------------------------------------------+ -//| HashMap.mqh | -//| Copyright 2016-2021, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include -#include -#include -#include -#include -#include "HashSet.mqh" -//+------------------------------------------------------------------+ -//| Struct Entry. | -//| Usage: Internal structure for organization CHashMap. | -//+------------------------------------------------------------------+ -template -struct Entry: public Slot - { -public: - TKey key; - Entry(void): key((TKey)NULL) {} - }; -//+------------------------------------------------------------------+ -//| Class CKeyValuePair. | -//| Usage: Defines a key/value pair that can be set or retrieved. | -//+------------------------------------------------------------------+ -template -class CKeyValuePair: public IComparable*> - { -protected: - TKey m_key; - TValue m_value; - -public: - CKeyValuePair(void) { } - CKeyValuePair(TKey key,TValue value): m_key(key), m_value(value) { } - ~CKeyValuePair(void) { } - //--- methods to access protected data - TKey Key(void) { return(m_key); } - void Key(TKey key) { m_key=key; } - TValue Value(void) { return(m_value); } - void Value(TValue value) { m_value=value; } - //--- method to create clone of current instance - CKeyValuePair*Clone(void) { return new CKeyValuePair(m_key,m_value); } - //--- method to compare keys - int Compare(CKeyValuePair*pair) { return ::Compare(m_key,pair.m_key); } - //--- method for determining equality - bool Equals(CKeyValuePair*pair) { return ::Equals(m_key,pair.m_key); } - //--- method to calculate hash code - int HashCode(void) { return ::GetHashCode(m_key); } - }; -//+------------------------------------------------------------------+ -//| Class CKeyValuePairComparer. | -//| Usage: Provides a comparer class for convertation IComparer| -//| to the IComparer*> interface. | -//+------------------------------------------------------------------+ -template -class CKeyValuePairComparer: public IComparer*> - { -private: - IComparer*m_comparer; - -public: - CKeyValuePairComparer(IComparer*comaprer) { m_comparer=comaprer; } - int Compare(CKeyValuePair* x,CKeyValuePair* y) { return(m_comparer.Compare(x.Key(), y.Key())); } - }; -//+------------------------------------------------------------------+ -//| Class CHashMap. | -//| Usage: Represents a collection of keys and values. | -//+------------------------------------------------------------------+ -template -class CHashMap: public IMap - { -protected: - int m_buckets[]; - Entrym_entries[]; - int m_count; - int m_capacity; - int m_free_list; - int m_free_count; - IEqualityComparer*m_comparer; - bool m_delete_comparer; - -public: - CHashMap(void); - CHashMap(const int capacity); - CHashMap(IEqualityComparer*comparer); - CHashMap(const int capacity,IEqualityComparer*comparer); - CHashMap(IMap*map); - CHashMap(IMap*map,IEqualityComparer*comparer); - ~CHashMap(void); - //--- methods of filling data - bool Add(CKeyValuePair*pair); - bool Add(TKey key,TValue value); - //--- methods of access to protected data - int Count(void) { return(m_count-m_free_count); } - IEqualityComparer*Comparer(void) const { return(m_comparer); } - bool Contains(CKeyValuePair*item); - bool Contains(TKey key,TValue value); - bool ContainsKey(TKey key); - bool ContainsValue(TValue value); - //--- methods of copy data from collection - int CopyTo(CKeyValuePair*&dst_array[],const int dst_start=0); - int CopyTo(TKey &dst_keys[],TValue &dst_values[],const int dst_start=0); - //--- methods of cleaning and deleting - void Clear(void); - bool Remove(CKeyValuePair*item); - bool Remove(TKey key); - //--- method of access to the data - bool TryGetValue(TKey key,TValue &value); - bool TrySetValue(TKey key,TValue value); - -private: - void Initialize(const int capacity); - void Resize(int new_size); - int FindEntry(TKey key); - bool Insert(TKey key,TValue value,const bool add); - static int m_collision_threshold; - }; -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CHashMap class | -//| that is empty, has the default initial capacity, and uses the | -//| default equality comparer for the key type. | -//+------------------------------------------------------------------+ -template -CHashMap::CHashMap(void): m_count(0), - m_free_list(0), - m_free_count(0), - m_capacity(0) - { -//--- use default equality comaprer - m_comparer=new CDefaultEqualityComparer(); - m_delete_comparer=true; - } -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CHashMap class | -//| that is empty, has the specified initial capacity, and uses the | -//| default equality comparer for the key type. | -//+------------------------------------------------------------------+ -template -CHashMap::CHashMap(const int capacity): m_count(0), - m_free_list(0), - m_free_count(0), - m_capacity(0) - { -//--- set capacity - if(capacity>0) - Initialize(capacity); -//--- use default equality comaprer - m_comparer=new CDefaultEqualityComparer(); - m_delete_comparer=true; - } -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CHashMap class | -//| that is empty, has the default initial capacity, and uses the | -//| specified IEqualityComparer. | -//+------------------------------------------------------------------+ -template -CHashMap::CHashMap(IEqualityComparer*comparer): m_count(0), - m_free_list(0), - m_free_count(0), - m_capacity(0) - { -//--- check equality comaprer - if(CheckPointer(comparer)==POINTER_INVALID) - { - //--- use default equality comaprer - m_comparer=new CDefaultEqualityComparer(); - m_delete_comparer=true; - } - else - { - //--- use specified equality comaprer - m_comparer=comparer; - m_delete_comparer=false; - } - } -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CHashMap class | -//| that is empty, has the specified initial capacity, and uses the | -//| specified IEqualityComparer. | -//+------------------------------------------------------------------+ -template -CHashMap::CHashMap(const int capacity,IEqualityComparer*comparer): m_count(0), - m_free_list(0), - m_free_count(0), - m_capacity(0) - { - if(capacity>0) - Initialize(capacity); -//--- check equality comaprer - if(CheckPointer(comparer)==POINTER_INVALID) - { - //--- use default equality comaprer - m_comparer=new CDefaultEqualityComparer(); - m_delete_comparer=true; - } - else - { - //--- use specified equality comaprer - m_comparer=comparer; - m_delete_comparer=false; - } - } -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CHashMap class | -//| that contains elements copied from the specified | -//| IMap and uses the default equality comparer for the | -//| key type. | -//+------------------------------------------------------------------+ -template -CHashMap::CHashMap(IMap*map): m_count(0), - m_free_list(0), - m_free_count(0), - m_capacity(0) - { -//--- use default equality comaprer - m_comparer=new CDefaultEqualityComparer(); - m_delete_comparer=true; -//--- check map - if(CheckPointer(map)!=POINTER_INVALID && map.Count()>0) - { - //--- set capacity - Initialize(map.Count()); - TKey keys[]; - TValue values[]; - map.CopyTo(keys,values); - //--- copy all keys and values from specified map to current map - for(int i=0; i class | -//| that contains elements copied from the specified | -//| IMap and uses the specified IEqualityComparer.| -//+------------------------------------------------------------------+ -template -CHashMap::CHashMap(IMap*map,IEqualityComparer*comparer): m_count(0), - m_free_list(0), - m_free_count(0), - m_capacity(0) - { -//--- check equality comaprer - if(CheckPointer(comparer)==POINTER_INVALID) - { - //--- use default equality comaprer - m_comparer=new CDefaultEqualityComparer(); - m_delete_comparer=true; - } - else - { - //--- use specified equality comaprer - m_comparer=comparer; - m_delete_comparer=false; - } -//--- check map - if(CheckPointer(map)!=POINTER_INVALID && map.Count()>0) - { - //--- set capacity - Initialize(map.Count()); - TKey keys[]; - TValue values[]; - map.CopyTo(keys,values); - //--- copy all keys and values from specified map to current map - for(int i=0; i -CHashMap::~CHashMap(void) - { - if(m_delete_comparer) - delete m_comparer; - } -//+------------------------------------------------------------------+ -//| Adds the specified key-value pair to the map. | -//+------------------------------------------------------------------+ -template -bool CHashMap::Add(CKeyValuePair*pair) - { -//--- check pair - if(CheckPointer(pair)==POINTER_INVALID) - return(false); - return Add(pair.Key(),pair.Value()); - } -//+------------------------------------------------------------------+ -//| Adds the specified key and value to the map. | -//+------------------------------------------------------------------+ -template -bool CHashMap::Add(TKey key,TValue value) - { - return Insert(key,value,true); - } -//+------------------------------------------------------------------+ -//| Determines whether the map contains the specified key-value pair.| -//+------------------------------------------------------------------+ -template -bool CHashMap::Contains(CKeyValuePair*item) - { -//--- check pair - if(CheckPointer(item)==POINTER_INVALID) - return(false); -//--- find pair with specified key - int i=FindEntry(item.Key()); -//--- create default equality value comparer - CDefaultEqualityComparercomparer; -//--- check value is equal value from the found pair - if(i>=0 && comparer.Equals(m_entries[i].value,item.Value())) - return(true); - else - return(false); - } -//+------------------------------------------------------------------+ -//| Determines whether the map contains the specified key with value.| -//+------------------------------------------------------------------+ -template -bool CHashMap::Contains(TKey key,TValue value) - { -//--- find pair with specified key - int i=FindEntry(key); -//--- create default equality value comparer - CDefaultEqualityComparercomparer; -//--- check value is equal value from the found pair - if(i>=0 && comparer.Equals(m_entries[i].value,value)) - return(true); - else - return(false); - } -//+------------------------------------------------------------------+ -//| Determines whether the map contains the specified key. | -//+------------------------------------------------------------------+ -template -bool CHashMap::ContainsKey(TKey key) - { - return(FindEntry(key)>=0); - } -//+------------------------------------------------------------------+ -//| Determines whether the map contains the specified value. | -//+------------------------------------------------------------------+ -template -bool CHashMap::ContainsValue(TValue value) - { -//--- create default equality value comparer - CDefaultEqualityComparercomparer_value(); -//--- try to find pair contains specified value - for(int i=0; i=0 && comparer_value.Equals(m_entries[i].value,value)) - return(true); - return(false); - } -//+------------------------------------------------------------------+ -//| Copies a range of elements from the map to a compatible | -//| one-dimensional array. | -//+------------------------------------------------------------------+ -template -int CHashMap::CopyTo(CKeyValuePair*&dst_array[],const int dst_start=0) - { -//--- resize array - if(dst_start+m_count>ArraySize(dst_array)) - ArrayResize(dst_array,dst_start+m_count); -//--- start copy - int index=0; - for(int i=0; i=0) - { - //--- check indexes - if(dst_start+index>=ArraySize(dst_array) || index>=m_count) - return(index); - dst_array[dst_start+index++]=new CKeyValuePair(m_entries[i].key,m_entries[i].value); - } - return(index); - } -//+------------------------------------------------------------------+ -//| Copies a range of elements from the map to a compatible | -//| one-dimensionals keys and values arrays. | -//+------------------------------------------------------------------+ -template -int CHashMap::CopyTo(TKey &dst_keys[],TValue &dst_values[],const int dst_start=0) - { - int count=m_count-m_free_count; -//--- resize keys array - if(dst_start+count>ArraySize(dst_keys)) - ArrayResize(dst_keys,dst_start+count); -//--- resize values array - if(dst_start+count>ArraySize(dst_values)) - ArrayResize(dst_values,MathMin(ArraySize(dst_keys),dst_start+count)); -//--- start copy - int index=0; - for(int i=0; i=0) - { - //--- check indexes - if(dst_start+index>=ArraySize(dst_keys) || dst_start+index>=ArraySize(dst_values) || index>=count) - return(index); - dst_keys[dst_start+index]=m_entries[i].key; - dst_values[dst_start+index]=m_entries[i].value; - index++; - } - return(index); - } -//+------------------------------------------------------------------+ -//| Removes all keys and values from the map. | -//+------------------------------------------------------------------+ -template -void CHashMap::Clear(void) - { -//--- check count - if(m_count>0) - { - ArrayFill(m_buckets,0,m_capacity,-1); - ArrayFree(m_entries); - m_count=0; - m_free_list=-1; - m_free_count=0; - } - } -//+------------------------------------------------------------------+ -//| Removes the specified key-value pair from map. | -//+------------------------------------------------------------------+ -template -bool CHashMap::Remove(CKeyValuePair*item) - { -//--- check pair - if(CheckPointer(item)==POINTER_INVALID) - return(false); -//--- find pair with specified key - int i=FindEntry(item.Key()); -//--- create default equality value comparer - CDefaultEqualityComparercomparer_value(); -//--- remove pair - if(i>=0 && comparer_value.Equals(m_entries[i].value,item.Value())) - return Remove(item.Key()); - return(false); - } -//+------------------------------------------------------------------+ -//| Removes the value with the specified key from the map. | -//+------------------------------------------------------------------+ -template -bool CHashMap::Remove(TKey key) - { - if(m_capacity!=0) - { - int hash_code=m_comparer.HashCode(key)&0x7FFFFFFF; - int bucket=hash_code%m_capacity; - int last=-1; - //--- search pair with specified key - for(int i=m_buckets[bucket]; i>=0; last=i,i=m_entries[i].next) - { - if(m_entries[i].hash_code==hash_code && m_comparer.Equals(m_entries[i].key,key)) - { - if(last<0) - m_buckets[bucket]=m_entries[i].next; - else - m_entries[last].next=m_entries[i].next; - //--- remove pair - m_entries[i].hash_code=-1; - m_entries[i].next=m_free_list; - m_entries[i].key=(TKey)NULL; - m_entries[i].value=(TValue)NULL; - //--- incremet free count - m_free_list=i; - m_free_count++; - return(true); - } - } - } - return(false); - } -//+------------------------------------------------------------------+ -//| Gets the value associated with the specified key. | -//+------------------------------------------------------------------+ -template -bool CHashMap::TryGetValue(TKey key,TValue &value) - { -//--- find pair with specified key - int i=FindEntry(key); -//--- check index - if(i>=0) - { - //--- get value - value=m_entries[i].value; - return(true); - } - return(false); - } -//+------------------------------------------------------------------+ -//| Sets the value associated with the specified key. | -//+------------------------------------------------------------------+ -template -bool CHashMap::TrySetValue(TKey key,TValue value) - { - return Insert(key, value, false); - } -//+------------------------------------------------------------------+ -//| Initialize map with specified capacity. | -//+------------------------------------------------------------------+ -template -void CHashMap::Initialize(const int capacity) - { - m_capacity=CPrimeGenerator::GetPrime(capacity); - ArrayResize(m_buckets,m_capacity); - ArrayFill(m_buckets,0,m_capacity,-1); - ArrayResize(m_entries,m_capacity); - m_free_list=-1; - } -//+------------------------------------------------------------------+ -//| Resize map. | -//+------------------------------------------------------------------+ -template -void CHashMap::Resize(const int new_size) - { -//--- resize buckets - ArrayResize(m_buckets,new_size); - ArrayFill(m_buckets,0,new_size,-1); -//--- resize entries - ArrayResize(m_entries,new_size); -//--- restore buckets - for(int i=0; i=0) - { - int bucket=m_entries[i].hash_code%new_size; - m_entries[i].next = m_buckets[bucket]; - m_buckets[bucket] = i; - } -//--- restore capacity - m_capacity=new_size; - } -//+------------------------------------------------------------------+ -//| Find index of entry with specified key. | -//+------------------------------------------------------------------+ -template -int CHashMap::FindEntry(TKey key) - { - if(m_capacity!=NULL) - { - //--- get hash code from key - int hash_code=m_comparer.HashCode(key)&0x7FFFFFFF; - //--- search pair with specified key - for(int i=m_buckets[hash_code%m_capacity]; i>=0; i=m_entries[i].next) - if(m_entries[i].hash_code==hash_code && m_comparer.Equals(m_entries[i].key,key)) - return(i); - } - return(-1); - } -//+------------------------------------------------------------------+ -//| Insert the value with the specified key from the map. | -//+------------------------------------------------------------------+ -template -bool CHashMap::Insert(TKey key,TValue value,const bool add) - { - if(m_capacity==0) - Initialize(0); -//--- get hash code from key - int hash_code=m_comparer.HashCode(key)&0x7FFFFFFF; - int target_bucket=hash_code%m_capacity; -//--- collisions count in one bucket with different hashes - int collision_count=0; -//--- search pair with specified key - for(int i=m_buckets[target_bucket]; i>=0; i=m_entries[i].next) - { - //--- hash compare - if(m_entries[i].hash_code!=hash_code) - { - collision_count++; - continue; - } - //--- value compare - if(m_comparer.Equals(m_entries[i].key,key)) - { - //--- adding duplicate - if(add) - return(false); - m_entries[i].value=value; - return(true); - } - } -//--- check collision - if(collision_count>=m_collision_threshold) - { - int new_size=CPrimeGenerator::ExpandPrime(m_count); - Resize(new_size); - target_bucket=hash_code%new_size; - } -//--- calculate index - int index; - if(m_free_count>0) - { - index=m_free_list; - m_free_list=m_entries[index].next; - m_free_count--; - } - else - { - if(m_count==ArraySize(m_entries)) - { - int new_size=CPrimeGenerator::ExpandPrime(m_count); - Resize(new_size); - target_bucket=hash_code%new_size; - } - index=m_count; - m_count++; - } -//--- set pair - m_entries[index].hash_code=hash_code; - m_entries[index].next=m_buckets[target_bucket]; - m_entries[index].key=key; - m_entries[index].value=value; - m_buckets[target_bucket]=index; - return(true); - } -template -static int CHashMap::m_collision_threshold=8; -//+------------------------------------------------------------------+ \ No newline at end of file diff --git a/Include/Generic/HashSet.mqh b/Include/Generic/HashSet.mqh deleted file mode 100644 index fbb2141..0000000 --- a/Include/Generic/HashSet.mqh +++ /dev/null @@ -1,972 +0,0 @@ -//+------------------------------------------------------------------+ -//| HashSet.mqh | -//| Copyright 2016-2021, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include -#include -#include -#include -//+------------------------------------------------------------------+ -//| Struct Slot. | -//| Usage: Internal structure for organization CHashSet. | -//+------------------------------------------------------------------+ -template -struct Slot - { -public: - int hash_code; - T value; - int next; - Slot(void): hash_code(0),value((T)NULL),next(0) {} - }; -//+------------------------------------------------------------------+ -//| Class CHashSet. | -//| Usage: Represents a set of unique values. | -//+------------------------------------------------------------------+ -template -class CHashSet: public ISet - { -protected: - int m_buckets[]; - Slot m_slots[]; - int m_count; - int m_last_index; - int m_free_list; - IEqualityComparer*m_comparer; - bool m_delete_comparer; - -public: - CHashSet(void); - CHashSet(IEqualityComparer*comparer); - CHashSet(ICollection*collection); - CHashSet(ICollection*collection,IEqualityComparer*comparer); - CHashSet(T &array[]); - CHashSet(T &array[],IEqualityComparer*comparer); - ~CHashSet(void); - //--- methods of filling data - bool Add(T value); - //--- methods of access to protected data - int Count(void) { return(m_count); } - IEqualityComparer* Comparer(void) const { return(m_comparer); } - bool Contains(T item); - void TrimExcess(void); - //--- methods of copy data from collection - int CopyTo(T &ds_array[],const int dst_start=0); - //--- methods of cleaning and deleting - void Clear(void); - bool Remove(T item); - //--- methods of changing sets - void ExceptWith(ICollection*collection); - void ExceptWith(T &array[]); - void IntersectWith(ICollection*collection); - void IntersectWith(T &array[]); - void SymmetricExceptWith(ICollection*collection); - void SymmetricExceptWith(T &array[]); - void UnionWith(ICollection*collection); - void UnionWith(T &array[]); - //--- methods for determining the relationship between sets - bool IsProperSubsetOf(ICollection*collection); - bool IsProperSubsetOf(T &array[]); - bool IsProperSupersetOf(ICollection*collection); - bool IsProperSupersetOf(T &array[]); - bool IsSubsetOf(ICollection*collection); - bool IsSubsetOf(T &array[]); - bool IsSupersetOf(ICollection*collection); - bool IsSupersetOf(T &array[]); - bool Overlaps(ICollection*collection); - bool Overlaps(T &array[]); - bool SetEquals(ICollection*collection); - bool SetEquals(T &array[]); - -private: - void SetCapacity(const int new_size,bool new_hash_codes); - bool AddIfNotPresent(T value); - void Initialize(const int capacity); - void InternalSymmetricExceptWith(CHashSet*set); - bool InternalIsSubsetOf(CHashSet*set); - bool InternalIsSupersetOf(CHashSet*set); - bool InternalIsProperSubsetOf(CHashSet*set); - bool InternalIsProperSupersetOf(CHashSet*set); - }; -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CHashSet class that is empty| -//| and uses the default equality comparer for the set type. | -//+------------------------------------------------------------------+ -template -CHashSet::CHashSet(void): m_count(0), - m_last_index(0), - m_free_list(-1) - { -//--- use default equality comaprer - m_comparer=new CDefaultEqualityComparer(); - m_delete_comparer=true; - } -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CHashSet class that is empty| -//| and uses the specified equality comparer for the set type. | -//+------------------------------------------------------------------+ -template -CHashSet::CHashSet(IEqualityComparer*comparer): m_count(0), - m_last_index(0), - m_free_list(-1) - { -//--- check equality comaprer - if(CheckPointer(comparer)==POINTER_INVALID) - { - //--- use default equality comaprer - m_comparer=new CDefaultEqualityComparer(); - m_delete_comparer=true; - } - else - { - //--- use specified equality comaprer - m_comparer=comparer; - m_delete_comparer=false; - } - } -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CHashSet class that uses the| -//| default equality comparer for the set type, contains elements | -//| copied from the specified collection, and has sufficient capacity| -//| to accommodate the number of elements copied. | -//+------------------------------------------------------------------+ -template -CHashSet::CHashSet(ICollection*collection): m_count(0), - m_last_index(0), - m_free_list(-1) - { -//--- use default equality comaprer - m_comparer=new CDefaultEqualityComparer(); - m_delete_comparer=true; -//--- check collection - if(CheckPointer(collection)==POINTER_INVALID) - return; -//--- set capacity for elements of the collection - int count=collection.Count(); - Initialize(count); -//--- add element from collection to the set - this.UnionWith(collection); - if((m_count==0 && ArraySize(m_slots)>3) || - (m_count>0 && ArraySize(m_slots)/m_count>3)) - TrimExcess(); - } -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CHashSet class that uses the| -//| specified equality comparer for the set type, contains elements | -//| copied from the specified collection, and has sufficient capacity| -//| to accommodate the number of elements copied. | -//+------------------------------------------------------------------+ -template -CHashSet::CHashSet(ICollection*collection,IEqualityComparer*comparer): m_count(0), - m_last_index(0), - m_free_list(-1) - { -//--- check equality comaprer - if(CheckPointer(comparer)==POINTER_INVALID) - { - //--- use default equality comaprer - m_comparer=new CDefaultEqualityComparer(); - m_delete_comparer=true; - } - else - { - //--- use specified comaprer - m_comparer=comparer; - m_delete_comparer=false; - } -//--- check collection - if(CheckPointer(collection)==POINTER_INVALID) - return; -//--- set capacity for elements of the collection - int count=collection.Count(); - Initialize(count); -//--- add element from collection to the set - this.UnionWith(collection); - if((m_count==0 && ArraySize(m_slots)>3) || - (m_count>0 && ArraySize(m_slots)/m_count>3)) - TrimExcess(); - } -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CHashSet class that uses the| -//| default equality comparer for the set type, contains elements | -//| copied from the specified array, and has sufficient capacity to | -//| accommodate the number of elements copied. | -//+------------------------------------------------------------------+ -template -CHashSet::CHashSet(T &array[]): m_count(0), - m_last_index(0), - m_free_list(-1) - { -//--- use default equality comaprer - m_comparer=new CDefaultEqualityComparer(); - m_delete_comparer=true; -//--- set capacity for elements of the array - int count=ArraySize(array); - Initialize(count); -//--- add element from array to the set - this.UnionWith(array); - if((m_count==0 && ArraySize(m_slots)>3) || - (m_count>0 && ArraySize(m_slots)/m_count>3)) - TrimExcess(); - } -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CHashSet class that uses the| -//| specified equality comparer for the set type, contains elements | -//| copied from the specified array, and has sufficient capacity to | -//| accommodate the number of elements copied. | -//+------------------------------------------------------------------+ -template -CHashSet::CHashSet(T &array[],IEqualityComparer*comparer): m_count(0), - m_last_index(0), - m_free_list(-1) - { -//--- check equality comaprer - if(CheckPointer(comparer)==POINTER_INVALID) - { - //--- use default equality comaprer - m_comparer=new CDefaultEqualityComparer(); - m_delete_comparer=true; - } - else - { - //--- use specified comaprer - m_comparer=comparer; - m_delete_comparer=false; - } -//--- set capacity for elements of the array - int count=ArraySize(array); - Initialize(count); -//--- add element from array to the set - this.UnionWith(array); - if((m_count==0 && ArraySize(m_slots)>3) || - (m_count>0 && ArraySize(m_slots)/m_count>3)) - TrimExcess(); - } -//+------------------------------------------------------------------+ -//| Destructor. | -//+------------------------------------------------------------------+ -template CHashSet::~CHashSet(void) - { - if(m_delete_comparer) - delete m_comparer; - } -//+------------------------------------------------------------------+ -//| Adds the specified element to a set. | -//+------------------------------------------------------------------+ -template -bool CHashSet::Add(T value) - { - return AddIfNotPresent(value); - } -//+------------------------------------------------------------------+ -//| Determines whether a set contains the specified element. | -//+------------------------------------------------------------------+ -template -bool CHashSet::Contains(T item) - { -//--- check buckets - if(ArraySize(m_buckets)!=0) - { - //--- get hash code for item - int hash_code=m_comparer.HashCode(item)&0x7FFFFFFF; - //--- search item in the slots - for(int i=m_buckets[hash_code%ArraySize(m_buckets)]-1; i>=0; i=m_slots[i].next) - if(m_slots[i].hash_code==hash_code && m_comparer.Equals(m_slots[i].value,item)) - return(true); - } - return(false); - } -//+------------------------------------------------------------------+ -//| Sets the capacity of a set to the actual number of elements it | -//| contains, rounded up to a nearby, implementation-specific value. | -//+------------------------------------------------------------------+ -template -void CHashSet::TrimExcess(void) - { - if(m_count==0) - { - ArrayFree(m_buckets); - ArrayFree(m_slots); - } - else - { - //--- calculate min prime size for current count - int new_size=CPrimeGenerator::GetPrime(m_count); - //--- resize buckets and slots - ArrayResize(m_slots,new_size); - ArrayResize(m_buckets,new_size); - //--- restore buckets and slots - int new_index=0; - for(int i=0; i=0) - { - m_slots[new_index]=m_slots[i]; - //--- rehash - int bucket=m_slots[new_index].hash_code%new_size; - m_slots[new_index].next=m_buckets[bucket]-1; - m_buckets[bucket]=new_index+1; - //--- increment index - new_index++; - } - } - m_last_index=new_index; - m_free_list=-1; - } - } -//+------------------------------------------------------------------+ -//| Copies a range of elements from the set to a compatible | -//| one-dimensional array. | -//+------------------------------------------------------------------+ -template -int CHashSet::CopyTo(T &dst_array[],const int dst_start) - { -//--- resize array - if(dst_start+m_count>ArraySize(dst_array)) - ArrayResize(dst_array,dst_start+m_count); -//--- start copy - int index=0; - for(int i=0; i=0) - { - if(dst_start+index>=ArraySize(dst_array) || index>=m_count) - return(index); - dst_array[dst_start+index++]=m_slots[i].value; - } - return(index); - } -//+------------------------------------------------------------------+ -//| Removes all elements from a set. | -//+------------------------------------------------------------------+ -template -void CHashSet::Clear(void) - { - if(m_last_index>0) - { - ArrayFree(m_slots); - ArrayFree(m_buckets); - m_last_index=0; - m_count=0; - m_free_list=-1; - } - } -//+------------------------------------------------------------------+ -//| Removes the specified element from a set. | -//+------------------------------------------------------------------+ -template -bool CHashSet::Remove(T item) - { - if(ArraySize(m_buckets)!=0) - { - //--- get hash code for item - int hash_code=m_comparer.HashCode(item)&0x7FFFFFFF; - int bucket=hash_code%ArraySize(m_buckets); - int last=-1; - //--- search item - for(int i=m_buckets[bucket]-1; i>=0; last=i,i=m_slots[i].next) - { - if(m_slots[i].hash_code==hash_code && m_comparer.Equals(m_slots[i].value,item)) - { - if(last<0) - m_buckets[bucket]=m_slots[i].next+1; - else - m_slots[last].next=m_slots[i].next; - //--- remove item - m_slots[i].hash_code=-1; - m_slots[i].value=(T)NULL; - m_slots[i].next =m_free_list; - //--- decrement count - m_count--; - if(m_count==0) - { - m_last_index= 0; - m_free_list = -1; - } - else - { - m_free_list=i; - } - return(true); - } - } - } - return(false); - } -//+------------------------------------------------------------------+ -//| Removes all elements in the specified collection from the current| -//| set. | -//+------------------------------------------------------------------+ -template -void CHashSet::ExceptWith(ICollection*collection) - { -//--- check collection - if(CheckPointer(collection)==POINTER_INVALID) - return; -//--- this is already the enpty set - if(m_count==0) - return; -//--- special case if collecion is this -//--- a set minus itself is the empty set - if(collection==GetPointer(this)) - { - Clear(); - return; - } -//--- copy collection to array - T array[]; - collection.CopyTo(array,0); -//--- remove every element in collection from this - for(int i=0; i -void CHashSet::ExceptWith(T &array[]) - { -//--- this is already the enpty set - if(m_count==0) - return; -//--- remove every element in collection from this - for(int i=0; i -void CHashSet::IntersectWith(ICollection*collection) - { -//--- check collection - if(CheckPointer(collection)==POINTER_INVALID) - return; -//--- intersection of anything with empty set is empty set, so return if count is 0 - if(m_count==0) - return; -//--- if collection is empty, intersection is empty set - if(collection.Count()==0) - { - Clear(); - return; - } -//--- intersect - for(int i=0; i=0) - { - T item=m_slots[i].value; - if(!collection.Contains(item)) - Remove(item); - } - } - } -//+------------------------------------------------------------------+ -//| Modifies the current set to contain only elements that are | -//| present in that object and in the specified array. | -//+------------------------------------------------------------------+ -template -void CHashSet::IntersectWith(T &array[]) - { -//--- intersection of anything with empty set is empty set, so return if count is 0 - if(m_count==0) - return; -//--- if collection is empty, intersection is empty set - if(ArraySize(array)==0) - { - Clear(); - return; - } -//--- intersect - CHashSetset(array); - for(int i=0; i=0) - { - T item=m_slots[i].value; - if(!set.Contains(item)) - Remove(item); - } - } - } -//+------------------------------------------------------------------+ -//| Modifies the current set to contain only elements that are | -//| present either in that set or in the specified collection, but | -//| not both. | -//+------------------------------------------------------------------+ -template -void CHashSet::SymmetricExceptWith(ICollection*collection) - { -//--- check collection - if(CheckPointer(collection)==POINTER_INVALID) - return; -//--- if set is empty, then symmetric difference is other - if(m_count==0) - { - UnionWith(collection); - return; - } -//--- special case this; the symmetric difference of a set with itself is the empty set - if(collection==GetPointer(this)) - { - Clear(); - return; - } -//--- check collection is set - CHashSet*ptr_set=dynamic_cast*>(collection); - if(CheckPointer(ptr_set)!=POINTER_INVALID) - { - InternalSymmetricExceptWith(ptr_set); - } - else - { - //--- create a set based on a specified collection - CHashSetset(collection); - InternalSymmetricExceptWith(GetPointer(set)); - } - } -//+------------------------------------------------------------------+ -//| Modifies the current set to contain only elements that are | -//| present either in that set or in the specified array, but not | -//| both. | -//+------------------------------------------------------------------+ -template -void CHashSet::SymmetricExceptWith(T &array[]) - { -//--- if set is empty, then symmetric difference is other - if(m_count==0) - { - UnionWith(array); - return; - } -//--- symmetric except - CHashSetset(array); - InternalSymmetricExceptWith(GetPointer(set)); - } -//+------------------------------------------------------------------+ -//| Modifies the current set to contain all elements that are present| -//| in itself, the specified collection, or both. | -//+------------------------------------------------------------------+ -template -void CHashSet::UnionWith(ICollection*collection) - { -//--- check collection - if(CheckPointer(collection)==POINTER_INVALID) - return; -//--- get array from collection - T array[]; - collection.CopyTo(array); -//--- union array with the current set - UnionWith(array); - } -//+------------------------------------------------------------------+ -//| Modifies the current set to contain all elements that are present| -//| in itself, the specified array, or both. | -//+------------------------------------------------------------------+ -template -void CHashSet::UnionWith(T &array[]) - { - for(int i=0; i -bool CHashSet::IsProperSubsetOf(ICollection*collection) - { -//--- check collection - if(CheckPointer(collection)==POINTER_INVALID) - return(false); -//--- the empty set is a proper subset of anything but the empty set - if(m_count==0) - return(collection.Count()>0); -//--- check collection is set - CHashSet*ptr_set=dynamic_cast*>(collection); - if(CheckPointer(ptr_set)!=POINTER_INVALID) - { - return InternalIsProperSubsetOf(ptr_set); - } - else - { - //--- create a set based on a specified collection - CHashSetset(collection); - return InternalIsProperSubsetOf(GetPointer(set)); - } - } -//+------------------------------------------------------------------+ -//| Determines whether a set is a proper subset of the specified | -//| array. | -//+------------------------------------------------------------------+ -template -bool CHashSet::IsProperSubsetOf(T &array[]) - { -//--- the empty set is a proper subset of anything but the empty set - if(m_count==0) - return(ArraySize(array)>0); -//--- create a set based on a specified array - CHashSetset(array); - return InternalIsProperSubsetOf(GetPointer(set)); - } -//+------------------------------------------------------------------+ -//| Determines whether a set is a proper superset of the specified | -//| collection. | -//+------------------------------------------------------------------+ -template -bool CHashSet::IsProperSupersetOf(ICollection*collection) - { -//--- check collection - if(CheckPointer(collection)==POINTER_INVALID) - return(m_count>0); -//--- the empty set is a proper subset of anything but the empty set - if(m_count==0) - return(false); -//--- if other is the empty set then this is a superset - if(collection.Count()==0) - return(true); -//--- check collection is set - CHashSet*ptr_set=dynamic_cast*>(collection); - if(CheckPointer(ptr_set)!=POINTER_INVALID) - { - return InternalIsProperSupersetOf(ptr_set); - } - else - { - //--- create a set based on a specified collection - CHashSetset(collection); - return InternalIsProperSupersetOf(GetPointer(set)); - } - } -//+------------------------------------------------------------------+ -//| Determines whether a set is a proper superset of the specified | -//| array. | -//+------------------------------------------------------------------+ -template -bool CHashSet::IsProperSupersetOf(T &array[]) - { -//--- the empty set is a proper subset of anything but the empty set - if(m_count==0) - return(false); -//--- if other is the empty set then this is a superset - if(ArraySize(array)==0) - return(true); -//--- create a set based on a specified array - CHashSetset(array); - return InternalIsProperSupersetOf(GetPointer(set)); - } -//+------------------------------------------------------------------+ -//| Determines whether a set is a subset of the specified collection.| -//+------------------------------------------------------------------+ -template -bool CHashSet::IsSubsetOf(ICollection*collection) - { - if(CheckPointer(collection)==POINTER_INVALID) - return(m_count==0); -//--- The empty set is a subset of any set - if(m_count==0) - return(true); -//--- check collection is set - CHashSet*ptr_set=dynamic_cast*>(collection); - if(CheckPointer(ptr_set)!=POINTER_INVALID) - { - return InternalIsSubsetOf(ptr_set); - } - else - { - //--- create a set based on a specified collection - CHashSetset(collection); - return InternalIsSubsetOf(GetPointer(set)); - } - } -//+------------------------------------------------------------------+ -//| Determines whether a set is a subset of the specified array. | -//+------------------------------------------------------------------+ -template -bool CHashSet::IsSubsetOf(T &array[]) - { -//--- The empty set is a subset of any set - if(m_count==0) - return(true); -//--- create a set based on a specified array - CHashSetset(array); - return InternalIsSubsetOf(GetPointer(set)); - } -//+------------------------------------------------------------------+ -//| Determines whether a set is a superset of the specified | -//| collection. | -//+------------------------------------------------------------------+ -template -bool CHashSet::IsSupersetOf(ICollection*collection) - { - if(CheckPointer(collection)==POINTER_INVALID) - return(m_count>=0); -//--- if other is the empty set then this is a superset - if(collection.Count()==0) - return(true); -//--- check collection is set - CHashSet*ptr_set=dynamic_cast*>(collection); - if(CheckPointer(ptr_set)!=POINTER_INVALID) - { - return InternalIsSupersetOf(ptr_set); - } - else - { - //--- create a set based on a specified collection - CHashSetset(collection); - return InternalIsSupersetOf(GetPointer(set)); - } - } -//+------------------------------------------------------------------+ -//| Determines whether a set is a superset of the specified array. | -//+------------------------------------------------------------------+ -template -bool CHashSet::IsSupersetOf(T &array[]) - { -//--- if other is the empty set then this is a superset - if(ArraySize(array)==0) - return(true); -//--- create a set based on a specified array - CHashSetset(array); - return InternalIsSupersetOf(GetPointer(set)); - } -//+------------------------------------------------------------------+ -//| Determines whether the current set and a specified collection | -//| share common elements. | -//+------------------------------------------------------------------+ -template -bool CHashSet::Overlaps(ICollection*collection) - { -//--- check collection - if(CheckPointer(collection)==POINTER_INVALID) - return(false); -//--- check current count - if(m_count==0) - return(false); -//--- get array from collection - T array[]; - collection.CopyTo(array); -//--- check overlaps between current set and array - return Overlaps(array); - } -//+------------------------------------------------------------------+ -//| Determines whether the current set and a specified array share | -//| common elements. | -//+------------------------------------------------------------------+ -template -bool CHashSet::Overlaps(T &array[]) - { -//--- check current count - if(m_count==0) - return(false); -//--- try to find any elements from specified array in current set - for(int i=0; i -bool CHashSet::SetEquals(ICollection*collection) - { -//--- check collection - if(CheckPointer(collection)==POINTER_INVALID) - return(false); -//--- check current set is equal specified collection - if(collection==GetPointer(this)) - return(true); -//--- get array from collection - T array[]; - collection.CopyTo(array); -//--- check current set is equal specified array - return SetEquals(array); - } -//+------------------------------------------------------------------+ -//| Determines whether a set and the specified array contain the same| -//| elements. | -//+------------------------------------------------------------------+ -template -bool CHashSet::SetEquals(T &array[]) - { -//--- check size - if(ArraySize(array)!=m_count) - return(false); -//--- check current set is equal specified array - for(int i=0; i -void CHashSet::SetCapacity(const int new_size,bool new_hash_codes) - { -//--- resize slots - ArrayResize(m_slots,new_size); -//--- restore slots - if(new_hash_codes) - for(int i=0; i -bool CHashSet::AddIfNotPresent(T value) - { -//--- set minimum capacity - if(ArraySize(m_buckets)==0) - Initialize(0); -//--- get hash code and bucket for value - int hash_code=m_comparer.HashCode(value)&0x7FFFFFFF; - int bucket=hash_code%ArraySize(m_buckets); -//--- check value already in the set - for(int i=m_buckets[hash_code%ArraySize(m_buckets)]-1; i>=0; i=m_slots[i].next) - if(m_slots[i].hash_code==hash_code && m_comparer.Equals(m_slots[i].value,value)) - return(false); -//--- calculate index for value - int index=0; - if(m_free_list>=0) - { - index=m_free_list; - m_free_list=m_slots[index].next; - } - else - { - if(m_last_index==ArraySize(m_slots)) - { - int new_size=CPrimeGenerator::ExpandPrime(m_count); - SetCapacity(new_size,false); - bucket=hash_code%ArraySize(m_buckets); - } - index=m_last_index; - m_last_index++; - } -//--- set value - m_slots[index].hash_code=hash_code; - m_slots[index].value=value; - m_slots[index].next=m_buckets[bucket]-1; - m_buckets[bucket]=index+1; -//--- increase count - m_count++; - return(true); - } -//+------------------------------------------------------------------+ -//| Initialize set with specified capacity. | -//+------------------------------------------------------------------+ -template -void CHashSet::Initialize(const int capacity) - { - int size=CPrimeGenerator::GetPrime(capacity); - ArrayResize(m_buckets,size); - ArrayResize(m_slots,size); - ZeroMemory(m_buckets); - ZeroMemory(m_slots); - } -//+------------------------------------------------------------------+ -//| Modifies the current set to contain only elements that are | -//| present either in that set or in the specified set, but not both.| -//+------------------------------------------------------------------+ -template -void CHashSet::InternalSymmetricExceptWith(CHashSet*set) - { - for(int i=0; i -bool CHashSet::InternalIsSubsetOf(CHashSet*set) - { -//--- if this has more elements then it can't be a subset - if(m_count>set.m_count) - return(false); -//--- try to find any elements from current set in specified set - for(int i=0; i -bool CHashSet::InternalIsSupersetOf(CHashSet*set) - { -//--- if this has less elements then it can't be a superset - if(set.m_count>m_count) - return(false); -//--- try to find any elements from specified set in current set - for(int i=0; i -bool CHashSet::InternalIsProperSubsetOf(CHashSet*set) - { -//--- if this has more or equal elements then it can't be a proper subset - if(m_count>=set.m_count) - return(false); -//--- try to find any elements from current set in specified set - for(int i=0; i -bool CHashSet::InternalIsProperSupersetOf(CHashSet*set) - { -//--- if this has less or equal elements then it can't be a proper superset - if(m_count<=set.m_count) - return(false); -//--- try to find any elements from specified set in current set - for(int i=0; i. | -//| Usage: Defines methods to manipulate generic collections. | -//+------------------------------------------------------------------+ -template -interface ICollection - { -//--- methods of filling data - bool Add(T value); -//--- methods of access to protected data - int Count(void); - bool Contains(T item); -//--- methods of copy data from collection - int CopyTo(T &dst_array[],const int dst_start=0); -//--- methods of cleaning and removing - void Clear(void); - bool Remove(T item); - }; -//+------------------------------------------------------------------+ diff --git a/Include/Generic/Interfaces/IComparable.mqh b/Include/Generic/Interfaces/IComparable.mqh deleted file mode 100644 index 45fb320..0000000 --- a/Include/Generic/Interfaces/IComparable.mqh +++ /dev/null @@ -1,19 +0,0 @@ -//+------------------------------------------------------------------+ -//| IComparable.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include "IEqualityComparable.mqh" -//+------------------------------------------------------------------+ -//| Interface IComparable. | -//| Usage: Defines a generalized comparison method to create a | -//| type-specific comparison method for ordering or sorting | -//| instances. | -//+------------------------------------------------------------------+ -template -interface IComparable: public IEqualityComparable - { -//--- method for determining compare - int Compare(T value); - }; -//+------------------------------------------------------------------+ diff --git a/Include/Generic/Interfaces/IComparer.mqh b/Include/Generic/Interfaces/IComparer.mqh deleted file mode 100644 index 47862dd..0000000 --- a/Include/Generic/Interfaces/IComparer.mqh +++ /dev/null @@ -1,17 +0,0 @@ -//+------------------------------------------------------------------+ -//| IComparer.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ -//| Interface IComparer. | -//| Usage: Defines a method that a type implements to compare two | -//| values. | -//+------------------------------------------------------------------+ -template -interface IComparer - { -//--- compares two values and returns a value indicating whether one is less than, equal to, or greater than the other - int Compare(T x,T y); - }; -//+------------------------------------------------------------------+ diff --git a/Include/Generic/Interfaces/IEqualityComparable.mqh b/Include/Generic/Interfaces/IEqualityComparable.mqh deleted file mode 100644 index 5a09bde..0000000 --- a/Include/Generic/Interfaces/IEqualityComparable.mqh +++ /dev/null @@ -1,19 +0,0 @@ -//+------------------------------------------------------------------+ -//| IEqualityComparable.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ -//| Interface IEqualityComparable. | -//| Usage: Defines a generalized method to create a type-specific | -//| method for determining equality of instances. | -//+------------------------------------------------------------------+ -template -interface IEqualityComparable - { -//--- method for determining equality - bool Equals(T value); -//--- method to calculate hash code - int HashCode(void); - }; -//+------------------------------------------------------------------+ diff --git a/Include/Generic/Interfaces/IEqualityComparer.mqh b/Include/Generic/Interfaces/IEqualityComparer.mqh deleted file mode 100644 index 8fbe395..0000000 --- a/Include/Generic/Interfaces/IEqualityComparer.mqh +++ /dev/null @@ -1,19 +0,0 @@ -//+------------------------------------------------------------------+ -//| IEqualityComparer.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ -//| Interface IEqualityComparer. | -//| Usage: Defines methods to support the comparison of values for | -//| equality. | -//+------------------------------------------------------------------+ -template -interface IEqualityComparer - { -//--- determines whether the specified values are equal - bool Equals(T x,T y); -//--- returns a hash code for the specified object - int HashCode(T value); - }; -//+------------------------------------------------------------------+ diff --git a/Include/Generic/Interfaces/IList.mqh b/Include/Generic/Interfaces/IList.mqh deleted file mode 100644 index 1384a4c..0000000 --- a/Include/Generic/Interfaces/IList.mqh +++ /dev/null @@ -1,26 +0,0 @@ -//+------------------------------------------------------------------+ -//| IList.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include "ICollection.mqh" -//+------------------------------------------------------------------+ -//| Interface IList. | -//| Usage: Represents a collection of objects that can be | -//| individually accessed by index. | -//+------------------------------------------------------------------+ -template -interface IList: public ICollection - { -//--- method of access to the data - bool TryGetValue(const int index,T &value); - bool TrySetValue(const int index,T value); -//--- methods of filling the array - bool Insert(const int index,T item); -//--- methods for searching index - int IndexOf(T item); - int LastIndexOf(T item); -//--- methods of cleaning and deleting - bool RemoveAt(const int index); - }; -//+------------------------------------------------------------------+ diff --git a/Include/Generic/Interfaces/IMap.mqh b/Include/Generic/Interfaces/IMap.mqh deleted file mode 100644 index a328492..0000000 --- a/Include/Generic/Interfaces/IMap.mqh +++ /dev/null @@ -1,27 +0,0 @@ -//+------------------------------------------------------------------+ -//| IMap.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include "ICollection.mqh" -template -class CKeyValuePair; -//+------------------------------------------------------------------+ -//| Interface IMap. | -//| Usage: Represents a generic collection of key/value pairs. | -//+------------------------------------------------------------------+ -template -interface IMap: public ICollection*> - { -//--- methods of filling data - bool Add(TKey key,TValue value); -//--- methods of access to protected data - bool Contains(TKey key,TValue value); - bool Remove(TKey key); -//--- method of access to the data - bool TryGetValue(TKey key,TValue &value); - bool TrySetValue(TKey key,TValue value); -//--- methods of copy data from collection - int CopyTo(TKey &dst_keys[],TValue &dst_values[],const int dst_start=0); - }; -//+------------------------------------------------------------------+ diff --git a/Include/Generic/Interfaces/ISet.mqh b/Include/Generic/Interfaces/ISet.mqh deleted file mode 100644 index 29a3839..0000000 --- a/Include/Generic/Interfaces/ISet.mqh +++ /dev/null @@ -1,37 +0,0 @@ -//+------------------------------------------------------------------+ -//| ISet.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include "ICollection.mqh" -//+------------------------------------------------------------------+ -//| Interface ISet. | -//| Usage: Provides the base interface for the abstraction of sets. | -//+------------------------------------------------------------------+ -template -interface ISet: public ICollection - { -//--- methods of changing sets - void ExceptWith(ICollection*collection); - void ExceptWith(T &array[]); - void IntersectWith(ICollection*collection); - void IntersectWith(T &array[]); - void SymmetricExceptWith(ICollection*collection); - void SymmetricExceptWith(T &array[]); - void UnionWith(ICollection*collection); - void UnionWith(T &array[]); -//--- methods for determining the relationship between sets - bool IsProperSubsetOf(ICollection*collection); - bool IsProperSubsetOf(T &array[]); - bool IsProperSupersetOf(ICollection*collection); - bool IsProperSupersetOf(T &array[]); - bool IsSubsetOf(ICollection*collection); - bool IsSubsetOf(T &array[]); - bool IsSupersetOf(ICollection*collection); - bool IsSupersetOf(T &array[]); - bool Overlaps(ICollection*collection); - bool Overlaps(T &array[]); - bool SetEquals(ICollection*collection); - bool SetEquals(T &array[]); - }; -//+------------------------------------------------------------------+ diff --git a/Include/Generic/Internal/ArrayFunction.mqh b/Include/Generic/Internal/ArrayFunction.mqh deleted file mode 100644 index 1204bc7..0000000 --- a/Include/Generic/Internal/ArrayFunction.mqh +++ /dev/null @@ -1,135 +0,0 @@ -//+------------------------------------------------------------------+ -//| ArrayFunction.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include "CompareFunction.mqh" -#include -//+------------------------------------------------------------------+ -//| Searches an entire one-dimensional sorted array for a specific | -//| element, using the IComparable generic interface implemented | -//| by each element of the array and by the specified object. | -//+------------------------------------------------------------------+ -template -int ArrayBinarySearch(T &array[],const int start_index,const int count, T value,IComparer*comparer) - { - int lo=start_index; - int hi=start_index+count-1; - int size=ArraySize(array); -//--- check array size - if(size==0) - return(-1); -//--- check comaparer - if(CheckPointer(comparer)==POINTER_INVALID) - return(-1); -//--- check index - if(start_index<0 || count<0 || size-start_index>1); - int order=comparer.Compare(array[i],value); - if(order==0) - { - return(i); - } - if(order<0) - { - lo=i+1; - } - else - { - hi=i-1; - } - } -//--- returns the index of an element nearest in value - if(lo>0) - return(lo-1); - return(lo); - } -//+------------------------------------------------------------------+ -//| Searches for the specified object and returns the index of its | -//| first occurrence in a one-dimensional array. | -//+------------------------------------------------------------------+ -template -int ArrayIndexOf(T &array[],T value,const int start_index,const int count) - { - int size=ArraySize(array); -//--- check array size - if(size==0) - return(-1); -//--- check start index and count - if(start_index<0 || start_index>size || - count<0 || count>size-start_index) - return(-1); -//--- search value - int end_index=start_index+count; - for(int i=start_index; i -int ArrayLastIndexOf(T &array[],T value,const int start_index,const int count) - { - int size=ArraySize(array); -//--- check array size - if(size==0) - return(-1); -//--- check start index and count - if(start_index<0 || start_index>=size || - count<0 || count>start_index+1) - return(-1); -//--- search value - int end_index=start_index-count+1; - for(int i=start_index; i>=end_index; i--) - { - //--- check the value in array is eqaul to specified value - if(::Equals(array[i],value)) - { - //--- return fist index from the end - return (i); - } - } -//--- return -1 if value not in array - return(-1); - } -//+------------------------------------------------------------------+ -//| Reverses the elements in a range of this array. Following a call | -//| to this method, an element in the range given by index and count | -//| which was previously located at index i will now be located at | -//| index index + (index + count - i - 1). | -//+------------------------------------------------------------------+ -template -bool ArrayReverse(T &array[],const int start_index,const int count) - { - int size=ArraySize(array); -//--- check start index and count - if(count<0 || size-start_index -//+------------------------------------------------------------------+ -//| Compares two objects and returns a value indicating whether one | -//| is less than, equal to, or greater than the other. | -//+------------------------------------------------------------------+ -int Compare(const bool x,const bool y) - { - if(x>y) - return(1); - else if(xy) - return(1); - else if(xy) - return(1); - else if(xy) - return(1); - else if(xy) - return(1); - else if(xy) - return(1); - else if(xy) - return(1); - else if(xy) - return(1); - else if(xy) - return(1); - else if(xy) - return(1); - else if(xy) - return(1); - else if(xy) - return(1); - else if(xy) - return(1); - else if(xy) - return(1); - else if(x -int Compare(T x,T y) - { -//--- try to convert to comparable object - IComparable*comparable=dynamic_cast*>(x); - if(comparable) - { - //--- use specied compare method - return comparable.Compare(y); - } - else - { - //--- unknown compare function - return(0); - } - } -//+------------------------------------------------------------------+ diff --git a/Include/Generic/Internal/DefaultComparer.mqh b/Include/Generic/Internal/DefaultComparer.mqh deleted file mode 100644 index cd4e7fa..0000000 --- a/Include/Generic/Internal/DefaultComparer.mqh +++ /dev/null @@ -1,22 +0,0 @@ -//+------------------------------------------------------------------+ -//| DefaultComparer.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include -#include "CompareFunction.mqh" -//+------------------------------------------------------------------+ -//| Class CDefaultComparer. | -//| Usage: Provides a default class for implementations of the | -//| IComparer generic interface. | -//+------------------------------------------------------------------+ -template -class CDefaultComparer: public IComparer - { -public: - CDefaultComparer(void) { } - ~CDefaultComparer(void) { } - //--- compares two values and returns a value describing relationship between them - int Compare(T x,T y) { return ::Compare(x,y); } - }; -//+------------------------------------------------------------------+ diff --git a/Include/Generic/Internal/DefaultEqualityComparer.mqh b/Include/Generic/Internal/DefaultEqualityComparer.mqh deleted file mode 100644 index 278f71a..0000000 --- a/Include/Generic/Internal/DefaultEqualityComparer.mqh +++ /dev/null @@ -1,25 +0,0 @@ -//+------------------------------------------------------------------+ -//| DefaultEqualityComparer.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include -#include "EqualFunction.mqh" -#include "HashFunction.mqh" -//+------------------------------------------------------------------+ -//| Class CDefaultEqualityComparer. | -//| Usage: Provides a default class for implementations of the | -//| IEqualityComparer generic interface. | -//+------------------------------------------------------------------+ -template -class CDefaultEqualityComparer: public IEqualityComparer - { -public: - CDefaultEqualityComparer(void) { } - ~CDefaultEqualityComparer(void) { } - //--- determines whether the specified values are equal - bool Equals(T x,T y) { return ::Equals(x,y); } - //--- returns a hash code for the specified object - int HashCode(T value) { return ::GetHashCode(value); } - }; -//+------------------------------------------------------------------+ diff --git a/Include/Generic/Internal/EqualFunction.mqh b/Include/Generic/Internal/EqualFunction.mqh deleted file mode 100644 index 1eb92a6..0000000 --- a/Include/Generic/Internal/EqualFunction.mqh +++ /dev/null @@ -1,26 +0,0 @@ -//+------------------------------------------------------------------+ -//| EqualFunction.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include -//+------------------------------------------------------------------+ -//| Indicates whether x object is equal y object of the same type. | -//+------------------------------------------------------------------+ -template -bool Equals(T x,T y) - { -//--- try to convert to equality comparable object - IEqualityComparable*equtable=dynamic_cast*>(x); - if(equtable) - { - //--- use specied equality compare method - return equtable.Equals(y); - } - else - { - //--- use default equality comparer operator - return(x==y); - } - } -//+------------------------------------------------------------------+ diff --git a/Include/Generic/Internal/HashFunction.mqh b/Include/Generic/Internal/HashFunction.mqh deleted file mode 100644 index 209f6c4..0000000 --- a/Include/Generic/Internal/HashFunction.mqh +++ /dev/null @@ -1,176 +0,0 @@ -//+------------------------------------------------------------------+ -//| HashFunction.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ -//| Unioun BitInterpreter. | -//| Usage: Provides the ability to interpret the same bit sequence in| -//| different types. | -//+------------------------------------------------------------------+ -union BitInterpreter - { - bool bool_value; - char char_value; - uchar uchar_value; - short short_value; - ushort ushort_value; - color color_value; - int int_value; - uint uint_value; - datetime datetime_value; - long long_value; - ulong ulong_value; - float float_value; - double double_value; - }; -//+------------------------------------------------------------------+ -//| Returns a hashcode for boolean. | -//+------------------------------------------------------------------+ -int GetHashCode(const bool value) - { - return((value)?true:false); - } -//+------------------------------------------------------------------+ -//| Returns a hashcode for character. | -//+------------------------------------------------------------------+ -int GetHashCode(const char value) - { - return((int)value | ((int)value << 16)); - } -//+------------------------------------------------------------------+ -//| Returns a hashcode for unsigned character. | -//+------------------------------------------------------------------+ -int GetHashCode(const uchar value) - { - return((int)value | ((int)value << 16)); - } -//+------------------------------------------------------------------+ -//| Returns a hashcode for short. | -//+------------------------------------------------------------------+ -int GetHashCode(const short value) - { - return(((int)((ushort)value) | (((int)value) << 16))); - } -//+------------------------------------------------------------------+ -//| Returns a hashcode for unsigned short. | -//+------------------------------------------------------------------+ -int GetHashCode(const ushort value) - { - return((int)value); - } -//+------------------------------------------------------------------+ -//| Returns a hashcode for color. | -//+------------------------------------------------------------------+ -int GetHashCode(const color value) - { - return((int)value); - } -//+------------------------------------------------------------------+ -//| Returns a hashcode for integer. | -//+------------------------------------------------------------------+ -int GetHashCode(const int value) - { - return(value); - } -//+------------------------------------------------------------------+ -//| Returns a hashcode for unsigned integer. | -//+------------------------------------------------------------------+ -int GetHashCode(const uint value) - { - return((int)value); - } -//+------------------------------------------------------------------+ -//| Returns a hashcode for datetime. | -//+------------------------------------------------------------------+ -int GetHashCode(const datetime value) - { - long ticks=(long)value; - return(((int)ticks) ^ (int)(ticks >> 32)); - } -//+------------------------------------------------------------------+ -//| Returns a hashcode for long. | -//+------------------------------------------------------------------+ -int GetHashCode(const long value) - { - return(((int)((long)value)) ^ (int)(value >> 32)); - } -//+------------------------------------------------------------------+ -//| Returns a hashcode for unsigned long. | -//+------------------------------------------------------------------+ -int GetHashCode(const ulong value) - { - return(((int)value) ^ (int)(value >> 32)); - } -//+------------------------------------------------------------------+ -//| Returns a hashcode for float. | -//+------------------------------------------------------------------+ -int GetHashCode(const float value) - { - if(value==0) - { - //--- ensure that 0 and -0 have the same hash code - return(0); - } - BitInterpreter convert; - convert.float_value=value; - return(convert.int_value); - } -//+------------------------------------------------------------------+ -//| Returns a hashcode for string. | -//+------------------------------------------------------------------+ -int GetHashCode(const double value) - { - if(value==0) - { - //--- ensure that 0 and -0 have the same hash code - return(0); - } - BitInterpreter convert; - convert.double_value=value; - long lvalue=convert.long_value; - return(((int)lvalue) ^ ((int)(lvalue >> 32))); - } -//+------------------------------------------------------------------+ -//| Returns a hashcode for string. | -//| The hashcode for a string is computed as: | -//| | -//| s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] | -//| | -//| using int arithmetic, where s[i] is the ith character of the | -//| string, n is the length of the string, and ^ indicates | -//| exponentiation. (The hash value of the empty string is zero.) | -//+------------------------------------------------------------------+ -int GetHashCode(const string value) - { - int len=StringLen(value); - int hash=0; -//--- check length of string - if(len>0) - { - //--- calculate a hash as a fucntion of each char - for(int i=0; i -int GetHashCode(T value) - { -//--- try to convert to equality comparable object - IEqualityComparable*equtable=dynamic_cast*>(value); - if(equtable) - { - //--- calculate hash by specied method - return equtable.HashCode(); - } - else - { - //--- calculate hash from name of object - return GetHashCode(typename(value)); - } - } -//+------------------------------------------------------------------+ diff --git a/Include/Generic/Internal/Introsort.mqh b/Include/Generic/Internal/Introsort.mqh deleted file mode 100644 index 8ac3ad6..0000000 --- a/Include/Generic/Internal/Introsort.mqh +++ /dev/null @@ -1,251 +0,0 @@ -//+------------------------------------------------------------------+ -//| Introsort.mqh | -//| Copyright 2016, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ -//| Struct Introsort. | -//| Usage: Used by the sort methods for instances of array. | -//+------------------------------------------------------------------+ -template -struct Introsort - { -public: - IComparer*comparer; - TKey keys[]; - TItem items[]; - - Introsort(void) {} - ~Introsort(void) {} - //--- method for sort array - void Sort(const int index,const int length); -private: - //--- methods for introspective sorting - void IntroSort(const int lo,const int hi,int depthLimit); - int PickPivotAndPartition(const int lo,const int hi); - void InsertionSort(const int lo,const int hi); - //--- methods for heap sorting - void Heapsort(const int lo,const int hi); - void DownHeap(const int i,const int n,const int lo); - //--- swap methods - void SwapIfGreaterWithItems(const int a,const int b); - void Swap(const int i,const int j); - //--- service methods - int FloorLog2(int n) const; - }; -//+------------------------------------------------------------------+ -//| IntrospectiveSort is a hybrid sorting algorithm that provides | -//| both fast average performance and (asymptotically) optimal | -//| worst-case performance. It begins with quicksort and switches to | -//| heapsort when the recursion depth exceeds a level based on the | -//| number of elements being sorted. | -//+------------------------------------------------------------------+ -template -void Introsort::Sort(const int index,const int length) - { - if(length<2) - return; - IntroSort(index,length+index-1,2*FloorLog2(ArraySize(keys))); - } -//+------------------------------------------------------------------+ -//| Exchanges the values of a and b, if a greater b. | -//+------------------------------------------------------------------+ -template -void Introsort::SwapIfGreaterWithItems(const int a,const int b) - { - if(a!=b) - { - if(comparer.Compare(keys[a],keys[b])>0) - { - TKey key=keys[a]; - keys[a]=keys[b]; - keys[b]=key; - if(ArraySize(items)!=NULL) - { - TItem item=items[a]; - items[a]=items[b]; - items[b]=item; - } - } - } - } -//+------------------------------------------------------------------+ -//| Exchanges the values of a and b. | -//+------------------------------------------------------------------+ -template -void Introsort::Swap(const int i,const int j) - { - TKey key=keys[i]; - keys[i]=keys[j]; - keys[j]=key; - if(ArraySize(items)!=NULL) - { - TItem item=items[i]; - items[i]=items[j]; - items[j]=item; - } - } -//+------------------------------------------------------------------+ -//| Returns the closest integer value less than or equal to the base | -//| 2 log of the input value. | -//+------------------------------------------------------------------+ -template -int Introsort::FloorLog2(int n) const - { - int result=0; - while(n>=1) - { - result++; - n=n/2; - } - return(result); - } -//+------------------------------------------------------------------+ -//| Introspective sort. | -//+------------------------------------------------------------------+ -template -void Introsort::IntroSort(const int lo,int hi,int depthLimit) - { - const int IntrosortSizeThreshold=16; - while(hi>lo) - { - int partitionSize = hi - lo + 1; - if(partitionSize <= IntrosortSizeThreshold) - { - if(partitionSize==1) - { - return; - } - if(partitionSize==2) - { - SwapIfGreaterWithItems(lo,hi); - return; - } - if(partitionSize==3) - { - SwapIfGreaterWithItems(lo,hi-1); - SwapIfGreaterWithItems(lo,hi); - SwapIfGreaterWithItems(hi-1,hi); - return; - } - InsertionSort(lo,hi); - return; - } - if(depthLimit==0) - { - Heapsort(lo,hi); - return; - } - depthLimit--; - int p=PickPivotAndPartition(lo,hi); - IntroSort(p+1,hi,depthLimit); - hi=p-1; - } - } -//+------------------------------------------------------------------+ -//| Insertion sort. | -//+------------------------------------------------------------------+ -template -void Introsort::InsertionSort(const int lo,const int hi) - { - int i,j; - TKey t; - TItem dt; - for(i=lo; i=lo && comparer.Compare(t,keys[j])<0) - { - keys[j+1]=keys[j]; - if(ArraySize(items)!=NULL) - { - items[j+1]=items[j]; - } - j--; - } - keys[j+1]=t; - if(ArraySize(items)!=NULL) - { - items[j+1]=dt; - } - } - } -//+------------------------------------------------------------------+ -//| Array partitioning by a quick sort algorithm. | -//+------------------------------------------------------------------+ -template -int Introsort::PickPivotAndPartition(const int lo,const int hi) - { -//--- Compute median-of-three. But also partition them, since we've done the comparison. - int mid=lo+(hi-lo)/2; - SwapIfGreaterWithItems(lo,mid); - SwapIfGreaterWithItems(lo,hi); - SwapIfGreaterWithItems(mid,hi); - TKey pivot=keys[mid]; - Swap(mid,hi-1); - int left=lo,right=hi-1; - while(left=right) - break; - Swap(left,right); - } -//--- Put pivot in the right location. - Swap(left,(hi-1)); - return (left); - } -//+------------------------------------------------------------------+ -//| Heap sorting algorithm. | -//+------------------------------------------------------------------+ -template -void Introsort::Heapsort(const int lo,const int hi) - { - int n=hi-lo+1; - for(int i=n/2; i>=1; i=i-1) - { - DownHeap(i,n,lo); - } - for(int i=n; i>1; i=i-1) - { - Swap(lo,lo+i-1); - DownHeap(1,i-1,lo); - } - } -//+------------------------------------------------------------------+ -//| Downheap function for heapsort. | -//+------------------------------------------------------------------+ -template -void Introsort::DownHeap(int i,const int n,const int lo) - { - TKey d=keys[lo+i-1]; - TItem dt=items[lo+i-1]; - int child; - while(i<=n/2) - { - child=2*i; - if(child=min) - return(prime); - } -//--- outside of our predefined table - for(int i=(min|1); i<=INT_MAX;i+=2) - { - if(IsPrime(i) && ((i-1)%s_hash_prime!=0)) - return(i); - } - return(min); - } -//+------------------------------------------------------------------+ -//| Generate a new prime value greater than old_size. | -//+------------------------------------------------------------------+ -int CPrimeGenerator::ExpandPrime(const int old_size) - { - int new_size=2*old_size; - if((uint)new_size>INT_MAX && INT_MAX>old_size) - return INT_MAX; - else - return GetPrime(new_size); - } -//+------------------------------------------------------------------+ diff --git a/Include/Generic/LinkedList.mqh b/Include/Generic/LinkedList.mqh deleted file mode 100644 index 5183648..0000000 --- a/Include/Generic/LinkedList.mqh +++ /dev/null @@ -1,563 +0,0 @@ -//+------------------------------------------------------------------+ -//| LinkedList.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include -#include -//+------------------------------------------------------------------+ -//| Class CLinkedListNode. | -//| Usage: Represents a node of linked list. | -//+------------------------------------------------------------------+ -template -class CLinkedListNode - { -protected: - CLinkedList*m_list; - CLinkedListNode*m_next; - CLinkedListNode*m_prev; - T m_item; - -public: - CLinkedListNode(T value): m_item(value) { } - CLinkedListNode(CLinkedList*list,T value): m_list(list),m_item(value) { } - ~CLinkedListNode(void) { } - //--- methods of access to protected data - CLinkedList* List(void) { return(m_list); } - void List(CLinkedList*value) { m_list=value; } - CLinkedListNode*Next(void) { return(m_next); } - void Next(CLinkedListNode*value) { m_next=value; } - CLinkedListNode*Previous(void) { return(m_prev); } - void Previous(CLinkedListNode*value) { m_prev=value; } - T Value(void) { return(m_item); } - void Value(T value) { m_item=value; } - }; -//+------------------------------------------------------------------+ -//| Class CLinkedList. | -//| Usage: Represents a doubly linked list. | -//+------------------------------------------------------------------+ -template -class CLinkedList: public ICollection - { -protected: - CLinkedListNode*m_head; - int m_count; - -public: - CLinkedList(void); - CLinkedList(ICollection*collection); - CLinkedList(T &array[]); - ~CLinkedList(void); - //--- methods of filling data - bool Add(T value); - CLinkedListNode*AddAfter(CLinkedListNode*node,T value); - bool AddAfter(CLinkedListNode*node,CLinkedListNode*new_node); - CLinkedListNode*AddBefore(CLinkedListNode*node,T value); - bool AddBefore(CLinkedListNode*node,CLinkedListNode*new_node); - CLinkedListNode*AddFirst(T value); - bool AddFirst(CLinkedListNode*node); - CLinkedListNode*AddLast(T value); - bool AddLast(CLinkedListNode*node); - //--- methods of access to protected data - int Count(void); - CLinkedListNode*Head(void) {return(m_head);} - CLinkedListNode*First(void); - CLinkedListNode*Last(void); - bool Contains(T item); - //--- methods of copy data from collection - int CopyTo(T &dst_array[],const int dst_start=0); - //--- methods of cleaning and deleting - void Clear(void); - bool Remove(T item); - bool Remove(CLinkedListNode*node); - bool RemoveFirst(void); - bool RemoveLast(void); - //--- method for searching - CLinkedListNode*Find(T value); - CLinkedListNode*FindLast(T value); - -private: - bool ValidateNode(CLinkedListNode*node); - bool ValidateNewNode(CLinkedListNode*node); - void InternalInsertNodeBefore(CLinkedListNode*node,CLinkedListNode*new_node); - void InternalInsertNodeToEmptyList(CLinkedListNode*new_node); - void InternalRemoveNode(CLinkedListNode*node); - }; -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CLinkedList class that is | -//| empty. | -//+------------------------------------------------------------------+ -template -CLinkedList::CLinkedList(void): m_count(0) - { - } -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CLinkedList class that | -//| contains elements copied from the specified array and has | -//| sufficient capacity to accommodate the number of elements copied.| -//+------------------------------------------------------------------+ -template -CLinkedList::CLinkedList(T &array[]): m_count(0) - { - for(int i=0; i class that | -//| contains elements copied from the specified collection and has | -//| sufficient capacity to accommodate the number of elements copied.| -//+------------------------------------------------------------------+ -template -CLinkedList::CLinkedList(ICollection*collection): m_count(0) - { -//--- check collection - if(CheckPointer(collection)!=POINTER_INVALID) - { - T array[]; - int size=collection.CopyTo(array,0); - for(int i=0; i -CLinkedList::~CLinkedList(void) - { - Clear(); - } -//+------------------------------------------------------------------+ -//| Adds an value to the end of the list. | -//+------------------------------------------------------------------+ -template -bool CLinkedList::Add(T value) - { - return(CheckPointer(AddLast(value))!=POINTER_INVALID); - } -//+------------------------------------------------------------------+ -//| Adds a new node containing the specified value after the | -//| specified existing node in the CLinkedList. | -//+------------------------------------------------------------------+ -template -CLinkedListNode*CLinkedList::AddAfter(CLinkedListNode*node,T value) - { -//--- check node - if(!ValidateNode(node)) - return(NULL); -//--- create new node - CLinkedListNode*result=new CLinkedListNode(node.List(),value); -//--- insert node to the list - InternalInsertNodeBefore(node.Next(),result); - return(result); - } -//+------------------------------------------------------------------+ -//| Adds the specified new node after the specified existing node in | -//| the LinkedList. | -//+------------------------------------------------------------------+ -template -bool CLinkedList::AddAfter(CLinkedListNode*node,CLinkedListNode*new_node) - { -//--- check node - if(!ValidateNode(node)) - return(false); -//--- check new node - if(!ValidateNewNode(new_node)) - return(false); -//--- insert node to the list - InternalInsertNodeBefore(node.Next(),new_node); -//--- set the current list as list for new node - new_node.List(GetPointer(this)); - return(true); - } -//+------------------------------------------------------------------+ -//| Adds a new node containing the specified value before the | -//| specified existing node in the CLinkedList. | -//+------------------------------------------------------------------+ -template -CLinkedListNode*CLinkedList::AddBefore(CLinkedListNode*node,T value) - { -//--- check node - if(!ValidateNode(node)) - return(NULL); -//--- create new node - CLinkedListNode*result=new CLinkedListNode(node.List(),value); -//--- insert node to the list - InternalInsertNodeBefore(node,result); - if(node==m_head) - m_head=result; - return(result); - } -//+------------------------------------------------------------------+ -//| Adds the specified new node before the specified existing node in| -//| the LinkedList. | -//+------------------------------------------------------------------+ -template -bool CLinkedList::AddBefore(CLinkedListNode*node,CLinkedListNode*new_node) - { -//--- check node - if(!ValidateNode(node)) - return(false); -//--- check new node - if(!ValidateNewNode(new_node)) - return(false); -//--- insert node to the list - InternalInsertNodeBefore(node,new_node); -//--- set the current list as list for new node - new_node.List(GetPointer(this)); - if(node==m_head) - m_head=new_node; - return(true); - } -//+------------------------------------------------------------------+ -//| Adds a new node containing the specified value at the start of | -//| the CLinkedList. | -//+------------------------------------------------------------------+ -template -CLinkedListNode*CLinkedList::AddFirst(T value) - { -//--- create new node - CLinkedListNode*node=new CLinkedListNode(GetPointer(this),value); -//--- check head node - if(CheckPointer(m_head)==POINTER_INVALID) - { - //--- insert node to the empty list - InternalInsertNodeToEmptyList(node); - } - else - { - //--- insert node to the list - InternalInsertNodeBefore(m_head,node); - m_head=node; - } - return(node); - } -//+------------------------------------------------------------------+ -//| Adds the specified new node at the start of the CLinkedList. | -//+------------------------------------------------------------------+ -template -bool CLinkedList::AddFirst(CLinkedListNode*node) - { -//--- check node - if(!ValidateNewNode(node)) - return(false); -//--- check head node - if(CheckPointer(m_head)==POINTER_INVALID) - { - //--- insert node to the empty list - InternalInsertNodeToEmptyList(node); - } - else - { - //--- insert node to the list - InternalInsertNodeBefore(m_head,node); - m_head=node; - } -//--- set the current list as list for node - node.List(GetPointer(this)); - return(true); - } -//+------------------------------------------------------------------+ -//| Adds a new node containing the specified value at the end of the | -//| CLinkedList. | -//+------------------------------------------------------------------+ -template -CLinkedListNode*CLinkedList::AddLast(T value) - { -//--- create new node - CLinkedListNode*node=new CLinkedListNode(GetPointer(this),value); -//--- check head node - if(CheckPointer(m_head)==POINTER_INVALID) - { - //--- insert node to the empty list - InternalInsertNodeToEmptyList(node); - } - else - { - //--- insert node to the list - InternalInsertNodeBefore(m_head,node); - } - return(node); - } -//+------------------------------------------------------------------+ -//| Adds the specified new node at the end of the CLinkedList. | -//+------------------------------------------------------------------+ -template -bool CLinkedList::AddLast(CLinkedListNode*node) - { -//--- check node - if(!ValidateNewNode(node)) - return(false); -//--- check head node - if(CheckPointer(m_head)==POINTER_INVALID) - { - //--- insert node to the empty list - InternalInsertNodeToEmptyList(node); - } - else - { - //--- insert node to the list - InternalInsertNodeBefore(m_head,node); - } -//--- set the current list as list for node - node.List(GetPointer(this)); - return(true); - } -//+------------------------------------------------------------------+ -//| Determines whether an element is in the linked list. | -//+------------------------------------------------------------------+ -template -int CLinkedList::Count(void) - { - return(m_count); - } -//+------------------------------------------------------------------+ -//| Gets the first node of the CLinkedList. | -//+------------------------------------------------------------------+ -template -CLinkedListNode*CLinkedList::First(void) - { - return(m_head); - } -//+------------------------------------------------------------------+ -//| Gets the last node of the CLinkedList. | -//+------------------------------------------------------------------+ -template -CLinkedListNode*CLinkedList::Last(void) - { - return(CheckPointer(m_head)!=POINTER_INVALID ? m_head.Previous() : NULL); - } -//+------------------------------------------------------------------+ -//| Determines whether a value is in the CLinkedList. | -//+------------------------------------------------------------------+ -template -bool CLinkedList::Contains(T item) - { - return(CheckPointer(Find(item))!=POINTER_INVALID); - } -//+------------------------------------------------------------------+ -//| Copies a range of elements from the linkedlist to a compatible | -//| one-dimensional array. | -//+------------------------------------------------------------------+ -template -int CLinkedList::CopyTo(T &dst_array[],const int dst_start=0) - { -//--- resize array - if(dst_start+m_count>ArraySize(dst_array)) - ArrayResize(dst_array,dst_start+m_count); -//--- check start index - if(dst_start>ArraySize(dst_array)) - return(0); -//--- start copy - CLinkedListNode*node=m_head; - if(CheckPointer(node)!=POINTER_INVALID) - { - int dst_index=dst_start; - do - { - dst_array[dst_index++]=node.Value(); - node=node.Next(); - } - while(dst_index. | -//+------------------------------------------------------------------+ -template -void CLinkedList::Clear(void) - { -//--- check count - if(m_count>0) - { - //--- check head node - if(CheckPointer(m_head)!=POINTER_INVALID) - { - while(m_head.Next()!=m_head) - { - CLinkedListNode*node=m_head.Next(); - m_head.Next(node.Next()); - delete node; - } - delete m_head; - } - //--- reset count - m_count=0; - } - } -//+------------------------------------------------------------------+ -//| Removes the first occurrence of the specified value from the | -//| CLinkedList. | -//+------------------------------------------------------------------+ -template -bool CLinkedList::Remove(T item) - { -//--- find node with specified value - CLinkedListNode*node=Find(item); - if(CheckPointer(node)!=POINTER_INVALID) - { - //--- remove node - InternalRemoveNode(node); - return(true); - } - return(false); - } -//+------------------------------------------------------------------+ -//| Removes the specified node from the LinkedList. | -//+------------------------------------------------------------------+ -template -bool CLinkedList::Remove(CLinkedListNode*node) - { -//--- check node - if(ValidateNode(node)) - { - //--- remove node - InternalRemoveNode(node); - return(true); - } - return(false); - } -//+------------------------------------------------------------------+ -//| Removes the node at the start of the CLinkedList. | -//+------------------------------------------------------------------+ -template -bool CLinkedList::RemoveFirst(void) - { -//--- check head node - if(CheckPointer(m_head)==POINTER_INVALID) - return(false); -//--- remove head node - InternalRemoveNode(m_head); - return(true); - } -//+------------------------------------------------------------------+ -//| Removes the node at the end of the CLinkedList. | -//+------------------------------------------------------------------+ -template -bool CLinkedList::RemoveLast(void) - { -//--- check head node - if(CheckPointer(m_head)==POINTER_INVALID) - return(false); -//--- remove last node - InternalRemoveNode(m_head.Previous()); - return(true); - } -//+------------------------------------------------------------------+ -//| Finds the first node that contains the specified value. | -//+------------------------------------------------------------------+ -template -CLinkedListNode*CLinkedList::Find(T value) - { - CLinkedListNode*node=m_head; -//--- start search specified value in the list - if(CheckPointer(node)!=POINTER_INVALID) - { - do - { - //--- use default equals function - if(::Equals(node.Value(),value)) - return(node); - node=node.Next(); - } - while(node!=m_head); - } - return(NULL); - } -//+------------------------------------------------------------------+ -//| Finds the last node that contains the specified value. | -//+------------------------------------------------------------------+ -template -CLinkedListNode*CLinkedList::FindLast(T value) - { -//--- check head node - if(CheckPointer(m_head)==POINTER_INVALID) - return(NULL); -//--- get last node - CLinkedListNode *last = m_head.Previous(); - CLinkedListNode *node = last; -//--- start search from the end of the list - if(node!=NULL) - { - do - { - //--- use default equals function - if(::Equals(node.Value(),value)) - return(node); - node=node.Previous(); - } - while(node!=last); - } - return(NULL); - } -//+------------------------------------------------------------------+ -//| Validation of node on not null and belongs in the current list. | -//+------------------------------------------------------------------+ -template -bool CLinkedList::ValidateNode(CLinkedListNode*node) - { - return(CheckPointer(node)!=POINTER_INVALID && node.List()==GetPointer(this)); - } -//+------------------------------------------------------------------+ -//| Validation of new node on not null. | -//+------------------------------------------------------------------+ -template -bool CLinkedList::ValidateNewNode(CLinkedListNode*node) - { - return(CheckPointer(node)!=POINTER_INVALID && node.List()==NULL); - } -//+------------------------------------------------------------------+ -//| Insert node before the specified node. | -//+------------------------------------------------------------------+ -template -void CLinkedList::InternalInsertNodeBefore(CLinkedListNode*node,CLinkedListNode*new_node) - { -//--- set node befor the specified node - new_node.Next(node); - new_node.Previous(node.Previous()); - node.Previous().Next(new_node); - node.Previous(new_node); -//--- increment count - m_count++; - } -//+------------------------------------------------------------------+ -//| Add first node to the list. | -//+------------------------------------------------------------------+ -template -void CLinkedList::InternalInsertNodeToEmptyList(CLinkedListNode*new_node) - { -//--- set node as head of the list - new_node.Next(new_node); - new_node.Previous(new_node); - m_head=new_node; -//--- increment count - m_count++; - } -//+------------------------------------------------------------------+ -//| Remove specified node from the list. | -//+------------------------------------------------------------------+ -template -void CLinkedList::InternalRemoveNode(CLinkedListNode*node) - { -//--- check node - if(node.Next()==node) - { - //--- resets the head of the list - m_head=NULL; - } - else - { - //--- detach node from the list - node.Next().Previous(node.Previous()); - node.Previous().Next(node.Next()); - if(m_head==node) - m_head=node.Next(); - } -//--- decrement count and delete node - m_count--; - delete node; - } -//+------------------------------------------------------------------+ diff --git a/Include/Generic/Queue.mqh b/Include/Generic/Queue.mqh deleted file mode 100644 index 5b95f45388592cba66bf1d8c86a628bcdcd41399..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23370 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 L!te(+Q=k4n#Pe)) diff --git a/Include/Generic/SortedMap.mqh b/Include/Generic/SortedMap.mqh deleted file mode 100644 index 170a530..0000000 --- a/Include/Generic/SortedMap.mqh +++ /dev/null @@ -1,341 +0,0 @@ -//+------------------------------------------------------------------+ -//| SortedMap.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include -#include -#include -#include -#include "HashMap.mqh" -#include "SortedSet.mqh" -//+------------------------------------------------------------------+ -//| Class CSortedMap. | -//| Usage: Represents a collection of key/value pairs that are sorted| -//| on the key. | -//+------------------------------------------------------------------+ -template -class CSortedMap: public IMap - { -protected: - CRedBlackTree*>*m_tree; - IComparer*m_comparer; - bool m_delete_comparer; - -public: - CSortedMap(void); - CSortedMap(IComparer*comparer); - CSortedMap(IMap*map); - CSortedMap(IMap*map,IComparer*comparer); - ~CSortedMap(void); - //--- methods of filling data - bool Add(CKeyValuePair*value) { return m_tree.Add(value); } - bool Add(TKey key,TValue value); - //--- methods of access to protected data - int Count(void) { return m_tree.Count(); } - bool Contains(CKeyValuePair*item) { return m_tree.Contains(item); } - bool Contains(TKey key,TValue value); - bool ContainsKey(TKey key); - bool ContainsValue(TValue value); - IComparer *Comparer(void) const { return(m_comparer); } - //--- methods of copy data from collection - int CopyTo(CKeyValuePair*&dst_array[],const int dst_start=0); - int CopyTo(TKey &dst_keys[],TValue &dst_values[],const int dst_start=0); - //--- methods of cleaning and deleting - void Clear(void); - bool Remove(CKeyValuePair*item) { return m_tree.Remove(item); } - bool Remove(TKey key); - //--- method of access to the data - bool TryGetValue(TKey key,TValue &value); - bool TrySetValue(TKey key,TValue value); - -private: - static void ClearNodes(CRedBlackTreeNode*>*node); - }; -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CSortedMap class | -//| that is empty, has the default initial capacity, and uses the | -//| default comparer for the key type. | -//+------------------------------------------------------------------+ -template -CSortedMap::CSortedMap(void) - { -//--- use default comaprer - m_comparer=new CDefaultComparer(); - m_delete_comparer=true; - m_tree=new CRedBlackTree*>(new CKeyValuePairComparer(m_comparer)); - } -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CSortedMap class | -//| that is empty, has the default initial capacity, and uses the | -//| specified IComparer. | -//+------------------------------------------------------------------+ -template -CSortedMap::CSortedMap(IComparer*comparer) - { -//--- check comaprer - if(CheckPointer(comparer)==POINTER_INVALID) - { - //--- use default comaprer - m_comparer=new CDefaultComparer(); - m_delete_comparer=true; - } - else - { - //--- use specified comaprer - m_comparer=comparer; - m_delete_comparer=false; - } - m_tree=new CRedBlackTree*>(new CKeyValuePairComparer(m_comparer)); - } -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CSortedMap class | -//| that contains elements copied from the specified | -//| IMap and uses the default comparer for the key type.| -//+------------------------------------------------------------------+ -template -CSortedMap::CSortedMap(IMap*map) - { -//--- use default comaprer - m_comparer=new CDefaultComparer(); - m_delete_comparer=true; - m_tree=new CRedBlackTree*>(map,new CKeyValuePairComparer(m_comparer)); - } -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CSortedMap class | -//| that contains elements copied from the specified | -//| IMap and uses the specified IComparer. | -//+------------------------------------------------------------------+ -template -CSortedMap::CSortedMap(IMap*map,IComparer*comparer) - { -//--- check comaprer - if(CheckPointer(comparer)==POINTER_INVALID) - { - //--- use default comaprer - m_comparer=new CDefaultComparer(); - m_delete_comparer=true; - } - else - { - //--- use specified comaprer - m_comparer=comparer; - m_delete_comparer=false; - } - m_tree=new CRedBlackTree*>(map,new CKeyValuePairComparer(m_comparer)); - } -//+------------------------------------------------------------------+ -//| Destructor. | -//+------------------------------------------------------------------+ -template -CSortedMap::~CSortedMap(void) - { -//--- delete comparer - if(m_delete_comparer) - delete m_comparer; -//--- delete tree comparer - delete m_tree.Comparer(); -//--- delete nodes values - ClearNodes(m_tree.Root()); -//--- delete tree and nodes - delete m_tree; - } -//+------------------------------------------------------------------+ -//| Walk all nodes of tree and delete their value. | -//+------------------------------------------------------------------+ -template -static void CSortedMap::ClearNodes(CRedBlackTreeNode*>*node) - { -//--- check node - if(CheckPointer(node)==POINTER_INVALID) - return; -//--- walk of a right subtree - if(!node.Right().IsLeaf()) - ClearNodes(node.Right()); -//--- delete value - delete node.Value(); -//--- walk of a left subtree - if(!node.Left().IsLeaf()) - ClearNodes(node.Left()); - } -//+------------------------------------------------------------------+ -//| Adds the specified key and value to the map. | -//+------------------------------------------------------------------+ -template -bool CSortedMap::Add(TKey key,TValue value) - { -//--- create pair - CKeyValuePair*pair=new CKeyValuePair(key,value); -//--- add pair to tree - bool success=m_tree.Add(pair); -//--- if addition was not successful delte pair - if(!success) - delete pair; - return(success); - } -//+------------------------------------------------------------------+ -//| Determines whether the map contains the specified key with value.| -//+------------------------------------------------------------------+ -template -bool CSortedMap::Contains(TKey key,TValue value) - { -//--- find node with specified key - CKeyValuePairpair(key,NULL); - CRedBlackTreeNode*>*node=m_tree.Find(GetPointer(pair)); -//--- create value comparer - CDefaultEqualityComparercomaprer; -//--- determine whether the finding node contains specified value - if(CheckPointer(node)!=POINTER_INVALID && comaprer.Equals(value,node.Value().Value())) - return(true); - return(false); - } -//+------------------------------------------------------------------+ -//| Determines whether the map contains the specified key. | -//+------------------------------------------------------------------+ -template -bool CSortedMap::ContainsKey(TKey key) - { -//--- crete pair - CKeyValuePairpair(key,NULL); -//--- determines whether the tree contains the pair. - return m_tree.Contains(GetPointer(pair)); - } -//+------------------------------------------------------------------+ -//| Determines whether the map contains the specified value. | -//+------------------------------------------------------------------+ -template -bool CSortedMap::ContainsValue(TValue value) - { -//--- copy all pairs in array - CKeyValuePair*array[]; - int count=m_tree.CopyTo(array); -//--- create value comparer - CDefaultEqualityComparercomaprer; -//--- determines whether the array contains the specified value - for(int i=0; i -int CSortedMap::CopyTo(CKeyValuePair*&dst_array[],const int dst_start=0) - { - int result=m_tree.CopyTo(dst_array,dst_start); - if(result>0) - { - //--- create clones for each pair - for(int i=0; i -int CSortedMap::CopyTo(TKey &dst_keys[],TValue &dst_values[],const int dst_start=0) - { -//--- create array and copy all values from tree to there - CKeyValuePair*array[]; - int count=m_tree.CopyTo(array); -//--- check real cout - if(count>0) - { - //--- resize keys array - if(dst_start+count>ArraySize(dst_keys)) - ArrayResize(dst_keys,dst_start+count); - //--- resize values array - if(dst_start+count>ArraySize(dst_values)) - ArrayResize(dst_values,MathMin(ArraySize(dst_keys),dst_start+count)); - //--- start copy - int index=0; - while(index -void CSortedMap::Clear(void) - { -//--- check count - if(m_tree.Count()>0) - { - //--- delete nodes values - ClearNodes(m_tree.Root()); - //--- claer th tree - m_tree.Clear(); - } - } -//+------------------------------------------------------------------+ -//| Removes the value with the specified key from the map. | -//+------------------------------------------------------------------+ -template -bool CSortedMap::Remove(TKey key) - { -//--- create pair with specified key - CKeyValuePairpair(key,NULL); -//--- find node - CRedBlackTreeNode*>*node=m_tree.Find(GetPointer(pair)); -//--- check node - if(CheckPointer(node)!=POINTER_INVALID) - { - CKeyValuePair*real_pair=node.Value(); - //--- remove node from tree - if(m_tree.Remove(node)) - { - //--- check and delete node value - if(CheckPointer(real_pair)==POINTER_DYNAMIC) - delete real_pair; - return(true); - } - } - return(false); - } -//+------------------------------------------------------------------+ -//| Gets the value associated with the specified key. | -//+------------------------------------------------------------------+ -template -bool CSortedMap::TryGetValue(TKey key,TValue &value) - { -//--- create pair with specified key - CKeyValuePairpair(key,NULL); -//--- find node with specified pair in the tree - CRedBlackTreeNode*>*node=m_tree.Find(GetPointer(pair)); -//--- check node - if(CheckPointer(node)==POINTER_INVALID) - return(false); -//--- get value - value=node.Value().Value(); - return(true); - } -//+------------------------------------------------------------------+ -//| Sets the value associated with the specified key. | -//+------------------------------------------------------------------+ -template -bool CSortedMap::TrySetValue(TKey key,TValue value) - { -//--- create pair with specified key - CKeyValuePairpair(key,NULL); -//--- find node with specified pair in the tree - CRedBlackTreeNode*>*node=m_tree.Find(GetPointer(pair)); -//--- check node - if(CheckPointer(node)==POINTER_INVALID) - return(false); -//--- set value - node.Value().Value(value); - return(true); - } -//+------------------------------------------------------------------+ diff --git a/Include/Generic/SortedSet.mqh b/Include/Generic/SortedSet.mqh deleted file mode 100644 index 9df8d27..0000000 --- a/Include/Generic/SortedSet.mqh +++ /dev/null @@ -1,673 +0,0 @@ -//+------------------------------------------------------------------+ -//| SortedList.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include -#include -#include "RedBlackTree.mqh" -#include "HashSet.mqh" -//+------------------------------------------------------------------+ -//| Class CSortedSet. | -//| Usage: Represents a collection of objects that is maintained in | -//| sorted order. | -//+------------------------------------------------------------------+ -template -class CSortedSet: public ISet - { -protected: - CRedBlackTree*m_tree; - -public: - CSortedSet(void); - CSortedSet(IComparer*comparer); - CSortedSet(ICollection*collection); - CSortedSet(ICollection*collection,IComparer*comparer); - CSortedSet(T &array[]); - CSortedSet(T &array[],IComparer*comparer); - ~CSortedSet(void); - //--- methods of filling data - bool Add(T value) { return(m_tree.Add(value)); } - //--- methods of access to protected data - int Count(void) { return(m_tree.Count()); } - bool Contains(T item) { return(m_tree.Contains(item)); } - IComparer *Comparer(void) const { return(m_tree.Comparer()); } - bool TryGetMin(T &min) { return(m_tree.TryGetMin(min)); } - bool TryGetMax(T &max) { return(m_tree.TryGetMax(max)); } - //--- methods of copy data from collection - int CopyTo(T &dst_array[],const int dst_start=0); - //--- methods of cleaning and deleting - void Clear(void) { m_tree.Clear(); } - bool Remove(T item) { return(m_tree.Remove(item)); } - //--- methods of changing sets - void ExceptWith(ICollection*collection); - void ExceptWith(T &array[]); - void IntersectWith(ICollection*collection); - void IntersectWith(T &array[]); - void SymmetricExceptWith(ICollection*collection); - void SymmetricExceptWith(T &array[]); - void UnionWith(ICollection*collection); - void UnionWith(T &array[]); - //--- methods for determining the relationship between sets - bool IsProperSubsetOf(ICollection*collection); - bool IsProperSubsetOf(T &array[]); - bool IsProperSupersetOf(ICollection*collection); - bool IsProperSupersetOf(T &array[]); - bool IsSubsetOf(ICollection*collection); - bool IsSubsetOf(T &array[]); - bool IsSupersetOf(ICollection*collection); - bool IsSupersetOf(T &array[]); - bool Overlaps(ICollection*collection); - bool Overlaps(T &array[]); - bool SetEquals(ICollection*collection); - bool SetEquals(T &array[]); - //--- methods for working with an ordered set - bool GetViewBetween(T &array[],T lower_value,T upper_value); - bool GetReverse(T &array[]); - }; -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CSortedSet class that is | -//| empty and uses the default equality comparer for the set type. | -//+------------------------------------------------------------------+ -template -CSortedSet::CSortedSet(void) - { - m_tree=new CRedBlackTree(); - } -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CSortedSet class that is | -//| empty and uses the specified equality comparer for the set type. | -//+------------------------------------------------------------------+ -template -CSortedSet::CSortedSet(IComparer*comparer) - { - m_tree=new CRedBlackTree(comparer); - } -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CSortedSet class that uses | -//| the default equality comparer for the set type, contains elements| -//| copied from the specified collection, and has sufficient capacity| -//| to accommodate the number of elements copied. | -//+------------------------------------------------------------------+ -template -CSortedSet::CSortedSet(ICollection*collection) - { - m_tree=new CRedBlackTree(collection); - } -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CSortedSet class that uses | -//| the specified equality comparer for the set type, contains | -//| elements copied from the specified collection, and has sufficient| -//| capacity to accommodate the number of elements copied. | -//+------------------------------------------------------------------+ -template -CSortedSet::CSortedSet(ICollection*collection,IComparer*comparer) - { - m_tree=new CRedBlackTree(collection,comparer); - } -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CSortedSet class that uses | -//| the default equality comparer for the set type, contains | -//| elements copied from the specified array, and has sufficient | -//| capacity to accommodate the number of elements copied. | -//+------------------------------------------------------------------+ -template -CSortedSet::CSortedSet(T &array[]) - { - m_tree=new CRedBlackTree(array); - } -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CSortedSet class that uses | -//| the specified equality comparer for the set type, contains | -//| elements copied from the specified array, and has sufficient | -//| capacity to accommodate the number of elements copied. | -//+------------------------------------------------------------------+ -template -CSortedSet::CSortedSet(T &array[],IComparer*comparer) - { - m_tree=new CRedBlackTree(array,comparer); - } -//+------------------------------------------------------------------+ -//| Destructor. | -//+------------------------------------------------------------------+ -template -CSortedSet::~CSortedSet(void) - { - delete m_tree; - } -//+------------------------------------------------------------------+ -//| Copies a range of elements from the set to a compatible | -//| one-dimensional array. | -//+------------------------------------------------------------------+ -template -int CSortedSet::CopyTo(T &dst_array[],const int dst_start=0) - { - return(m_tree.CopyTo(dst_array, dst_start)); - } -//+------------------------------------------------------------------+ -//| Removes all elements in the specified collection from the current| -//| set. | -//+------------------------------------------------------------------+ -template -void CSortedSet::ExceptWith(ICollection*collection) - { -//--- check collection - if(CheckPointer(collection)==POINTER_INVALID) - return; -//--- check tree count - if(m_tree.Count()==0) - return; -//--- special case if collection is this -//--- a set minus itself is the empty set - if(collection==GetPointer(this)) - { - Clear(); - return; - } -//--- copy collection to array - T array[]; - int size=collection.CopyTo(array); -//--- find max and min value - T max; - T min; -//--- get comaprer - IComparer*comparer=Comparer(); - if(!m_tree.TryGetMax(max)) - return; - if(!m_tree.TryGetMin(min)) - return; -//--- remove elements - for(int i=0; i0) && Contains(item)) - m_tree.Remove(item); - } - } -//+------------------------------------------------------------------+ -//| Removes all elements in the specified array from the current set.| -//+------------------------------------------------------------------+ -template -void CSortedSet::ExceptWith(T &array[]) - { -//--- check tree count - if(m_tree.Count()==0) - return; -//--- get array size - int size=ArraySize(array); -//--- find max and min value - T max; - T min; -//--- get comparer - IComparer*comparer=Comparer(); - if(!m_tree.TryGetMax(max)) - return; - if(!m_tree.TryGetMin(min)) - return; -//--- remove elements - for(int i=0; i0) && Contains(item)) - m_tree.Remove(item); - } - } -//+------------------------------------------------------------------+ -//| Modifies the current set to contain only elements that are | -//| present in that object and in the specified collection. | -//+------------------------------------------------------------------+ -template -void CSortedSet::IntersectWith(ICollection*collection) - { -//--- check collection - if(CheckPointer(collection)==POINTER_INVALID) - return; -//--- check tree count - if(m_tree.Count()==0) - return; -//--- special case if collection is this -//--- a set minus itself is the empty set - if(collection==GetPointer(this)) - return; -//--- copy collection to array - T array[]; - int size=collection.CopyTo(array); -//--- create emty tree - CRedBlackTree*tree=new CRedBlackTree(); -//--- store values conatin in tree and array - for(int i=0; i -void CSortedSet::IntersectWith(T &array[]) - { -//--- check tree count - if(m_tree.Count()==0) - return; -//--- get array size - int size=ArraySize(array); -//--- create emty tree - CRedBlackTree*tree=new CRedBlackTree(); -//--- store values conatin in tree and array - for(int i=0; i -void CSortedSet::SymmetricExceptWith(ICollection*collection) - { -//--- check collection - if(CheckPointer(collection)==POINTER_INVALID) - return; -//--- check collection count - if(collection.Count()==0) - return; -//--- check tree count - if(m_tree.Count()==0) - { - UnionWith(collection); - return; - } -//--- special case if collection is this -//--- a set minus itself is the empty set - if(collection==GetPointer(this)) - { - Clear(); - return; - } -//--- copy colleaction to array - T array[]; - int size=collection.CopyTo(array); -//--- get comparer - IComparer*comparer=m_tree.Comparer(); -//--- sort array - Introsortsort; - ArrayCopy(sort.keys,array); - sort.comparer=comparer; - sort.Sort(0, size); - ArrayCopy(array,sort.keys); -//--- modify tree - T last=array[0]; - for(int i=0; i=size) - break; - - if(m_tree.Contains(array[i])) - m_tree.Remove(array[i]); - else - m_tree.Add(array[i]); - - last=array[i]; - } - } -//+------------------------------------------------------------------+ -//| Modifies the current set to contain only elements that are | -//| present either in that set or in the specified array, but not | -//| both. | -//+------------------------------------------------------------------+ -template -void CSortedSet::SymmetricExceptWith(T &array[]) - { -//--- check array size - if(ArraySize(array)==0) - return; -//--- check tree count - if(m_tree.Count()==0) - { - UnionWith(array); - return; - } -//--- get size - int size=ArraySize(array); -//--- get comparer - IComparer*comparer=m_tree.Comparer(); -//--- sort array - Introsortsort; - ArrayCopy(sort.keys,array); - sort.comparer=comparer; - sort.Sort(0, size); - ArrayReverse(sort.keys,0,ArraySize(sort.keys)); -//--- modify tree - T last=sort.keys[0]; - for(int i=0; i=size) - break; - - if(m_tree.Contains(sort.keys[i])) - m_tree.Remove(sort.keys[i]); - else - m_tree.Add(sort.keys[i]); - - last=sort.keys[i]; - } - } -//+------------------------------------------------------------------+ -//| Modifies the current set to contain all elements that are present| -//| in itself, the specified collection, or both. | -//+------------------------------------------------------------------+ -template -void CSortedSet::UnionWith(ICollection*collection) - { -//--- check collection - if(CheckPointer(collection)==POINTER_INVALID) - return; -//--- copy all elements from collecton to array - T array[]; - int size=collection.CopyTo(array); -//--- add all elemets from array to set - for(int i=0; i -void CSortedSet::UnionWith(T &array[]) - { -//--- get array size - int size=ArraySize(array); -//--- add all elemets from array to set - for(int i=0; i -bool CSortedSet::IsProperSubsetOf(ICollection*collection) - { -//--- check collection - if(CheckPointer(collection)==POINTER_INVALID) - return(false); -//--- check tree count - if(m_tree.Count()==0) - return(collection.Count() > 0); -//--- check collection is set - CHashSet*ptr_set=dynamic_cast*>(collection); - if(CheckPointer(ptr_set)!=POINTER_INVALID) - { - return(ptr_set.IsProperSupersetOf(m_tree)); - } - else - { - //--- create a set based on a specified collection - CHashSetset(collection); - return(set.IsProperSupersetOf(m_tree)); - } - } -//+------------------------------------------------------------------+ -//| Determines whether a set is a proper subset of the specified | -//| array. | -//+------------------------------------------------------------------+ -template -bool CSortedSet::IsProperSubsetOf(T &array[]) - { - if(m_tree.Count()==0) - return(ArraySize(array) > 0); -//--- create a set based on a specified array - CHashSetset(array); - if(m_tree.Count()>=set.Count()) - return(false); - return(set.IsProperSupersetOf(m_tree)); - } -//+------------------------------------------------------------------+ -//| Determines whether a set is a proper superset of the specified | -//| collection. | -//+------------------------------------------------------------------+ -template -bool CSortedSet::IsProperSupersetOf(ICollection*collection) - { -//--- check collection - if(CheckPointer(collection)==POINTER_INVALID) - return(m_tree.Count()>0); -//--- check tree count - if(m_tree.Count()==0) - return(false); -//--- check collection count - if(collection.Count()==0) - return(true); -//--- check collection is set - CHashSet*ptr_set=dynamic_cast*>(collection); - if(CheckPointer(ptr_set)!=POINTER_INVALID) - { - return(ptr_set.IsProperSubsetOf(m_tree)); - } - else - { - //--- create a set based on a specified collection - CHashSetset(collection); - return(set.IsProperSubsetOf(m_tree)); - } - } -//+------------------------------------------------------------------+ -//| Determines whether a set is a proper superset of the specified | -//| array. | -//+------------------------------------------------------------------+ -template -bool CSortedSet::IsProperSupersetOf(T &array[]) - { - if(m_tree.Count()==0) - return(false); - if(ArraySize(array)==0) - return(true); -//--- create a set based on a specified array - CHashSetset(array); - return(set.IsProperSubsetOf(m_tree)); - } -//+------------------------------------------------------------------+ -//| Determines whether a set is a subset of the specified collection.| -//+------------------------------------------------------------------+ -template -bool CSortedSet::IsSubsetOf(ICollection*collection) - { -//--- cehck collection - if(CheckPointer(collection)==POINTER_INVALID) - return(m_tree.Count()==0); -//--- check tree count - if(m_tree.Count()==0) - return(true); -//--- check collection is set - CHashSet*ptr_set=dynamic_cast*>(collection); - if(CheckPointer(ptr_set)==POINTER_DYNAMIC) - { - return(ptr_set.IsProperSupersetOf(m_tree)); - } - else - { - //--- create a set based on a specified collection - CHashSetset(collection); - return(set.IsProperSupersetOf(m_tree)); - } - } -//+------------------------------------------------------------------+ -//| Determines whether a set is a subset of the specified array. | -//+------------------------------------------------------------------+ -template -bool CSortedSet::IsSubsetOf(T &array[]) - { -//--- check tree count - if(m_tree.Count()==0) - return(true); -//--- create a set based on a specified array - CHashSetset(array); - if(m_tree.Count()>set.Count()) - return(false); - return(set.IsProperSupersetOf(m_tree)); - } -//+------------------------------------------------------------------+ -//| Determines whether a set is a superset of the specified | -//| collection. | -//+------------------------------------------------------------------+ -template -bool CSortedSet::IsSupersetOf(ICollection*collection) - { -//--- check collection - if(CheckPointer(collection)==POINTER_INVALID) - return(m_tree.Count()>=0); -//--- check collection count - if(collection.Count()==0) - return(true); -//--- check collection is set - CHashSet*ptr_set=dynamic_cast*>(collection); - if(CheckPointer(ptr_set)!=POINTER_INVALID) - { - return(ptr_set.IsSupersetOf(m_tree)); - } - else - { - //--- create a set based on a specified collection - CHashSetset(collection); - return(set.IsSupersetOf(m_tree)); - } - } -//+------------------------------------------------------------------+ -//| Determines whether a set is a superset of the specified array. | -//+------------------------------------------------------------------+ -template -bool CSortedSet::IsSupersetOf(T &array[]) - { -//--- check array size - if(ArraySize(array)==0) - return(true); -//--- create a set based on a specified array - CHashSetset(array); - return(set.IsSupersetOf(m_tree)); - } -//+------------------------------------------------------------------+ -//| Determines whether the current set and a specified collection | -//| share common elements. | -//+------------------------------------------------------------------+ -template -bool CSortedSet::Overlaps(ICollection*collection) - { -//--- check collection - if(CheckPointer(collection)==POINTER_INVALID) - return(false); -//--- check tree count - if(m_tree.Count()==0) - return(false); -//--- check collection count - if(collection.Count()==0) - return(false); -//--- check collection is set - CHashSet*ptr_set=dynamic_cast*>(collection); - if(CheckPointer(ptr_set)!=POINTER_INVALID) - { - return(ptr_set.Overlaps(m_tree)); - } - else - { - //--- create a set based on a specified collection - CHashSetset(collection); - return(set.Overlaps(m_tree)); - } - } -//+------------------------------------------------------------------+ -//| Determines whether the current set and a specified array share | -//| common elements. | -//+------------------------------------------------------------------+ -template -bool CSortedSet::Overlaps(T &array[]) - { -//--- check tree count - if(m_tree.Count()==0) - return(false); -//--- check array size - if(ArraySize(array)==0) - return(false); -//--- convert array to set - CHashSetset(array); - return(set.Overlaps(m_tree)); - } -//+------------------------------------------------------------------+ -//| Determines whether a set and the specified collection contain the| -//| same elements. | -//+------------------------------------------------------------------+ -template -bool CSortedSet::SetEquals(ICollection*collection) - { - if(CheckPointer(collection)==POINTER_INVALID) - return(false); -//--- get array from collection - T array[]; - collection.CopyTo(array); -//--- check current set is equal specified array - return SetEquals(array); - } -//+------------------------------------------------------------------+ -//| Determines whether a set and the specified array contain the same| -//| elements. | -//+------------------------------------------------------------------+ -template -bool CSortedSet::SetEquals(T &array[]) - { -//--- try find all elements in the tree - for(int i=0; i to array. | -//+------------------------------------------------------------------+ -template -bool CSortedSet::GetViewBetween(T &array[],T lower_value,T upper_value) - { -//--- get comparer - IComparer*comparer=m_tree.Comparer(); - if(comparer.Compare(lower_value,upper_value)>0) - return(false); -//--- copy all element from tree to array - T buff[]; - int size=m_tree.CopyTo(buff); -//--- check range - if(size==0 || comparer.Compare(buff[0],upper_value)>0 || comparer.Compare(buff[size-1],lower_value)<0) - return(false); -//--- find first element greater than lower_value - int index_lower=0; - while(index_lower0 && comparer.Compare(buff[index_upper],upper_value)>0) - index_upper--; -//--- check indices - if(index_lower>index_upper) - return(false); -//--- copy view between lower_value and upper_value to array - return(ArrayCopy(array,buff,0,index_lower,index_upper-index_lower+1)>=0); - } -//+------------------------------------------------------------------+ -//| Copy the CSortedSet in reverse order to array. | -//+------------------------------------------------------------------+ -template -bool CSortedSet::GetReverse(T &array[]) - { - int size=m_tree.CopyTo(array); - return ArrayReverse(array,0,size); - } -//+------------------------------------------------------------------+ diff --git a/Include/Generic/Stack.mqh b/Include/Generic/Stack.mqh deleted file mode 100644 index 1d3d54a..0000000 --- a/Include/Generic/Stack.mqh +++ /dev/null @@ -1,227 +0,0 @@ -//+------------------------------------------------------------------+ -//| Stack.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include -#include -#include -//+------------------------------------------------------------------+ -//| Class CStack. | -//| Usage: Represents a variable size last-in-first-out (LIFO) | -//| collection of instances of the same specified type. | -//+------------------------------------------------------------------+ -template -class CStack: public ICollection - { -protected: - T m_array[]; - int m_size; - const int m_default_capacity; - -public: - CStack(void); - CStack(const int capacity); - CStack(ICollection&collection[]); - CStack(T &array[]); - ~CStack(void); - //--- methods of filling data - bool Add(T value); - bool Push(T value); - //--- methods of access to protected data - int Count(void); - bool Contains(T item); - void TrimExcess(void); - //--- methods of copy data from collection - int CopyTo(T &dst_array[],const int dst_start=0); - //--- methods of cleaning and removing - void Clear(void); - bool Remove(T item); - //--- methods of access to protected data - T Peek(void); - T Pop(void); - }; -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CStack class that is empty | -//| and has the default initial capacity. | -//+------------------------------------------------------------------+ -template -CStack::CStack(void): m_default_capacity(4), - m_size(0) - { - } -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CStack class that is empty | -//| and has the specified initial capacity or the default initial | -//| capacity, whichever is greater. | -//+------------------------------------------------------------------+ -template -CStack::CStack(const int capacity): m_default_capacity(4), - m_size(0) - { - ArrayResize(m_array,capacity); - } -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CStack class that contains | -//| elements copied from the specified array and has sufficient | -//| capacity to accommodate the number of elements copied. | -//+------------------------------------------------------------------+ -template -CStack::CStack(T &array[]): m_default_capacity(4), - m_size(0) - { - m_size=ArrayCopy(m_array,array); - } -//+------------------------------------------------------------------+ -//| Initializes a new instance of the CStack class that contains | -//| elements copied from the specified collection and has sufficient | -//| capacity to accommodate the number of elements copied. | -//+------------------------------------------------------------------+ -template -CStack::CStack(ICollection*collection): m_default_capacity(4), - m_size(0) - { -//--- check collection - if(CheckPointer(collection)!=POINTER_INVALID) - m_size=collection.CopyTo(m_array,0); - } -//+------------------------------------------------------------------+ -//| Destructor. | -//+------------------------------------------------------------------+ -template -CStack::~CStack(void) - { - } -//+------------------------------------------------------------------+ -//| Inserts an value at the top of the CStack. | -//+------------------------------------------------------------------+ -template -bool CStack::Add(T value) - { - return Push(value); - } -//+------------------------------------------------------------------+ -//| Gets the number of elements. | -//+------------------------------------------------------------------+ -template -int CStack::Count(void) - { - return(m_size); - } -//+------------------------------------------------------------------+ -//| Removes all values from the CStack. | -//+------------------------------------------------------------------+ -template -bool CStack::Contains(T item) - { - int count=m_size; -//--- try to find item in array - while(count-->0) - { - //--- use default equality function - if(::Equals(m_array[count],item)) - return(true); - } - return(false); - } -//+------------------------------------------------------------------+ -//| Copies a range of elements from the stack to a compatible | -//| one-dimensional array. | -//+------------------------------------------------------------------+ -template -int CStack::CopyTo(T &dst_array[],const int dst_start=0) - { -//--- resize array - if(dst_start+m_size>ArraySize(dst_array)) - ArrayResize(dst_array,dst_start+m_size); -//--- start copy - int src_index = m_size-1; - int dst_index = dst_start; - while(src_index>=0 && dst_index. | -//+------------------------------------------------------------------+ -template -void CStack::Clear(void) - { -//--- check current size - if(m_size>0) - { - ZeroMemory(m_array); - m_size=0; - } - } -//+------------------------------------------------------------------+ -//| Removes the first occurrence of a specific value from the stack. | -//+------------------------------------------------------------------+ -template -bool CStack::Remove(T item) - { -//--- find index of item - int index=ArrayIndexOf(m_array,item,0,m_size); -//--- check index - if(index==-1) - return(false); -//--- shift the values to the left - ArrayCopy(m_array,m_array,index,index+1); -//--- decrement size - m_size--; - return(true); - } -//+------------------------------------------------------------------+ -//| Inserts an values at the top of the CStack. | -//+------------------------------------------------------------------+ -template -bool CStack::Push(T value) - { - int size=ArraySize(m_array); -//--- check array size - if(m_size==size) - { - //--- increase capacity - if(size==0) - ArrayResize(m_array,m_default_capacity); - else - ArrayResize(m_array,2*size); - } -//--- add value to the end - m_array[m_size++]=value; - return(true); - } -//+------------------------------------------------------------------+ -//| Returns the value at the top of the CStack without removing. | -//+------------------------------------------------------------------+ -template -T CStack::Peek(void) - { -//--- return last value - return(m_array[m_size-1]); - } -//+------------------------------------------------------------------+ -//| Removes and returns the value at the top of the CStack. | -//+------------------------------------------------------------------+ -template -T CStack::Pop(void) - { -//--- return last value and decrement size - T item=m_array[--m_size]; - return(item); - } -//+------------------------------------------------------------------+ -//| Sets the capacity to the actual number of elements in the | -//| CStack, if that number is less than 90 percent of current | -//| capacity. | -//+------------------------------------------------------------------+ -template -void CStack::TrimExcess(void) - { -//--- calculate threshold value - int threshold=(int)(((double)ArraySize(m_array)*0.9)); -//--- calculate resize array - if(m_sizem_max) - m_max=m_min; - if(!m_auto_scale) - { - if(m_max<=m_min) - ExtensionBoundaries(); - m_step=((m_max-m_min)>m_default_step && m_default_step>0) ? m_default_step : m_max-m_min; - return; - } - ExtensionBoundaries(); -//--- test for trivial condition of range = 0 and pick a suitable default - if(m_max-m_min<1.0e-30) - { - m_max=m_max+0.2 *(m_max==0 ? 1.0 : MathAbs(m_max)); - m_min=m_min-0.2 *(m_min==0 ? 1.0 : MathAbs(m_min)); - } -//--- this is the zero-lever test. If m_min is within the zero lever fraction of the data range,then use zero. - if(m_min>0 && m_min/(m_max-m_min)0) - m_step=CalcBoundedStepSize(m_max-m_min,m_max_labels); - else - m_step=CalcBoundedStepSize(m_max-m_min,labels); -//--- calculate the scale minimum - m_min=m_min-Mod(m_min,m_step); -//--- calculate the scale maximum - m_max=Mod(m_max,m_step)==0.0 ? m_max : m_max+m_step-Mod(m_max,m_step); - } -//+------------------------------------------------------------------+ -//| Expands the boundaries to the left and right. | -//+------------------------------------------------------------------+ -void CAxis::ExtensionBoundaries(void) - { - double range=m_max-m_min; -//--- do not let the grace value extend the axis below zero when all the values were positive - if(m_min<0 || m_min-m_min_grace*range>=0.0) - m_min=m_min-m_min_grace*range; -//--- do not let the grace value extend the axis above zero when all the values were negative - if(m_max>0 || m_max+m_max_grace*range<=0.0) - m_max=m_max+m_max_grace*range; -//--- calculate new min and max values if they equal - if(m_max==m_min) - { - if(MathAbs(m_max)>1e-100) - { - m_max *= (m_min < 0 ? 0.95 : 1.05 ); - m_min *= (m_min < 0 ? 1.05 : 0.95 ); - } - else - { - m_max = 1.0; - m_min = -1.0; - } - } -//--- - } -//+------------------------------------------------------------------+ -//| Calculate a m_step size based on a data range. | -//+------------------------------------------------------------------+ -double CAxis::CalcStepSize(const double range,const double steps) - { -//--- calculate an initial guess at m_step size - double temp=range/steps; -//--- get the magnitude of the m_step size - double mag=MathFloor(MathLog10(temp)); - double magPow=MathPow(10.0,mag); -//--- calculate most significant digit of the new m_step size - double magMsd=NormalizeDouble(temp/magPow+.5,0); -//--- promote the MSD to either 1, 2, or 5 - if(magMsd>5.0) - magMsd=10.0; - else - if(magMsd>2.0) - magMsd=5.0; - else - if(magMsd>1.0) - magMsd=2.0; -//--- return step - return(magMsd * magPow); - } -//+------------------------------------------------------------------+ -//| Calculate the modulus (remainder) in a safe manner so that divide| -//| by zero errors are avoided | -//+------------------------------------------------------------------+ -double CAxis::Mod(const double x,const double y) - { -//--- check - if(y==0) - return(0); -//--- calculate modulus - return (x>0)? MathMod(x,y): MathMod(x,y)+y; - } -//+------------------------------------------------------------------+ -//| Calculate a m_step size based on a data range, limited to a max | -//| number of steps. | -//+------------------------------------------------------------------+ -double CAxis::CalcBoundedStepSize(const double range,const double max_steps) - { -//--- calculate an initial guess at m_step size - double temp=range/max_steps; -//--- get the magnitude of the m_step size - double mag=MathFloor(MathLog10(temp)); - double magPow=MathPow((double) 10.0,mag); -//--- calculate most significant digit of the new m_step size - double magMsd=MathCeil(temp/magPow); -//--- promote the MSD to either 1, 2, or 5 - if(magMsd>5.0) - magMsd=10.0; - else - if(magMsd>2.0) - magMsd=5.0; - else - if(magMsd>1.0) - magMsd=2.0; -//--- return step - return(magMsd * magPow); - } -//+------------------------------------------------------------------+ diff --git a/Include/Graphics/ColorGenerator.mqh b/Include/Graphics/ColorGenerator.mqh deleted file mode 100644 index e4b7376..0000000 --- a/Include/Graphics/ColorGenerator.mqh +++ /dev/null @@ -1,74 +0,0 @@ -//+------------------------------------------------------------------+ -//| ColorGenerator.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ -//| Class CColorGenerator | -//| Usage: class to generate the default colors | -//+------------------------------------------------------------------+ -class CColorGenerator - { -private: - int m_index; - bool m_generate; - uint m_current_palette[20]; - const static uint s_default_palette[20]; - -public: - CColorGenerator(void); - ~CColorGenerator(void); - //--- gets the next color - uint Next(void); - //--- reset generator - void Reset(void); - }; -const uint CColorGenerator::s_default_palette[20]= - { - 0x3366CC,0xDC3912,0xFF9900,0x109618,0x990099, - 0x3B3EAC,0x0099C6,0xDD4477,0x66AA00,0xB82E2E, - 0x316395,0x994499,0x22AA99,0xAAAA11,0x6633CC, - 0xE67300,0x8B0707,0x329262,0x5574A6,0x3B3EAC - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CColorGenerator::CColorGenerator(void): m_index(0), - m_generate(false) - { - ArrayCopy(m_current_palette,s_default_palette); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CColorGenerator::~CColorGenerator(void) - { - } -//+------------------------------------------------------------------+ -//| Gets or generates the following color from the palette | -//+------------------------------------------------------------------+ -uint CColorGenerator::Next(void) - { -//--- check the array out of range - if(m_index==20) - { - m_index=0; - if(!m_generate) - m_generate=true; - } -//--- check the default palette is over - if(m_generate) - m_current_palette[m_index]=(m_index==19 ? (m_current_palette[m_index]^m_current_palette[0]):(m_current_palette[m_index]^m_current_palette[m_index+1])); -//--- return next color - return(m_current_palette[m_index++]); - } -//+------------------------------------------------------------------+ -//| Resets all the new colors, set the index to 0 | -//+------------------------------------------------------------------+ -void CColorGenerator::Reset(void) - { - m_index=0; - m_generate=false; - ArrayCopy(m_current_palette,s_default_palette); - } -//+------------------------------------------------------------------+ diff --git a/Include/Graphics/Curve.mqh b/Include/Graphics/Curve.mqh deleted file mode 100644 index 6f3db80..0000000 --- a/Include/Graphics/Curve.mqh +++ /dev/null @@ -1,700 +0,0 @@ -//+------------------------------------------------------------------+ -//| Curve.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include -#include -//--- forward declaration -class CGraphic; -//--- fucntion for represent custom plot method -typedef void(*PlotFucntion)(double &x[],double &y[],int size,CGraphic *graphic,CCanvas *canvas,void *cbdata); -//--- function for represent curve -typedef double(*CurveFunction)(double); -//--- drawing type -enum ENUM_CURVE_TYPE - { - CURVE_POINTS, - CURVE_LINES, - CURVE_POINTS_AND_LINES, - CURVE_STEPS, - CURVE_HISTOGRAM, - CURVE_CUSTOM, - CURVE_NONE - }; -//--- type for the various point shapes that are available -enum ENUM_POINT_TYPE - { - POINT_CIRCLE, - POINT_SQUARE, - POINT_DIAMOND, - POINT_TRIANGLE, - POINT_TRIANGLE_DOWN, - POINT_X_CROSS, - POINT_PLUS, - POINT_STAR, - POINT_HORIZONTAL_DASH, - POINT_VERTICAL_DASH - }; -//+------------------------------------------------------------------+ -//| Structure CPoint2D | -//| Usage: 2d point on graphic in Cartesian coordinates | -//+------------------------------------------------------------------+ -struct CPoint2D - { - double x; - double y; - }; -//+------------------------------------------------------------------+ -//| Class CCurve | -//| Usage: class to represent the one-dimensional curve | -//+------------------------------------------------------------------+ -class CCurve : public CObject - { -private: - uint m_clr; - double m_x[]; - double m_y[]; - double m_xmin; - double m_xmax; - double m_ymin; - double m_ymax; - int m_size; - ENUM_CURVE_TYPE m_type; - string m_name; - //--- lines - ENUM_LINE_STYLE m_lines_style; - ENUM_LINE_END m_lines_end_style; - int m_lines_width; - bool m_lines_smooth; - double m_lines_tension; - double m_lines_step; - //--- points - int m_points_size; - ENUM_POINT_TYPE m_points_type; - bool m_points_fill; - uint m_points_clr; - //--- steps - int m_steps_dimension; - //--- histogram - int m_hisogram_width; - //--- custom - PlotFucntion m_custom_plot_func; - void *m_custom_plot_cbdata; - //--- general property - bool m_visible; - //--- trend line property - uint m_trend_clr; - bool m_trend_visible; - -protected: - bool m_trend_calc; - double m_trend_coeff[]; - -public: - CCurve(const double &y[],const uint clr,ENUM_CURVE_TYPE type,const string name); - CCurve(const double &x[],const double &y[],const uint clr,ENUM_CURVE_TYPE type,const string name); - CCurve(const CPoint2D &points[],const uint clr,ENUM_CURVE_TYPE type,const string name); - CCurve(CurveFunction function,const double from,const double to,const double step,const uint clr,ENUM_CURVE_TYPE type,const string name); - ~CCurve(void); - //--- gets the general properties - void GetX(double &x[]) const { ArrayCopy(x,m_x); } - void GetY(double &y[]) const { ArrayCopy(y,m_y); } - double XMax(void) const { return(m_xmax); } - double XMin(void) const { return(m_xmin); } - double YMax(void) const { return(m_ymax); } - double YMin(void) const { return(m_ymin); } - int Size(void) const { return(m_size); } - //--- update - void Update(const double &y[]); - void Update(const double &x[],const double &y[]); - void Update(const CPoint2D &points[]); - void Update(CurveFunction function,const double from,const double to,const double step); - //--- gets or sets general options - uint Color(void) const { return(m_clr); } - int Type(void) const { return(m_type); } - string Name(void) const { return(m_name); } - bool Visible(void) const { return(m_visible); } - void Color(const uint clr) { m_clr=clr; } - void Type(const int type) { m_type=(ENUM_CURVE_TYPE)type; } - void Name(const string name) { m_name=name; } - void Visible(const bool visible) { m_visible=visible; } - //--- gets or sets the lines properties - ENUM_LINE_STYLE LinesStyle(void) const { return(m_lines_style); } - ENUM_LINE_END LinesEndStyle(void) const { return(m_lines_end_style); } - int LinesWidth(void) const { return(m_lines_width); } - bool LinesSmooth(void) const { return(m_lines_smooth); } - double LinesSmoothTension(void) const { return(m_lines_tension); } - double LinesSmoothStep(void) const { return(m_lines_step); } - void LinesStyle(ENUM_LINE_STYLE style) { m_lines_style=style; } - void LinesEndStyle(ENUM_LINE_END end_style) { m_lines_end_style=end_style; } - void LinesWidth(const int width) { m_lines_width=width; } - void LinesSmooth(const bool smooth) { m_lines_smooth=smooth; } - void LinesSmoothTension(const double tension) { m_lines_tension=tension; } - void LinesSmoothStep(const double step) { m_lines_step=step; } - //--- gets or sets the points properties - int PointsSize(void) const { return(m_points_size); } - ENUM_POINT_TYPE PointsType(void) const { return(m_points_type); } - bool PointsFill(void) const { return(m_points_fill); } - uint PointsColor(void) const { return(m_points_clr); } - void PointsSize(const int size) { m_points_size=size; } - void PointsType(ENUM_POINT_TYPE type) { m_points_type=type; } - void PointsFill(const bool fill) { m_points_fill=fill; } - void PointsColor(const uint clr) { m_points_clr=clr; } - //--- gets or sets the steps properties - int StepsDimension(void) const { return(m_steps_dimension); } - void StepsDimension(const int dimension) { m_steps_dimension=dimension; } - //--- gets or sets the histogram properties - int HistogramWidth(void) const { return(m_hisogram_width); } - void HistogramWidth(const int width) { m_hisogram_width=width; } - //--- gets or sets the custom properties - PlotFucntion CustomPlotFunction(void) const { return(m_custom_plot_func); } - void *CustomPlotCBData(void) const { return(m_custom_plot_cbdata); } - void CustomPlotFunction(PlotFucntion func) { m_custom_plot_func=func; } - void CustomPlotCBData(void *cbdata) { m_custom_plot_cbdata=cbdata; } - //--- gets or sets the trend line properties - bool TrendLineVisible(void) const { return(m_trend_visible); } - uint TrendLineColor(void) const { return(m_trend_clr); } - void TrendLineVisible(const bool visible) { m_trend_visible=visible; } - void TrendLineColor(const uint clr) { m_trend_clr=clr; } - void TrendLineCoefficients(double &coefficients[]); - -protected: - virtual void CalculateCoefficients(void); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CCurve::CCurve(const double &y[],const uint clr,ENUM_CURVE_TYPE type,const string name) - : m_name(name), - m_clr(clr), - m_type(type), - m_visible(false), - m_lines_style(STYLE_SOLID), - m_lines_end_style(LINE_END_ROUND), - m_lines_width(1), - m_lines_smooth(false), - m_lines_tension(0.5), - m_lines_step(1.0), - m_points_size(6), - m_points_type(POINT_CIRCLE), - m_points_fill(false), - m_points_clr(clr), - m_steps_dimension(0), - m_hisogram_width(1), - m_custom_plot_func(NULL), - m_custom_plot_cbdata(NULL), - m_trend_visible(false), - m_trend_clr(clr), - m_trend_calc(false) - { -//--- keep y array - m_size=ArraySize(y); - ArrayResize(m_x,m_size); - ArrayCopy(m_y,y); - m_xmax = m_size-1; - m_xmin = 0.0; - m_ymax = 0.0; - m_ymin = 0.0; - bool yvalid=false; -//--- find min and max values - for(int i=0; iy[i]) - m_ymin=y[i]; - } - } - } -//--- - } -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CCurve::CCurve(const double &x[],const double &y[],const uint clr,ENUM_CURVE_TYPE type,const string name) - : m_name(name), - m_clr(clr), - m_type(type), - m_visible(false), - m_lines_style(STYLE_SOLID), - m_lines_end_style(LINE_END_ROUND), - m_lines_width(1), - m_lines_smooth(false), - m_lines_tension(0.5), - m_lines_step(1.0), - m_points_size(6), - m_points_type(POINT_CIRCLE), - m_points_fill(false), - m_points_clr(clr), - m_steps_dimension(0), - m_hisogram_width(1), - m_custom_plot_func(NULL), - m_custom_plot_cbdata(NULL), - m_trend_visible(false), - m_trend_clr(clr), - m_trend_calc(false) - { -//--- keep x and y array - ArrayCopy(m_x,x); - ArrayCopy(m_y,y); - m_size = ArraySize(x); - m_xmax = 0.0; - m_xmin = 0.0; - m_ymax = 0.0; - m_ymin = 0.0; - bool yvalid=false; - bool xvalid=false; -//--- find min and max values - for(int i=0; ix[i]) - m_xmin=x[i]; - } - } - if(MathIsValidNumber(m_y[i])) - { - if(!yvalid) - { - m_ymax = y[i]; - m_ymin = y[i]; - yvalid=true; - } - else - { - //--- find max and min of y - if(m_ymaxy[i]) - m_ymin=y[i]; - } - } - } -//--- - } -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CCurve::CCurve(const CPoint2D &points[],const uint clr,ENUM_CURVE_TYPE type,const string name) - : m_name(name), - m_clr(clr), - m_type(type), - m_visible(false), - m_lines_style(STYLE_SOLID), - m_lines_end_style(LINE_END_ROUND), - m_lines_width(1), - m_lines_smooth(false), - m_lines_tension(0.5), - m_lines_step(1.0), - m_points_size(6), - m_points_type(POINT_CIRCLE), - m_points_fill(false), - m_points_clr(clr), - m_steps_dimension(0), - m_hisogram_width(1), - m_custom_plot_func(NULL), - m_custom_plot_cbdata(NULL), - m_trend_visible(false), - m_trend_clr(clr), - m_trend_calc(false) - { -//--- preliminary calculation - m_size=ArraySize(points); - ArrayResize(m_x,m_size); - ArrayResize(m_y,m_size); - m_xmax = 0.0; - m_xmin = 0.0; - m_ymax = 0.0; - m_ymin = 0.0; - bool xvalid=false; - bool yvalid=false; -//--- keep x and y array - for(int i=0; im_x[i]) - m_xmin=m_x[i]; - } - } - if(MathIsValidNumber(m_y[i])) - { - if(!yvalid) - { - m_ymax = m_y[i]; - m_ymin = m_y[i]; - yvalid=true; - } - else - { - //--- find max and min of y - if(m_ymaxm_y[i]) - m_ymin=m_y[i]; - } - } - } -//--- - } -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CCurve::CCurve(CurveFunction function,const double from,const double to,const double step,const uint clr,ENUM_CURVE_TYPE type,const string name) - : m_name(name), - m_clr(clr), - m_type(type), - m_visible(false), - m_lines_style(STYLE_SOLID), - m_lines_end_style(LINE_END_ROUND), - m_lines_width(1), - m_lines_smooth(false), - m_lines_tension(0.5), - m_lines_step(1.0), - m_points_size(6), - m_points_type(POINT_CIRCLE), - m_points_fill(false), - m_points_clr(clr), - m_steps_dimension(0), - m_hisogram_width(1), - m_custom_plot_func(NULL), - m_custom_plot_cbdata(NULL), - m_trend_visible(false), - m_trend_clr(clr), - m_trend_calc(false) - { -//--- preliminary calculation - m_size=(int)((to-from)/step)+1; - ArrayResize(m_x,m_size); - ArrayResize(m_y,m_size); - m_xmax = to; - m_xmin = from; - m_ymax = 0.0; - m_ymin = 0.0; - bool yvalid=false; -//--- keep x and y array - for(int i=0; im_y[i]) - m_ymin=m_y[i]; - } - } - } -//--- - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CCurve::~CCurve(void) - { - } -//+------------------------------------------------------------------+ -//| Update x and y coordinates of curve | -//+------------------------------------------------------------------+ -void CCurve::Update(const double &y[]) - { - m_trend_calc=false; - ArrayFree(m_y); - int size=ArraySize(y); -//--- keep y array - if(m_size!=size) - { - m_size=size; - ArrayResize(m_x,m_size); - } - ArrayCopy(m_y,y); - m_xmax = m_size-1; - m_xmin = 0.0; - m_ymax = 0.0; - m_ymin = 0.0; - bool yvalid=false; -//--- find min and max values - for(int i=0; iy[i]) - m_ymin=y[i]; - } - } - } -//--- - } -//+------------------------------------------------------------------+ -//| Update x and y coordinates of curve | -//+------------------------------------------------------------------+ -void CCurve::Update(const double &x[],const double &y[]) - { - m_trend_calc=false; - ArrayFree(m_x); - ArrayFree(m_y); -//--- keep x and y array - ArrayCopy(m_x,x); - ArrayCopy(m_y,y); - m_size = ArraySize(x); - m_xmax = 0.0; - m_xmin = 0.0; - m_ymax = 0.0; - m_ymin = 0.0; - bool yvalid=false; - bool xvalid=false; -//--- find min and max values - for(int i=0; ix[i]) - m_xmin=x[i]; - } - } - if(MathIsValidNumber(m_y[i])) - { - if(!yvalid) - { - m_ymax = y[i]; - m_ymin = y[i]; - yvalid=true; - } - else - { - //--- find max and min of y - if(m_ymaxy[i]) - m_ymin=y[i]; - } - } - } -//--- - } -//+------------------------------------------------------------------+ -//| Update x and y coordinates of curve | -//+------------------------------------------------------------------+ -void CCurve::Update(const CPoint2D &points[]) - { - m_trend_calc=false; - int size=ArraySize(points); -//--- preliminary calculation - if(size!=m_size) - { - m_size=size; - ArrayResize(m_x,m_size); - ArrayResize(m_y,m_size); - } - m_xmax = 0.0; - m_xmin = 0.0; - m_ymax = 0.0; - m_ymin = 0.0; - bool xvalid=false; - bool yvalid=false; -//--- keep x and y array - for(int i=0; im_x[i]) - m_xmin=m_x[i]; - } - } - if(MathIsValidNumber(m_y[i])) - { - if(!yvalid) - { - m_ymax = m_y[i]; - m_ymin = m_y[i]; - yvalid=true; - } - else - { - //--- find max and min of y - if(m_ymaxm_y[i]) - m_ymin=m_y[i]; - } - } - } -//--- - } -//+------------------------------------------------------------------+ -//| Update x and y coordinates of curve | -//+------------------------------------------------------------------+ -void CCurve::Update(CurveFunction function,const double from,const double to,const double step) - { - m_trend_calc=false; - int size=(int)((to-from)/step)+1; -//--- preliminary calculation - if(size!=m_size) - { - m_size=size; - ArrayResize(m_x,m_size); - ArrayResize(m_y,m_size); - } - m_xmax = to; - m_xmin = from; - m_ymax = 0.0; - m_ymin = 0.0; - bool yvalid=false; -//--- keep x and y array - for(int i=0; im_y[i]) - m_ymin=m_y[i]; - } - } - } -//--- - } -//+------------------------------------------------------------------+ -//| Gets the coefficients for trend line | -//+------------------------------------------------------------------+ -void CCurve::TrendLineCoefficients(double &coefficients[]) - { - if(!m_trend_calc) - { - CalculateCoefficients(); - m_trend_calc=true; - } - ArrayCopy(coefficients,m_trend_coeff); - } -//+------------------------------------------------------------------+ -//| Calculate coefficients | -//+------------------------------------------------------------------+ -void CCurve::CalculateCoefficients(void) - { -//--- simple linear resgression - ArrayResize(m_trend_coeff,2); - double xmean=0.0; - double ymean=0.0; - double sum_xy=0.0; - double sum_xx=0.0; -//--- primary calculate - for(int i=0; iUva(1Vsv?QWdZ&!kN(%_9|W2&Mt>Wv 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 diff --git a/Include/MQLTA ErrorHandling.mqh b/Include/MQLTA ErrorHandling.mqh deleted file mode 100644 index 4828d81..0000000 --- a/Include/MQLTA ErrorHandling.mqh +++ /dev/null @@ -1,95 +0,0 @@ -#property link "https://www.earnforex.com/" -#property version "1.00" -#property strict -#property copyright "EarnForex.com - 2020" -#property description "This is list of the available MT4 errors" -#property description " " -#property description "Find More on EarnForex.com" - -//This functions returns a string corresponding to the description of an error -//Complete list of error available https://book.mql4.com/appendix/errors -string GetLastErrorText(int Error){ - string Text="Error Not Defined"; - if(Error==ERR_NO_ERROR) Text="No error returned."; - if(Error==ERR_NO_RESULT) Text="No error returned, but the result is unknown."; - if(Error==ERR_COMMON_ERROR) Text="Common error."; - if(Error==ERR_INVALID_TRADE_PARAMETERS) Text="Invalid trade parameters."; - if(Error==ERR_SERVER_BUSY) Text="Trade server is busy."; - if(Error==ERR_OLD_VERSION) Text="Old version of the client terminal."; - if(Error==ERR_NO_CONNECTION) Text="No connection with trade server."; - if(Error==ERR_NOT_ENOUGH_RIGHTS) Text="Not enough rights."; - if(Error==ERR_TOO_FREQUENT_REQUESTS) Text="Too frequent requests."; - if(Error==ERR_MALFUNCTIONAL_TRADE) Text="Malfunctional trade operation."; - if(Error==ERR_ACCOUNT_DISABLED) Text="Account disabled."; - if(Error==ERR_INVALID_ACCOUNT) Text="Invalid account."; - if(Error==ERR_TRADE_TIMEOUT) Text="Trade timeout."; - if(Error==ERR_INVALID_PRICE) Text="Invalid price."; - if(Error==ERR_INVALID_STOPS) Text="Invalid stops."; - if(Error==ERR_INVALID_TRADE_VOLUME) Text="Invalid trade volume."; - if(Error==ERR_MARKET_CLOSED) Text="Market is closed."; - if(Error==ERR_TRADE_DISABLED) Text="Trade is disabled."; - if(Error==ERR_NOT_ENOUGH_MONEY) Text="Not enough money."; - if(Error==ERR_PRICE_CHANGED) Text="Price changed."; - if(Error==ERR_OFF_QUOTES) Text="Off quotes."; - if(Error==ERR_BROKER_BUSY) Text="Broker is busy."; - if(Error==ERR_REQUOTE) Text="Requote."; - if(Error==ERR_ORDER_LOCKED) Text="Order is locked."; - if(Error==ERR_LONG_POSITIONS_ONLY_ALLOWED) Text="Long positions only allowed."; - if(Error==ERR_TOO_MANY_REQUESTS) Text="Too many requests."; - if(Error==ERR_TRADE_MODIFY_DENIED) Text="Modification denied because an order is too close to market."; - if(Error==ERR_TRADE_CONTEXT_BUSY) Text="Trade context is busy."; - if(Error==ERR_TRADE_EXPIRATION_DENIED) Text="Expirations are denied by broker."; - if(Error==ERR_TRADE_TOO_MANY_ORDERS) Text="The amount of opened and pending orders has reached the limit set by a broker."; - if(Error==ERR_NO_MQLERROR) Text="No error."; - if(Error==ERR_WRONG_FUNCTION_POINTER) Text="Wrong function pointer."; - if(Error==ERR_ARRAY_INDEX_OUT_OF_RANGE) Text="Array index is out of range."; - if(Error==ERR_RECURSIVE_STACK_OVERFLOW) Text="Recursive stack overflow."; - if(Error==ERR_NO_MEMORY_FOR_TEMP_STRING) Text="No memory for temp string."; - if(Error==ERR_NOT_INITIALIZED_STRING) Text="Not initialized string."; - if(Error==ERR_NOT_INITIALIZED_ARRAYSTRING) Text="Not initialized string in an array."; - if(Error==ERR_NO_MEMORY_FOR_ARRAYSTRING) Text="No memory for an array string."; - if(Error==ERR_TOO_LONG_STRING) Text="Too long string."; - if(Error==ERR_REMAINDER_FROM_ZERO_DIVIDE) Text="Remainder from zero divide."; - if(Error==ERR_ZERO_DIVIDE) Text="Zero divide."; - if(Error==ERR_UNKNOWN_COMMAND) Text="Unknown command."; - if(Error==ERR_WRONG_JUMP) Text="Wrong jump."; - if(Error==ERR_NOT_INITIALIZED_ARRAY) Text="Not initialized array."; - if(Error==ERR_DLL_CALLS_NOT_ALLOWED) Text="DLL calls are not allowed."; - if(Error==ERR_CANNOT_LOAD_LIBRARY) Text="Cannot load library."; - if(Error==ERR_CANNOT_CALL_FUNCTION) Text="Cannot call function."; - if(Error==ERR_SYSTEM_BUSY) Text="System is busy."; - if(Error==ERR_SOME_ARRAY_ERROR) Text="Some array error."; - if(Error==ERR_CUSTOM_INDICATOR_ERROR) Text="Custom indicator error."; - if(Error==ERR_INCOMPATIBLE_ARRAYS) Text="Arrays are incompatible."; - if(Error==ERR_GLOBAL_VARIABLE_NOT_FOUND) Text="Global variable not found."; - if(Error==ERR_FUNCTION_NOT_CONFIRMED) Text="Function is not confirmed."; - if(Error==ERR_SEND_MAIL_ERROR) Text="Mail sending error."; - if(Error==ERR_STRING_PARAMETER_EXPECTED) Text="String parameter expected."; - if(Error==ERR_INTEGER_PARAMETER_EXPECTED) Text="Integer parameter expected."; - if(Error==ERR_DOUBLE_PARAMETER_EXPECTED) Text="Double parameter expected."; - if(Error==ERR_ARRAY_AS_PARAMETER_EXPECTED) Text="Array as parameter expected."; - if(Error==ERR_HISTORY_WILL_UPDATED) Text="Requested history data in updating state."; - if(Error==ERR_TRADE_ERROR) Text="Some error in trade operation execution."; - if(Error==ERR_END_OF_FILE) Text="End of a file."; - if(Error==ERR_SOME_FILE_ERROR) Text="Some file error."; - if(Error==ERR_WRONG_FILE_NAME) Text="Wrong file name."; - if(Error==ERR_TOO_MANY_OPENED_FILES) Text="Too many opened files."; - if(Error==ERR_CANNOT_OPEN_FILE) Text="Cannot open file."; - if(Error==ERR_NO_ORDER_SELECTED) Text="No order selected."; - if(Error==ERR_UNKNOWN_SYMBOL) Text="Unknown symbol."; - if(Error==ERR_INVALID_PRICE_PARAM) Text="Invalid price."; - if(Error==ERR_INVALID_TICKET) Text="Invalid ticket."; - if(Error==ERR_TRADE_NOT_ALLOWED) Text="Trade is not allowed."; - if(Error==ERR_LONGS_NOT_ALLOWED) Text="Longs are not allowed."; - if(Error==ERR_SHORTS_NOT_ALLOWED) Text="Shorts are not allowed."; - if(Error==ERR_OBJECT_ALREADY_EXISTS) Text="Object already exists."; - if(Error==ERR_UNKNOWN_OBJECT_PROPERTY) Text="Unknown object property."; - if(Error==ERR_OBJECT_DOES_NOT_EXIST) Text="Object does not exist."; - if(Error==ERR_UNKNOWN_OBJECT_TYPE) Text="Unknown object type."; - if(Error==ERR_NO_OBJECT_NAME) Text="No object name."; - if(Error==ERR_OBJECT_COORDINATES_ERROR) Text="Object coordinates error."; - if(Error==ERR_NO_SPECIFIED_SUBWINDOW) Text="No specified subwindow."; - if(Error==ERR_SOME_OBJECT_ERROR) Text="Some error in object operation."; - - return Text; -} \ No newline at end of file diff --git a/Include/Math/Alglib/alglib.mqh b/Include/Math/Alglib/alglib.mqh deleted file mode 100644 index f8085e6..0000000 --- a/Include/Math/Alglib/alglib.mqh +++ /dev/null @@ -1,23023 +0,0 @@ -//+------------------------------------------------------------------+ -//| alglib.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 -#include "alglibmisc.mqh" -#include "dataanalysis.mqh" -#include "diffequations.mqh" -#include "delegatefunctions.mqh" -#include "fasttransforms.mqh" -#include "integration.mqh" -#include "interpolation.mqh" -//+------------------------------------------------------------------+ -//| The main class, which includes functions for users | -//+------------------------------------------------------------------+ -class CAlglib - { -public: - //--- constructor, destructor - CAlglib(void); - ~CAlglib(void); - //--- function of package alglibmisc - //--- high quality random number generator - static void HQRndRandomize(CHighQualityRandStateShell &state); - static void HQRndSeed(const int s1,const int s2,CHighQualityRandStateShell &state); - static double HQRndUniformR(CHighQualityRandStateShell &state); - static int HQRndUniformI(CHighQualityRandStateShell &state,const int n); - static double HQRndNormal(CHighQualityRandStateShell &state); - static void HQRndUnit2(CHighQualityRandStateShell &state,double &x,double &y); - static void HQRndNormal2(CHighQualityRandStateShell &state,double &x1,double &x2); - static double HQRndExponential(CHighQualityRandStateShell &state,const double lambdav); - //--- build KD-trees - static void KDTreeSerialize(CKDTreeShell &obj,string &s_out); - static void KDTreeUnserialize(string s_in,CKDTreeShell &obj); - static void KDTreeBuild(CMatrixDouble &xy,const int n,const int nx,const int ny,const int normtype,CKDTreeShell &kdt); - static void KDTreeBuild(CMatrixDouble &xy,const int nx,const int ny,const int normtype,CKDTreeShell &kdt); - static void KDTreeBuildTagged(CMatrixDouble &xy,int &tags[],const int n,const int nx,const int ny,const int normtype,CKDTreeShell &kdt); - static void KDTreeBuildTagged(CMatrixDouble &xy,int &tags[],const int nx,const int ny,const int normtype,CKDTreeShell &kdt); - static int KDTreeQueryKNN(CKDTreeShell &kdt,double &x[],const int k,const bool selfmatch); - static int KDTreeQueryKNN(CKDTreeShell &kdt,double &x[],const int k); - static int KDTreeQueryRNN(CKDTreeShell &kdt,double &x[],const double r,const bool selfmatch); - static int KDTreeQueryRNN(CKDTreeShell &kdt,double &x[],const double r); - static int KDTreeQueryAKNN(CKDTreeShell &kdt,double &x[],const int k,const bool selfmatch,const double eps); - static int KDTreeQueryAKNN(CKDTreeShell &kdt,double &x[],const int k,const double eps); - static void KDTreeQueryResultsX(CKDTreeShell &kdt,CMatrixDouble &x); - static void KDTreeQueryResultsXY(CKDTreeShell &kdt,CMatrixDouble &xy); - static void KDTreeQueryResultsTags(CKDTreeShell &kdt,int &tags[]); - static void KDTreeQueryResultsDistances(CKDTreeShell &kdt,double &r[]); - static void KDTreeQueryResultsXI(CKDTreeShell &kdt,CMatrixDouble &x); - static void KDTreeQueryResultsXYI(CKDTreeShell &kdt,CMatrixDouble &xy); - static void KDTreeQueryResultsTagsI(CKDTreeShell &kdt,int &tags[]); - static void KDTreeQueryResultsDistancesI(CKDTreeShell &kdt,double &r[]); - //--- function of package dataanalysis - //--- data analysis - static void DSOptimalSplit2(double &a[],int &c[],const int n,int &info,double &threshold,double &pal,double &pbl,double &par,double &pbr,double &cve); - static void DSOptimalSplit2Fast(double &a[],int &c[],int &tiesbuf[],int &cntbuf[],double &bufr[],int &bufi[],const int n,const int nc,const double alpha,int &info,double &threshold,double &rms,double &cvrms); - //--- decision forest - static void DFSerialize(CDecisionForestShell &obj,string &s_out); - static void DFUnserialize(const string s_in,CDecisionForestShell &obj); - static void DFBuildRandomDecisionForest(CMatrixDouble &xy,const int npoints,const int nvars,const int nclasses,const int ntrees,const double r,int &info,CDecisionForestShell &df,CDFReportShell &rep); - static void DFBuildRandomDecisionForestX1(CMatrixDouble &xy,const int npoints,const int nvars,const int nclasses,const int ntrees,int nrndvars,const double r,int &info,CDecisionForestShell &df,CDFReportShell &rep); - static void DFProcess(CDecisionForestShell &df,double &x[],double &y[]); - static void DFProcessI(CDecisionForestShell &df,double &x[],double &y[]); - static double DFRelClsError(CDecisionForestShell &df,CMatrixDouble &xy,const int npoints); - static double DFAvgCE(CDecisionForestShell &df,CMatrixDouble &xy,const int npoints); - static double DFRMSError(CDecisionForestShell &df,CMatrixDouble &xy,const int npoints); - static double DFAvgError(CDecisionForestShell &df,CMatrixDouble &xy,const int npoints); - static double DFAvgRelError(CDecisionForestShell &df,CMatrixDouble &xy,const int npoints); - //--- middle and clusterization - static void KMeansGenerate(CMatrixDouble &xy,const int npoints,const int nvars,const int k,const int restarts,int &info,CMatrixDouble &c,int &xyc[]); - //--- Fisher LDA functions - static void FisherLDA(CMatrixDouble &xy,const int npoints,const int nvars,const int nclasses,int &info,double &w[]); - static void FisherLDAN(CMatrixDouble &xy,const int npoints,const int nvars,const int nclasses,int &info,CMatrixDouble &w); - //--- linear regression - static void LRBuild(CMatrixDouble &xy,const int npoints,const int nvars,int &info,CLinearModelShell &lm,CLRReportShell &ar); - static void LRBuildS(CMatrixDouble &xy,double &s[],const int npoints,const int nvars,int &info,CLinearModelShell &lm,CLRReportShell &ar); - static void LRBuildZS(CMatrixDouble &xy,double &s[],const int npoints,const int nvars,int &info,CLinearModelShell &lm,CLRReportShell &ar); - static void LRBuildZ(CMatrixDouble &xy,const int npoints,const int nvars,int &info,CLinearModelShell &lm,CLRReportShell &ar); - static void LRUnpack(CLinearModelShell &lm,double &v[],int &nvars); - static void LRPack(double &v[],const int nvars,CLinearModelShell &lm); - static double LRProcess(CLinearModelShell &lm,double &x[]); - static double LRRMSError(CLinearModelShell &lm,CMatrixDouble &xy,const int npoints); - static double LRAvgError(CLinearModelShell &lm,CMatrixDouble &xy,const int npoints); - static double LRAvgRelError(CLinearModelShell &lm,CMatrixDouble &xy,const int npoints); - //--- multilayer perceptron - static void MLPSerialize(CMultilayerPerceptronShell &obj,string &s_out); - static void MLPUnserialize(const string s_in,CMultilayerPerceptronShell &obj); - static void MLPCreate0(const int nin,const int nout,CMultilayerPerceptronShell &network); - static void MLPCreate1(const int nin,int nhid,const int nout,CMultilayerPerceptronShell &network); - static void MLPCreate2(const int nin,const int nhid1,const int nhid2,const int nout,CMultilayerPerceptronShell &network); - static void MLPCreateB0(const int nin,const int nout,const double b,const double d,CMultilayerPerceptronShell &network); - static void MLPCreateB1(const int nin,int nhid,const int nout,const double b,const double d,CMultilayerPerceptronShell &network); - static void MLPCreateB2(const int nin,const int nhid1,const int nhid2,const int nout,const double b,const double d,CMultilayerPerceptronShell &network); - static void MLPCreateR0(const int nin,const int nout,double a,const double b,CMultilayerPerceptronShell &network); - static void MLPCreateR1(const int nin,int nhid,const int nout,const double a,const double b,CMultilayerPerceptronShell &network); - static void MLPCreateR2(const int nin,const int nhid1,const int nhid2,const int nout,const double a,const double b,CMultilayerPerceptronShell &network); - static void MLPCreateC0(const int nin,const int nout,CMultilayerPerceptronShell &network); - static void MLPCreateC1(const int nin,int nhid,const int nout,CMultilayerPerceptronShell &network); - static void MLPCreateC2(const int nin,const int nhid1,const int nhid2,const int nout,CMultilayerPerceptronShell &network); - static void MLPRandomize(CMultilayerPerceptronShell &network); - static void MLPRandomizeFull(CMultilayerPerceptronShell &network); - static void MLPProperties(CMultilayerPerceptronShell &network,int &nin,int &nout,int &wcount); - static bool MLPIsSoftMax(CMultilayerPerceptronShell &network); - static int MLPGetLayersCount(CMultilayerPerceptronShell &network); - static int MLPGetLayerSize(CMultilayerPerceptronShell &network,const int k); - static void MLPGetInputScaling(CMultilayerPerceptronShell &network,const int i,double &mean,double &sigma); - static void MLPGetOutputScaling(CMultilayerPerceptronShell &network,const int i,double &mean,double &sigma); - static void MLPGetNeuronInfo(CMultilayerPerceptronShell &network,const int k,const int i,int &fkind,double &threshold); - static double MLPGetWeight(CMultilayerPerceptronShell &network,const int k0,const int i0,const int k1,const int i1); - static void MLPSetInputScaling(CMultilayerPerceptronShell &network,const int i,const double mean,const double sigma); - static void MLPSetOutputScaling(CMultilayerPerceptronShell &network,const int i,const double mean,const double sigma); - static void MLPSetNeuronInfo(CMultilayerPerceptronShell &network,const int k,const int i,int fkind,double threshold); - static void MLPSetWeight(CMultilayerPerceptronShell &network,const int k0,const int i0,const int k1,const int i1,const double w); - static void MLPActivationFunction(const double net,const int k,double &f,double &df,double &d2f); - static void MLPProcess(CMultilayerPerceptronShell &network,double &x[],double &y[]); - static void MLPProcessI(CMultilayerPerceptronShell &network,double &x[],double &y[]); - static double MLPError(CMultilayerPerceptronShell &network,CMatrixDouble &xy,const int ssize); - static double MLPErrorN(CMultilayerPerceptronShell &network,CMatrixDouble &xy,const int ssize); - static int MLPClsError(CMultilayerPerceptronShell &network,CMatrixDouble &xy,const int ssize); - static double MLPRelClsError(CMultilayerPerceptronShell &network,CMatrixDouble &xy,const int npoints); - static double MLPAvgCE(CMultilayerPerceptronShell &network,CMatrixDouble &xy,const int npoints); - static double MLPRMSError(CMultilayerPerceptronShell &network,CMatrixDouble &xy,const int npoints); - static double MLPAvgError(CMultilayerPerceptronShell &network,CMatrixDouble &xy,const int npoints); - static double MLPAvgRelError(CMultilayerPerceptronShell &network,CMatrixDouble &xy,const int npoints); - static void MLPGrad(CMultilayerPerceptronShell &network,double &x[],double &desiredy[],double &e,double &grad[]); - static void MLPGradN(CMultilayerPerceptronShell &network,double &x[],double &desiredy[],double &e,double &grad[]); - static void MLPGradBatch(CMultilayerPerceptronShell &network,CMatrixDouble &xy,const int ssize,double &e,double &grad[]); - static void MLPGradNBatch(CMultilayerPerceptronShell &network,CMatrixDouble &xy,const int ssize,double &e,double &grad[]); - static void MLPHessianNBatch(CMultilayerPerceptronShell &network,CMatrixDouble &xy,const int ssize,double &e,double &grad[],CMatrixDouble &h); - static void MLPHessianBatch(CMultilayerPerceptronShell &network,CMatrixDouble &xy,const int ssize,double &e,double &grad[],CMatrixDouble &h); - //--- logit model functions - static void MNLTrainH(CMatrixDouble &xy,const int npoints,const int nvars,const int nclasses,int &info,CLogitModelShell &lm,CMNLReportShell &rep); - static void MNLProcess(CLogitModelShell &lm,double &x[],double &y[]); - static void MNLProcessI(CLogitModelShell &lm,double &x[],double &y[]); - static void MNLUnpack(CLogitModelShell &lm,CMatrixDouble &a,int &nvars,int &nclasses); - static void MNLPack(CMatrixDouble &a,const int nvars,const int nclasses,CLogitModelShell &lm); - static double MNLAvgCE(CLogitModelShell &lm,CMatrixDouble &xy,const int npoints); - static double MNLRelClsError(CLogitModelShell &lm,CMatrixDouble &xy,const int npoints); - static double MNLRMSError(CLogitModelShell &lm,CMatrixDouble &xy,const int npoints); - static double MNLAvgError(CLogitModelShell &lm,CMatrixDouble &xy,const int npoints); - static double MNLAvgRelError(CLogitModelShell &lm,CMatrixDouble &xy,const int ssize); - static int MNLClsError(CLogitModelShell &lm,CMatrixDouble &xy,const int npoints); - //--- Markov chains - static void MCPDCreate(const int n,CMCPDStateShell &s); - static void MCPDCreateEntry(const int n,const int entrystate,CMCPDStateShell &s); - static void MCPDCreateExit(const int n,const int exitstate,CMCPDStateShell &s); - static void MCPDCreateEntryExit(const int n,const int entrystate,const int exitstate,CMCPDStateShell &s); - static void MCPDAddTrack(CMCPDStateShell &s,CMatrixDouble &xy,const int k); - static void MCPDAddTrack(CMCPDStateShell &s,CMatrixDouble &xy); - static void MCPDSetEC(CMCPDStateShell &s,CMatrixDouble &ec); - static void MCPDAddEC(CMCPDStateShell &s,const int i,const int j,const double c); - static void MCPDSetBC(CMCPDStateShell &s,CMatrixDouble &bndl,CMatrixDouble &bndu); - static void MCPDAddBC(CMCPDStateShell &s,const int i,const int j,const double bndl,const double bndu); - static void MCPDSetLC(CMCPDStateShell &s,CMatrixDouble &c,int &ct[],const int k); - static void MCPDSetLC(CMCPDStateShell &s,CMatrixDouble &c,int &ct[]); - static void MCPDSetTikhonovRegularizer(CMCPDStateShell &s,const double v); - static void MCPDSetPrior(CMCPDStateShell &s,CMatrixDouble &pp); - static void MCPDSetPredictionWeights(CMCPDStateShell &s,double &pw[]); - static void MCPDSolve(CMCPDStateShell &s); - static void MCPDResults(CMCPDStateShell &s,CMatrixDouble &p,CMCPDReportShell &rep); - //--- training neural networks - static void MLPTrainLM(CMultilayerPerceptronShell &network,CMatrixDouble &xy,const int npoints,const double decay,const int restarts,int &info,CMLPReportShell &rep); - static void MLPTrainLBFGS(CMultilayerPerceptronShell &network,CMatrixDouble &xy,const int npoints,const double decay,const int restarts,const double wstep,int maxits,int &info,CMLPReportShell &rep); - static void MLPTrainES(CMultilayerPerceptronShell &network,CMatrixDouble &trnxy,const int trnsize,CMatrixDouble &valxy,const int valsize,const double decay,const int restarts,int &info,CMLPReportShell &rep); - static void MLPKFoldCVLBFGS(CMultilayerPerceptronShell &network,CMatrixDouble &xy,const int npoints,const double decay,const int restarts,const double wstep,const int maxits,const int foldscount,int &info,CMLPReportShell &rep,CMLPCVReportShell &cvrep); - static void MLPKFoldCVLM(CMultilayerPerceptronShell &network,CMatrixDouble &xy,const int npoints,const double decay,const int restarts,const int foldscount,int &info,CMLPReportShell &rep,CMLPCVReportShell &cvrep); - //--- neural networks ensemble functions - static void MLPECreate0(const int nin,const int nout,const int ensemblesize,CMLPEnsembleShell &ensemble); - static void MLPECreate1(const int nin,int nhid,const int nout,const int ensemblesize,CMLPEnsembleShell &ensemble); - static void MLPECreate2(const int nin,const int nhid1,const int nhid2,const int nout,const int ensemblesize,CMLPEnsembleShell &ensemble); - static void MLPECreateB0(const int nin,const int nout,const double b,const double d,const int ensemblesize,CMLPEnsembleShell &ensemble); - static void MLPECreateB1(const int nin,int nhid,const int nout,const double b,const double d,const int ensemblesize,CMLPEnsembleShell &ensemble); - static void MLPECreateB2(const int nin,const int nhid1,const int nhid2,const int nout,const double b,const double d,const int ensemblesize,CMLPEnsembleShell &ensemble); - static void MLPECreateR0(const int nin,const int nout,const double a,const double b,const int ensemblesize,CMLPEnsembleShell &ensemble); - static void MLPECreateR1(const int nin,int nhid,const int nout,const double a,const double b,const int ensemblesize,CMLPEnsembleShell &ensemble); - static void MLPECreateR2(const int nin,const int nhid1,const int nhid2,const int nout,const double a,const double b,const int ensemblesize,CMLPEnsembleShell &ensemble); - static void MLPECreateC0(const int nin,const int nout,const int ensemblesize,CMLPEnsembleShell &ensemble); - static void MLPECreateC1(const int nin,int nhid,const int nout,const int ensemblesize,CMLPEnsembleShell &ensemble); - static void MLPECreateC2(const int nin,const int nhid1,const int nhid2,const int nout,const int ensemblesize,CMLPEnsembleShell &ensemble); - static void MLPECreateFromNetwork(CMultilayerPerceptronShell &network,const int ensemblesize,CMLPEnsembleShell &ensemble); - static void MLPERandomize(CMLPEnsembleShell &ensemble); - static void MLPEProperties(CMLPEnsembleShell &ensemble,int &nin,int &nout); - static bool MLPEIsSoftMax(CMLPEnsembleShell &ensemble); - static void MLPEProcess(CMLPEnsembleShell &ensemble,double &x[],double &y[]); - static void MLPEProcessI(CMLPEnsembleShell &ensemble,double &x[],double &y[]); - static double MLPERelClsError(CMLPEnsembleShell &ensemble,CMatrixDouble &xy,const int npoints); - static double MLPEAvgCE(CMLPEnsembleShell &ensemble,CMatrixDouble &xy,const int npoints); - static double MLPERMSError(CMLPEnsembleShell &ensemble,CMatrixDouble &xy,const int npoints); - static double MLPEAvgError(CMLPEnsembleShell &ensemble,CMatrixDouble &xy,const int npoints); - static double MLPEAvgRelError(CMLPEnsembleShell &ensemble,CMatrixDouble &xy,const int npoints); - static void MLPEBaggingLM(CMLPEnsembleShell &ensemble,CMatrixDouble &xy,const int npoints,const double decay,const int restarts,int &info,CMLPReportShell &rep,CMLPCVReportShell &ooberrors); - static void MLPEBaggingLBFGS(CMLPEnsembleShell &ensemble,CMatrixDouble &xy,const int npoints,const double decay,const int restarts,const double wstep,const int maxits,int &info,CMLPReportShell &rep,CMLPCVReportShell &ooberrors); - static void MLPETrainES(CMLPEnsembleShell &ensemble,CMatrixDouble &xy,const int npoints,const double decay,const int restarts,int &info,CMLPReportShell &rep); - //--- principal components analysis - static void PCABuildBasis(CMatrixDouble &x,const int npoints,const int nvars,int &info,double &s2[],CMatrixDouble &v); - //--- function of package diffequations - static void ODESolverRKCK(double &y[],const int n,double &x[],const int m,const double eps,const double h,CODESolverStateShell &state); - static void ODESolverRKCK(double &y[],double &x[],const double eps,const double h,CODESolverStateShell &state); - static bool ODESolverIteration(CODESolverStateShell &state); - static void ODESolverSolve(CODESolverStateShell &state,CNDimensional_ODE_RP &diff,CObject &obj); - static void ODESolverResults(CODESolverStateShell &state,int &m,double &xtbl[],CMatrixDouble &ytbl,CODESolverReportShell &rep); - //--- function of package fasttransforms - //--- fast Fourier transform - static void FFTC1D(al_complex &a[],const int n); - static void FFTC1D(al_complex &a[]); - static void FFTC1DInv(al_complex &a[],const int n); - static void FFTC1DInv(al_complex &a[]); - static void FFTR1D(double &a[],const int n,al_complex &f[]); - static void FFTR1D(double &a[],al_complex &f[]); - static void FFTR1DInv(al_complex &f[],const int n,double &a[]); - static void FFTR1DInv(al_complex &f[],double &a[]); - //--- convolution - static void ConvC1D(al_complex &a[],const int m,al_complex &b[],const int n,al_complex &r[]); - static void ConvC1DInv(al_complex &a[],const int m,al_complex &b[],const int n,al_complex &r[]); - static void ConvC1DCircular(al_complex &s[],const int m,al_complex &r[],const int n,al_complex &c[]); - static void ConvC1DCircularInv(al_complex &a[],const int m,al_complex &b[],const int n,al_complex &r[]); - static void ConvR1D(double &a[],const int m,double &b[],const int n,double &r[]); - static void ConvR1DInv(double &a[],const int m,double &b[],const int n,double &r[]); - static void ConvR1DCircular(double &s[],const int m,double &r[],const int n,double &c[]); - static void ConvR1DCircularInv(double &a[],const int m,double &b[],const int n,double &r[]); - static void CorrC1D(al_complex &signal[],const int n,al_complex &pattern[],const int m,al_complex &r[]); - static void CorrC1DCircular(al_complex &signal[],const int m,al_complex &pattern[],const int n,al_complex &c[]); - static void CorrR1D(double &signal[],const int n,double &pattern[],const int m,double &r[]); - static void CorrR1DCircular(double &signal[],const int m,double &pattern[],const int n,double &c[]); - //--- fast Hartley transform - static void FHTR1D(double &a[],const int n); - static void FHTR1DInv(double &a[],const int n); - //--- function of package integration - //--- Gauss quadrature formula - static void GQGenerateRec(double &alpha[],double &beta[],const double mu0,const int n,int &info,double &x[],double &w[]); - static void GQGenerateGaussLobattoRec(double &alpha[],double &beta[],const double mu0,const double a,const double b,const int n,int &info,double &x[],double &w[]); - static void GQGenerateGaussRadauRec(double &alpha[],double &beta[],const double mu0,const double a,const int n,int &info,double &x[],double &w[]); - static void GQGenerateGaussLegendre(const int n,int &info,double &x[],double &w[]); - static void GQGenerateGaussJacobi(const int n,const double alpha,const double beta,int &info,double &x[],double &w[]); - static void GQGenerateGaussLaguerre(const int n,const double alpha,int &info,double &x[],double &w[]); - static void GQGenerateGaussHermite(const int n,int &info,double &x[],double &w[]); - //--- Gauss-Kronrod quadrature formula - static void GKQGenerateRec(double &alpha[],double &beta[],const double mu0,const int n,int &info,double &x[],double &wkronrod[],double &wgauss[]); - static void GKQGenerateGaussLegendre(const int n,int &info,double &x[],double &wkronrod[],double &wgauss[]); - static void GKQGenerateGaussJacobi(const int n,const double alpha,const double beta,int &info,double &x[],double &wkronrod[],double &wgauss[]); - static void GKQLegendreCalc(const int n,int &info,double &x[],double &wkronrod[],double &wgauss[]); - static void GKQLegendreTbl(const int n,double &x[],double &wkronrod[],double &wgauss[],double &eps); - //--- auto Gauss-Kronrod - static void AutoGKSmooth(const double a,const double b,CAutoGKStateShell &state); - static void AutoGKSmoothW(const double a,const double b,double xwidth,CAutoGKStateShell &state); - static void AutoGKSingular(const double a,const double b,const double alpha,const double beta,CAutoGKStateShell &state); - static bool AutoGKIteration(CAutoGKStateShell &state); - static void AutoGKIntegrate(CAutoGKStateShell &state,CIntegrator1_Func &func,CObject &obj); - static void AutoGKResults(CAutoGKStateShell &state,double &v,CAutoGKReportShell &rep); - //--- function of package interpolation - //--- inverse distance weighting interpolation - static double IDWCalc(CIDWInterpolantShell &z,double &x[]); - static void IDWBuildModifiedShepard(CMatrixDouble &xy,const int n,const int nx,const int d,const int nq,const int nw,CIDWInterpolantShell &z); - static void IDWBuildModifiedShepardR(CMatrixDouble &xy,const int n,const int nx,const double r,CIDWInterpolantShell &z); - static void IDWBuildNoisy(CMatrixDouble &xy,const int n,const int nx,const int d,const int nq,const int nw,CIDWInterpolantShell &z); - //--- rational interpolation - static double BarycentricCalc(CBarycentricInterpolantShell &b,const double t); - static void BarycentricDiff1(CBarycentricInterpolantShell &b,const double t,double &f,double &df); - static void BarycentricDiff2(CBarycentricInterpolantShell &b,const double t,double &f,double &df,double &d2f); - static void BarycentricLinTransX(CBarycentricInterpolantShell &b,const double ca,const double cb); - static void BarycentricLinTransY(CBarycentricInterpolantShell &b,const double ca,const double cb); - static void BarycentricUnpack(CBarycentricInterpolantShell &b,int &n,double &x[],double &y[],double &w[]); - static void BarycentricBuildXYW(double &x[],double &y[],double &w[],const int n,CBarycentricInterpolantShell &b); - static void BarycentricBuildFloaterHormann(double &x[],double &y[],const int n,const int d,CBarycentricInterpolantShell &b); - //--- polynomial interpolant - static void PolynomialBar2Cheb(CBarycentricInterpolantShell &p,const double a,const double b,double &t[]); - static void PolynomialCheb2Bar(double &t[],const int n,const double a,const double b,CBarycentricInterpolantShell &p); - static void PolynomialCheb2Bar(double &t[],const double a,const double b,CBarycentricInterpolantShell &p); - static void PolynomialBar2Pow(CBarycentricInterpolantShell &p,const double c,const double s,double &a[]); - static void PolynomialBar2Pow(CBarycentricInterpolantShell &p,double &a[]); - static void PolynomialPow2Bar(double &a[],const int n,const double c,const double s,CBarycentricInterpolantShell &p); - static void PolynomialPow2Bar(double &a[],CBarycentricInterpolantShell &p); - static void PolynomialBuild(double &x[],double &y[],const int n,CBarycentricInterpolantShell &p); - static void PolynomialBuild(double &x[],double &y[],CBarycentricInterpolantShell &p); - static void PolynomialBuildEqDist(const double a,const double b,double &y[],const int n,CBarycentricInterpolantShell &p); - static void PolynomialBuildEqDist(const double a,const double b,double &y[],CBarycentricInterpolantShell &p); - static void PolynomialBuildCheb1(const double a,const double b,double &y[],const int n,CBarycentricInterpolantShell &p); - static void PolynomialBuildCheb1(const double a,const double b,double &y[],CBarycentricInterpolantShell &p); - static void PolynomialBuildCheb2(const double a,const double b,double &y[],const int n,CBarycentricInterpolantShell &p); - static void PolynomialBuildCheb2(const double a,const double b,double &y[],CBarycentricInterpolantShell &p); - static double PolynomialCalcEqDist(const double a,const double b,double &f[],const int n,const double t); - static double PolynomialCalcEqDist(const double a,const double b,double &f[],const double t); - static double PolynomialCalcCheb1(const double a,const double b,double &f[],const int n,const double t); - static double PolynomialCalcCheb1(const double a,const double b,double &f[],const double t); - static double PolynomialCalcCheb2(const double a,const double b,double &f[],const int n,const double t); - static double PolynomialCalcCheb2(const double a,const double b,double &f[],const double t); - //--- 1-dimensional spline interpolation - static void Spline1DBuildLinear(double &x[],double &y[],const int n,CSpline1DInterpolantShell &c); - static void Spline1DBuildLinear(double &x[],double &y[],CSpline1DInterpolantShell &c); - static void Spline1DBuildCubic(double &x[],double &y[],const int n,const int boundltype,const double boundl,const int boundrtype,const double boundr,CSpline1DInterpolantShell &c); - static void Spline1DBuildCubic(double &x[],double &y[],CSpline1DInterpolantShell &c); - static void Spline1DGridDiffCubic(double &x[],double &y[],const int n,const int boundltype,const double boundl,const int boundrtype,const double boundr,double &d[]); - static void Spline1DGridDiffCubic(double &x[],double &y[],double &d[]); - static void Spline1DGridDiff2Cubic(double &x[],double &y[],const int n,const int boundltype,const double boundl,const int boundrtype,const double boundr,double &d1[],double &d2[]); - static void Spline1DGridDiff2Cubic(double &x[],double &y[],double &d1[],double &d2[]); - static void Spline1DConvCubic(double &x[],double &y[],const int n,const int boundltype,const double boundl,const int boundrtype,const double boundr,double &x2[],int n2,double &y2[]); - static void Spline1DConvCubic(double &x[],double &y[],double &x2[],double &y2[]); - static void Spline1DConvDiffCubic(double &x[],double &y[],const int n,const int boundltype,const double boundl,const int boundrtype,const double boundr,double &x2[],int n2,double &y2[],double &d2[]); - static void Spline1DConvDiffCubic(double &x[],double &y[],double &x2[],double &y2[],double &d2[]); - static void Spline1DConvDiff2Cubic(double &x[],double &y[],const int n,const int boundltype,const double boundl,const int boundrtype,const double boundr,double &x2[],const int n2,double &y2[],double &d2[],double &dd2[]); - static void Spline1DConvDiff2Cubic(double &x[],double &y[],double &x2[],double &y2[],double &d2[],double &dd2[]); - static void Spline1DBuildCatmullRom(double &x[],double &y[],const int n,const int boundtype,const double tension,CSpline1DInterpolantShell &c); - static void Spline1DBuildCatmullRom(double &x[],double &y[],CSpline1DInterpolantShell &c); - static void Spline1DBuildHermite(double &x[],double &y[],double &d[],const int n,CSpline1DInterpolantShell &c); - static void Spline1DBuildHermite(double &x[],double &y[],double &d[],CSpline1DInterpolantShell &c); - static void Spline1DBuildAkima(double &x[],double &y[],const int n,CSpline1DInterpolantShell &c); - static void Spline1DBuildAkima(double &x[],double &y[],CSpline1DInterpolantShell &c); - static double Spline1DCalc(CSpline1DInterpolantShell &c,const double x); - static void Spline1DDiff(CSpline1DInterpolantShell &c,const double x,double &s,double &ds,double &d2s); - static void Spline1DUnpack(CSpline1DInterpolantShell &c,int &n,CMatrixDouble &tbl); - static void Spline1DLinTransX(CSpline1DInterpolantShell &c,const double a,const double b); - static void Spline1DLinTransY(CSpline1DInterpolantShell &c,const double a,const double b); - static double Spline1DIntegrate(CSpline1DInterpolantShell &c,const double x); - //--- least squares fitting - static void PolynomialFit(double &x[],double &y[],const int n,const int m,int &info,CBarycentricInterpolantShell &p,CPolynomialFitReportShell &rep); - static void PolynomialFit(double &x[],double &y[],const int m,int &info,CBarycentricInterpolantShell &p,CPolynomialFitReportShell &rep); - static void PolynomialFitWC(double &x[],double &y[],double &w[],const int n,double &xc[],double &yc[],int &dc[],const int k,const int m,int &info,CBarycentricInterpolantShell &p,CPolynomialFitReportShell &rep); - static void PolynomialFitWC(double &x[],double &y[],double &w[],double &xc[],double &yc[],int &dc[],const int m,int &info,CBarycentricInterpolantShell &p,CPolynomialFitReportShell &rep); - static void BarycentricFitFloaterHormannWC(double &x[],double &y[],double &w[],const int n,double &xc[],double &yc[],int &dc[],const int k,const int m,int &info,CBarycentricInterpolantShell &b,CBarycentricFitReportShell &rep); - static void BarycentricFitFloaterHormann(double &x[],double &y[],const int n,const int m,int &info,CBarycentricInterpolantShell &b,CBarycentricFitReportShell &rep); - static void Spline1DFitPenalized(double &x[],double &y[],const int n,const int m,const double rho,int &info,CSpline1DInterpolantShell &s,CSpline1DFitReportShell &rep); - static void Spline1DFitPenalized(double &x[],double &y[],const int m,const double rho,int &info,CSpline1DInterpolantShell &s,CSpline1DFitReportShell &rep); - static void Spline1DFitPenalizedW(double &x[],double &y[],double &w[],const int n,const int m,const double rho,int &info,CSpline1DInterpolantShell &s,CSpline1DFitReportShell &rep); - static void Spline1DFitPenalizedW(double &x[],double &y[],double &w[],const int m,const double rho,int &info,CSpline1DInterpolantShell &s,CSpline1DFitReportShell &rep); - static void Spline1DFitCubicWC(double &x[],double &y[],double &w[],const int n,double &xc[],double &yc[],int &dc[],const int k,const int m,int &info,CSpline1DInterpolantShell &s,CSpline1DFitReportShell &rep); - static void Spline1DFitCubicWC(double &x[],double &y[],double &w[],double &xc[],double &yc[],int &dc[],const int m,int &info,CSpline1DInterpolantShell &s,CSpline1DFitReportShell &rep); - static void Spline1DFitHermiteWC(double &x[],double &y[],double &w[],const int n,double &xc[],double &yc[],int &dc[],const int k,const int m,int &info,CSpline1DInterpolantShell &s,CSpline1DFitReportShell &rep); - static void Spline1DFitHermiteWC(double &x[],double &y[],double &w[],double &xc[],double &yc[],int &dc[],const int m,int &info,CSpline1DInterpolantShell &s,CSpline1DFitReportShell &rep); - static void Spline1DFitCubic(double &x[],double &y[],const int n,const int m,int &info,CSpline1DInterpolantShell &s,CSpline1DFitReportShell &rep); - static void Spline1DFitCubic(double &x[],double &y[],const int m,int &info,CSpline1DInterpolantShell &s,CSpline1DFitReportShell &rep); - static void Spline1DFitHermite(double &x[],double &y[],const int n,const int m,int &info,CSpline1DInterpolantShell &s,CSpline1DFitReportShell &rep); - static void Spline1DFitHermite(double &x[],double &y[],const int m,int &info,CSpline1DInterpolantShell &s,CSpline1DFitReportShell &rep); - static void LSFitLinearW(double &y[],double &w[],CMatrixDouble &fmatrix,const int n,const int m,int &info,double &c[],CLSFitReportShell &rep); - static void LSFitLinearW(double &y[],double &w[],CMatrixDouble &fmatrix,int &info,double &c[],CLSFitReportShell &rep); - static void LSFitLinearWC(double &y[],double &w[],CMatrixDouble &fmatrix,CMatrixDouble &cmatrix,const int n,const int m,const int k,int &info,double &c[],CLSFitReportShell &rep); - static void LSFitLinearWC(double &y[],double &w[],CMatrixDouble &fmatrix,CMatrixDouble &cmatrix,int &info,double &c[],CLSFitReportShell &rep); - static void LSFitLinear(double &y[],CMatrixDouble &fmatrix,const int n,const int m,int &info,double &c[],CLSFitReportShell &rep); - static void LSFitLinear(double &y[],CMatrixDouble &fmatrix,int &info,double &c[],CLSFitReportShell &rep); - static void LSFitLinearC(double &y[],CMatrixDouble &fmatrix,CMatrixDouble &cmatrix,const int n,const int m,const int k,int &info,double &c[],CLSFitReportShell &rep); - static void LSFitLinearC(double &y[],CMatrixDouble &fmatrix,CMatrixDouble &cmatrix,int &info,double &c[],CLSFitReportShell &rep); - static void LSFitCreateWF(CMatrixDouble &x,double &y[],double &w[],double &c[],const int n,const int m,const int k,const double diffstep,CLSFitStateShell &state); - static void LSFitCreateWF(CMatrixDouble &x,double &y[],double &w[],double &c[],const double diffstep,CLSFitStateShell &state); - static void LSFitCreateF(CMatrixDouble &x,double &y[],double &c[],const int n,const int m,const int k,const double diffstep,CLSFitStateShell &state); - static void LSFitCreateF(CMatrixDouble &x,double &y[],double &c[],const double diffstep,CLSFitStateShell &state); - static void LSFitCreateWFG(CMatrixDouble &x,double &y[],double &w[],double &c[],const int n,const int m,const int k,const bool cheapfg,CLSFitStateShell &state); - static void LSFitCreateWFG(CMatrixDouble &x,double &y[],double &w[],double &c[],const bool cheapfg,CLSFitStateShell &state); - static void LSFitCreateFG(CMatrixDouble &x,double &y[],double &c[],const int n,const int m,const int k,const bool cheapfg,CLSFitStateShell &state); - static void LSFitCreateFG(CMatrixDouble &x,double &y[],double &c[],const bool cheapfg,CLSFitStateShell &state); - static void LSFitCreateWFGH(CMatrixDouble &x,double &y[],double &w[],double &c[],const int n,const int m,const int k,CLSFitStateShell &state); - static void LSFitCreateWFGH(CMatrixDouble &x,double &y[],double &w[],double &c[],CLSFitStateShell &state); - static void LSFitCreateFGH(CMatrixDouble &x,double &y[],double &c[],const int n,const int m,const int k,CLSFitStateShell &state); - static void LSFitCreateFGH(CMatrixDouble &x,double &y[],double &c[],CLSFitStateShell &state); - static void LSFitSetCond(CLSFitStateShell &state,const double epsf,const double epsx,const int maxits); - static void LSFitSetStpMax(CLSFitStateShell &state,const double stpmax); - static void LSFitSetXRep(CLSFitStateShell &state,const bool needxrep); - static void LSFitSetScale(CLSFitStateShell &state,double &s[]); - static void LSFitSetBC(CLSFitStateShell &state,double &bndl[],double &bndu[]); - static bool LSFitIteration(CLSFitStateShell &state); - static void LSFitFit(CLSFitStateShell &state,CNDimensional_PFunc &func,CNDimensional_Rep &rep,bool rep_status,CObject &obj); - static void LSFitFit(CLSFitStateShell &state,CNDimensional_PFunc &func,CNDimensional_PGrad &grad,CNDimensional_Rep &rep,bool rep_status,CObject &obj); - static void LSFitFit(CLSFitStateShell &state,CNDimensional_PFunc &func,CNDimensional_PGrad &grad,CNDimensional_PHess &hess,CNDimensional_Rep &rep,bool rep_status,CObject &obj); - static void LSFitResults(CLSFitStateShell &state,int &info,double &c[],CLSFitReportShell &rep); - //--- parametric spline - static void PSpline2Build(CMatrixDouble &xy,const int n,const int st,const int pt,CPSpline2InterpolantShell &p); - static void PSpline3Build(CMatrixDouble &xy,const int n,const int st,const int pt,CPSpline3InterpolantShell &p); - static void PSpline2BuildPeriodic(CMatrixDouble &xy,const int n,const int st,const int pt,CPSpline2InterpolantShell &p); - static void PSpline3BuildPeriodic(CMatrixDouble &xy,const int n,const int st,const int pt,CPSpline3InterpolantShell &p); - static void PSpline2ParameterValues(CPSpline2InterpolantShell &p,int &n,double &t[]); - static void PSpline3ParameterValues(CPSpline3InterpolantShell &p,int &n,double &t[]); - static void PSpline2Calc(CPSpline2InterpolantShell &p,const double t,double &x,double &y); - static void PSpline3Calc(CPSpline3InterpolantShell &p,const double t,double &x,double &y,double &z); - static void PSpline2Tangent(CPSpline2InterpolantShell &p,const double t,double &x,double &y); - static void PSpline3Tangent(CPSpline3InterpolantShell &p,const double t,double &x,double &y,double &z); - static void PSpline2Diff(CPSpline2InterpolantShell &p,const double t,double &x,double &dx,double &y,double &dy); - static void PSpline3Diff(CPSpline3InterpolantShell &p,const double t,double &x,double &dx,double &y,double &dy,double &z,double &dz); - static void PSpline2Diff2(CPSpline2InterpolantShell &p,const double t,double &x,double &dx,double &d2x,double &y,double &dy,double &d2y); - static void PSpline3Diff2(CPSpline3InterpolantShell &p,const double t,double &x,double &dx,double &d2x,double &y,double &dy,double &d2y,double &z,double &dz,double &d2z); - static double PSpline2ArcLength(CPSpline2InterpolantShell &p,const double a,const double b); - static double PSpline3ArcLength(CPSpline3InterpolantShell &p,const double a,const double b); - //--- 2-dimensional spline interpolation - static void Spline2DBuildBilinear(double &x[],double &y[],CMatrixDouble &f,const int m,const int n,CSpline2DInterpolantShell &c); - static void Spline2DBuildBicubic(double &x[],double &y[],CMatrixDouble &f,const int m,const int n,CSpline2DInterpolantShell &c); - static double Spline2DCalc(CSpline2DInterpolantShell &c,const double x,const double y); - static void Spline2DDiff(CSpline2DInterpolantShell &c,const double x,const double y,double &f,double &fx,double &fy,double &fxy); - static void Spline2DUnpack(CSpline2DInterpolantShell &c,int &m,int &n,CMatrixDouble &tbl); - static void Spline2DLinTransXY(CSpline2DInterpolantShell &c,const double ax,const double bx,const double ay,const double by); - static void Spline2DLinTransF(CSpline2DInterpolantShell &c,const double a,const double b); - static void Spline2DResampleBicubic(CMatrixDouble &a,const int oldheight,const int oldwidth,CMatrixDouble &b,const int newheight,const int newwidth); - static void Spline2DResampleBilinear(CMatrixDouble &a,const int oldheight,const int oldwidth,CMatrixDouble &b,const int newheight,const int newwidth); - //--- function of package linalg - //--- working with matrix forms - static void CMatrixTranspose(const int m,const int n,CMatrixComplex &a,const int ia,const int ja,CMatrixComplex &b,const int ib,const int jb); - static void RMatrixTranspose(const int m,const int n,CMatrixDouble &a,const int ia,const int ja,CMatrixDouble &b,const int ib,const int jb); - static void CMatrixCopy(const int m,const int n,CMatrixComplex &a,const int ia,const int ja,CMatrixComplex &b,const int ib,const int jb); - static void RMatrixCopy(const int m,const int n,CMatrixDouble &a,const int ia,const int ja,CMatrixDouble &b,const int ib,const int jb); - static void CMatrixRank1(const int m,const int n,CMatrixComplex &a,const int ia,const int ja,al_complex &u[],const int iu,al_complex &v[],const int iv); - static void RMatrixRank1(const int m,const int n,CMatrixDouble &a,const int ia,const int ja,double &u[],const int iu,double &v[],const int iv); - static void CMatrixMVect(const int m,const int n,CMatrixComplex &a,const int ia,const int ja,const int opa,al_complex &x[],const int ix,al_complex &y[],const int iy); - static void RMatrixMVect(const int m,const int n,CMatrixDouble &a,const int ia,const int ja,const int opa,double &x[],const int ix,double &y[],const int iy); - static void CMatrixRightTrsM(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 CMatrixLeftTrsM(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 RMatrixRightTrsM(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 RMatrixLeftTrsM(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 CMatrixSyrk(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 RMatrixSyrk(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 CMatrixGemm(const int m,const int n,const int k,al_complex &alpha,CMatrixComplex &a,const int ia,const int ja,const int optypea,CMatrixComplex &b,const int ib,const int jb,const int optypeb,al_complex &beta,CMatrixComplex &c,const int ic,const int jc); - static void RMatrixGemm(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); - //--- orthogonal factorizations - static void RMatrixQR(CMatrixDouble &a,const int m,const int n,double &tau[]); - static void RMatrixLQ(CMatrixDouble &a,const int m,const int n,double &tau[]); - static void CMatrixQR(CMatrixComplex &a,const int m,const int n,al_complex &tau[]); - static void CMatrixLQ(CMatrixComplex &a,const int m,const int n,al_complex &tau[]); - static void RMatrixQRUnpackQ(CMatrixDouble &a,const int m,const int n,double &tau[],const int qcolumns,CMatrixDouble &q); - static void RMatrixQRUnpackR(CMatrixDouble &a,const int m,const int n,CMatrixDouble &r); - static void RMatrixLQUnpackQ(CMatrixDouble &a,const int m,const int n,double &tau[],const int qrows,CMatrixDouble &q); - static void RMatrixLQUnpackL(CMatrixDouble &a,const int m,const int n,CMatrixDouble &l); - static void CMatrixQRUnpackQ(CMatrixComplex &a,const int m,const int n,al_complex &tau[],const int qcolumns,CMatrixComplex &q); - static void CMatrixQRUnpackR(CMatrixComplex &a,const int m,const int n,CMatrixComplex &r); - static void CMatrixLQUnpackQ(CMatrixComplex &a,const int m,const int n,al_complex &tau[],const int qrows,CMatrixComplex &q); - static void CMatrixLQUnpackL(CMatrixComplex &a,const int m,const int n,CMatrixComplex &l); - static void RMatrixBD(CMatrixDouble &a,const int m,const int n,double &tauq[],double &taup[]); - static void RMatrixBDUnpackQ(CMatrixDouble &qp,const int m,const int n,double &tauq[],const int qcolumns,CMatrixDouble &q); - static void RMatrixBDMultiplyByQ(CMatrixDouble &qp,const int m,const int n,double &tauq[],CMatrixDouble &z,const int zrows,const int zcolumns,const bool fromtheright,const bool dotranspose); - static void RMatrixBDUnpackPT(CMatrixDouble &qp,const int m,const int n,double &taup[],const int ptrows,CMatrixDouble &pt); - static void RMatrixBDMultiplyByP(CMatrixDouble &qp,const int m,const int n,double &taup[],CMatrixDouble &z,const int zrows,const int zcolumns,const bool fromtheright,const bool dotranspose); - static void RMatrixBDUnpackDiagonals(CMatrixDouble &b,const int m,const int n,bool &isupper,double &d[],double &e[]); - static void RMatrixHessenberg(CMatrixDouble &a,const int n,double &tau[]); - static void RMatrixHessenbergUnpackQ(CMatrixDouble &a,const int n,double &tau[],CMatrixDouble &q); - static void RMatrixHessenbergUnpackH(CMatrixDouble &a,const int n,CMatrixDouble &h); - static void SMatrixTD(CMatrixDouble &a,const int n,const bool isupper,double &tau[],double &d[],double &e[]); - static void SMatrixTDUnpackQ(CMatrixDouble &a,const int n,const bool isupper,double &tau[],CMatrixDouble &q); - static void HMatrixTD(CMatrixComplex &a,const int n,const bool isupper,al_complex &tau[],double &d[],double &e[]); - static void HMatrixTDUnpackQ(CMatrixComplex &a,const int n,const bool isupper,al_complex &tau[],CMatrixComplex &q); - //--- eigenvalues and eigenvectors - static bool SMatrixEVD(CMatrixDouble &a,const int n,int zneeded,const bool isupper,double &d[],CMatrixDouble &z); - static bool SMatrixEVDR(CMatrixDouble &a,const int n,int zneeded,const bool isupper,double b1,double b2,int &m,double &w[],CMatrixDouble &z); - static bool SMatrixEVDI(CMatrixDouble &a,const int n,int zneeded,const bool isupper,const int i1,const int i2,double &w[],CMatrixDouble &z); - static bool HMatrixEVD(CMatrixComplex &a,const int n,const int zneeded,const bool isupper,double &d[],CMatrixComplex &z); - static bool HMatrixEVDR(CMatrixComplex &a,const int n,const int zneeded,const bool isupper,double b1,double b2,int &m,double &w[],CMatrixComplex &z); - static bool HMatrixEVDI(CMatrixComplex &a,const int n,const int zneeded,const bool isupper,const int i1,const int i2,double &w[],CMatrixComplex &z); - static bool SMatrixTdEVD(double &d[],double &e[],const int n,const int zneeded,CMatrixDouble &z); - static bool SMatrixTdEVDR(double &d[],double &e[],const int n,const int zneeded,const double a,const double b,int &m,CMatrixDouble &z); - static bool SMatrixTdEVDI(double &d[],double &e[],const int n,const int zneeded,const int i1,const int i2,CMatrixDouble &z); - static bool RMatrixEVD(CMatrixDouble &a,const int n,const int vneeded,double &wr[],double &wi[],CMatrixDouble &vl,CMatrixDouble &vr); - //--- random matrix generation - static void RMatrixRndOrthogonal(const int n,CMatrixDouble &a); - static void RMatrixRndCond(const int n,const double c,CMatrixDouble &a); - static void CMatrixRndOrthogonal(const int n,CMatrixComplex &a); - static void CMatrixRndCond(const int n,const double c,CMatrixComplex &a); - static void SMatrixRndCond(const int n,const double c,CMatrixDouble &a); - static void SPDMatrixRndCond(const int n,const double c,CMatrixDouble &a); - static void HMatrixRndCond(const int n,const double c,CMatrixComplex &a); - static void HPDMatrixRndCond(const int n,const double c,CMatrixComplex &a); - static void RMatrixRndOrthogonalFromTheRight(CMatrixDouble &a,const int m,const int n); - static void RMatrixRndOrthogonalFromTheLeft(CMatrixDouble &a,const int m,const int n); - static void CMatrixRndOrthogonalFromTheRight(CMatrixComplex &a,const int m,const int n); - static void CMatrixRndOrthogonalFromTheLeft(CMatrixComplex &a,const int m,const int n); - static void SMatrixRndMultiply(CMatrixDouble &a,const int n); - static void HMatrixRndMultiply(CMatrixComplex &a,const int n); - //--- triangular factorizations - static void RMatrixLU(CMatrixDouble &a,const int m,const int n,int &pivots[]); - static void CMatrixLU(CMatrixComplex &a,const int m,const int n,int &pivots[]); - static bool HPDMatrixCholesky(CMatrixComplex &a,const int n,const bool isupper); - static bool SPDMatrixCholesky(CMatrixDouble &a,const int n,const bool isupper); - //--- estimate of the condition numbers - static double RMatrixRCond1(CMatrixDouble &a,const int n); - static double RMatrixRCondInf(CMatrixDouble &a,const int n); - static double SPDMatrixRCond(CMatrixDouble &a,const int n,const bool isupper); - static double RMatrixTrRCond1(CMatrixDouble &a,const int n,const bool isupper,const bool isunit); - static double RMatrixTrRCondInf(CMatrixDouble &a,const int n,const bool isupper,const bool isunit); - static double HPDMatrixRCond(CMatrixComplex &a,const int n,const bool isupper); - static double CMatrixRCond1(CMatrixComplex &a,const int n); - static double CMatrixRCondInf(CMatrixComplex &a,const int n); - static double RMatrixLURCond1(CMatrixDouble &lua,const int n); - static double RMatrixLURCondInf(CMatrixDouble &lua,const int n); - static double SPDMatrixCholeskyRCond(CMatrixDouble &a,const int n,const bool isupper); - static double HPDMatrixCholeskyRCond(CMatrixComplex &a,const int n,const bool isupper); - static double CMatrixLURCond1(CMatrixComplex &lua,const int n); - static double CMatrixLURCondInf(CMatrixComplex &lua,const int n); - static double CMatrixTrRCond1(CMatrixComplex &a,const int n,const bool isupper,const bool isunit); - static double CMatrixTrRCondInf(CMatrixComplex &a,const int n,const bool isupper,const bool isunit); - //--- matrix inversion - static void RMatrixLUInverse(CMatrixDouble &a,int &pivots[],const int n,int &info,CMatInvReportShell &rep); - static void RMatrixLUInverse(CMatrixDouble &a,int &pivots[],int &info,CMatInvReportShell &rep); - static void RMatrixInverse(CMatrixDouble &a,const int n,int &info,CMatInvReportShell &rep); - static void RMatrixInverse(CMatrixDouble &a,int &info,CMatInvReportShell &rep); - static void CMatrixLUInverse(CMatrixComplex &a,int &pivots[],const int n,int &info,CMatInvReportShell &rep); - static void CMatrixLUInverse(CMatrixComplex &a,int &pivots[],int &info,CMatInvReportShell &rep); - static void CMatrixInverse(CMatrixComplex &a,const int n,int &info,CMatInvReportShell &rep); - static void CMatrixInverse(CMatrixComplex &a,int &info,CMatInvReportShell &rep); - static void SPDMatrixCholeskyInverse(CMatrixDouble &a,const int n,const bool isupper,int &info,CMatInvReportShell &rep); - static void SPDMatrixCholeskyInverse(CMatrixDouble &a,int &info,CMatInvReportShell &rep); - static void SPDMatrixInverse(CMatrixDouble &a,const int n,const bool isupper,int &info,CMatInvReportShell &rep); - static void SPDMatrixInverse(CMatrixDouble &a,int &info,CMatInvReportShell &rep); - static void HPDMatrixCholeskyInverse(CMatrixComplex &a,const int n,const bool isupper,int &info,CMatInvReportShell &rep); - static void HPDMatrixCholeskyInverse(CMatrixComplex &a,int &info,CMatInvReportShell &rep); - static void HPDMatrixInverse(CMatrixComplex &a,const int n,const bool isupper,int &info,CMatInvReportShell &rep); - static void HPDMatrixInverse(CMatrixComplex &a,int &info,CMatInvReportShell &rep); - static void RMatrixTrInverse(CMatrixDouble &a,const int n,const bool isupper,const bool isunit,int &info,CMatInvReportShell &rep); - static void RMatrixTrInverse(CMatrixDouble &a,const bool isupper,int &info,CMatInvReportShell &rep); - static void CMatrixTrInverse(CMatrixComplex &a,const int n,const bool isupper,const bool isunit,int &info,CMatInvReportShell &rep); - static void CMatrixTrInverse(CMatrixComplex &a,const bool isupper,int &info,CMatInvReportShell &rep); - //--- singular value decomposition of a bidiagonal matrix - static bool RMatrixBdSVD(double &d[],double &e[],const int n,const bool isupper,bool isfractionalaccuracyrequired,CMatrixDouble &u,const int nru,CMatrixDouble &c,const int ncc,CMatrixDouble &vt,const int ncvt); - //--- singular value decomposition - static bool RMatrixSVD(CMatrixDouble &a,const int m,const int n,const int uneeded,const int vtneeded,const int additionalmemory,double &w[],CMatrixDouble &u,CMatrixDouble &vt); - //--- calculation determinant of the matrix - static double RMatrixLUDet(CMatrixDouble &a,int &pivots[],const int n); - static double RMatrixLUDet(CMatrixDouble &a,int &pivots[]); - static double RMatrixDet(CMatrixDouble &a,const int n); - static double RMatrixDet(CMatrixDouble &a); - static al_complex CMatrixLUDet(CMatrixComplex &a,int &pivots[],const int n); - static al_complex CMatrixLUDet(CMatrixComplex &a,int &pivots[]); - static al_complex CMatrixDet(CMatrixComplex &a,const int n); - static al_complex CMatrixDet(CMatrixComplex &a); - static double SPDMatrixCholeskyDet(CMatrixDouble &a,const int n); - static double SPDMatrixCholeskyDet(CMatrixDouble &a); - static double SPDMatrixDet(CMatrixDouble &a,const int n,const bool isupper); - static double SPDMatrixDet(CMatrixDouble &a); - //--- generalized symmetric positive definite eigenproblem - static bool SMatrixGEVD(CMatrixDouble &a,const int n,const bool isuppera,CMatrixDouble &b,const bool isupperb,const int zneeded,const int problemtype,double &d[],CMatrixDouble &z); - static bool SMatrixGEVDReduce(CMatrixDouble &a,const int n,const bool isuppera,CMatrixDouble &b,const bool isupperb,const int problemtype,CMatrixDouble &r,bool &isupperr); - //--- update of the inverse matrix by the Sherman-Morrison formula - static void RMatrixInvUpdateSimple(CMatrixDouble &inva,const int n,const int updrow,const int updcolumn,const double updval); - static void RMatrixInvUpdateRow(CMatrixDouble &inva,const int n,const int updrow,double &v[]); - static void RMatrixInvUpdateColumn(CMatrixDouble &inva,const int n,const int updcolumn,double &u[]); - static void RMatrixInvUpdateUV(CMatrixDouble &inva,const int n,double &u[],double &v[]); - //--- Schur decomposition - static bool RMatrixSchur(CMatrixDouble &a,const int n,CMatrixDouble &s); - //--- function of package optimization - //--- conjugate gradient method - static void MinCGCreate(const int n,double &x[],CMinCGStateShell &state); - static void MinCGCreate(double &x[],CMinCGStateShell &state); - static void MinCGCreateF(const int n,double &x[],double diffstep,CMinCGStateShell &state); - static void MinCGCreateF(double &x[],double diffstep,CMinCGStateShell &state); - static void MinCGSetCond(CMinCGStateShell &state,double epsg,double epsf,double epsx,int maxits); - static void MinCGSetScale(CMinCGStateShell &state,double &s[]); - static void MinCGSetXRep(CMinCGStateShell &state,bool needxrep); - static void MinCGSetCGType(CMinCGStateShell &state,int cgtype); - static void MinCGSetStpMax(CMinCGStateShell &state,double stpmax); - static void MinCGSuggestStep(CMinCGStateShell &state,double stp); - static void MinCGSetPrecDefault(CMinCGStateShell &state); - static void MinCGSetPrecDiag(CMinCGStateShell &state,double &d[]); - static void MinCGSetPrecScale(CMinCGStateShell &state); - static bool MinCGIteration(CMinCGStateShell &state); - static void MinCGOptimize(CMinCGStateShell &state,CNDimensional_Func &func,CNDimensional_Rep &rep,bool rep_status,CObject &obj); - static void MinCGOptimize(CMinCGStateShell &state,CNDimensional_Grad &grad,CNDimensional_Rep &rep,bool rep_status,CObject &obj); - static void MinCGResults(CMinCGStateShell &state,double &x[],CMinCGReportShell &rep); - static void MinCGResultsBuf(CMinCGStateShell &state,double &x[],CMinCGReportShell &rep); - static void MinCGRestartFrom(CMinCGStateShell &state,double &x[]); - //--- bound constrained optimization with additional linear equality and inequality constraints - static void MinBLEICCreate(const int n,double &x[],CMinBLEICStateShell &state); - static void MinBLEICCreate(double &x[],CMinBLEICStateShell &state); - static void MinBLEICCreateF(const int n,double &x[],double diffstep,CMinBLEICStateShell &state); - static void MinBLEICCreateF(double &x[],double diffstep,CMinBLEICStateShell &state); - static void MinBLEICSetBC(CMinBLEICStateShell &state,double &bndl[],double &bndu[]); - static void MinBLEICSetLC(CMinBLEICStateShell &state,CMatrixDouble &c,int &ct[],const int k); - static void MinBLEICSetLC(CMinBLEICStateShell &state,CMatrixDouble &c,int &ct[]); - static void MinBLEICSetInnerCond(CMinBLEICStateShell &state,const double epsg,const double epsf,const double epsx); - static void MinBLEICSetOuterCond(CMinBLEICStateShell &state,const double epsx,const double epsi); - static void MinBLEICSetScale(CMinBLEICStateShell &state,double &s[]); - static void MinBLEICSetPrecDefault(CMinBLEICStateShell &state); - static void MinBLEICSetPrecDiag(CMinBLEICStateShell &state,double &d[]); - static void MinBLEICSetPrecScale(CMinBLEICStateShell &state); - static void MinBLEICSetMaxIts(CMinBLEICStateShell &state,const int maxits); - static void MinBLEICSetXRep(CMinBLEICStateShell &state,bool needxrep); - static void MinBLEICSetStpMax(CMinBLEICStateShell &state,double stpmax); - static bool MinBLEICIteration(CMinBLEICStateShell &state); - static void MinBLEICOptimize(CMinBLEICStateShell &state,CNDimensional_Func &func,CNDimensional_Rep &rep,bool rep_status,CObject &obj); - static void MinBLEICOptimize(CMinBLEICStateShell &state,CNDimensional_Grad &grad,CNDimensional_Rep &rep,bool rep_status,CObject &obj); - static void MinBLEICResults(CMinBLEICStateShell &state,double &x[],CMinBLEICReportShell &rep); - static void MinBLEICResultsBuf(CMinBLEICStateShell &state,double &x[],CMinBLEICReportShell &rep); - static void MinBLEICRestartFrom(CMinBLEICStateShell &state,double &x[]); - //--- limited memory BFGS method for large scale optimization - static void MinLBFGSCreate(const int n,const int m,double &x[],CMinLBFGSStateShell &state); - static void MinLBFGSCreate(const int m,double &x[],CMinLBFGSStateShell &state); - static void MinLBFGSCreateF(const int n,const int m,double &x[],const double diffstep,CMinLBFGSStateShell &state); - static void MinLBFGSCreateF(const int m,double &x[],const double diffstep,CMinLBFGSStateShell &state); - static void MinLBFGSSetCond(CMinLBFGSStateShell &state,const double epsg,const double epsf,const double epsx,const int maxits); - static void MinLBFGSSetXRep(CMinLBFGSStateShell &state,const bool needxrep); - static void MinLBFGSSetStpMax(CMinLBFGSStateShell &state,const double stpmax); - static void MinLBFGSSetScale(CMinLBFGSStateShell &state,double &s[]); - static void MinLBFGSSetPrecDefault(CMinLBFGSStateShell &state); - static void MinLBFGSSetPrecCholesky(CMinLBFGSStateShell &state,CMatrixDouble &p,const bool isupper); - static void MinLBFGSSetPrecDiag(CMinLBFGSStateShell &state,double &d[]); - static void MinLBFGSSetPrecScale(CMinLBFGSStateShell &state); - static bool MinLBFGSIteration(CMinLBFGSStateShell &state); - static void MinLBFGSOptimize(CMinLBFGSStateShell &state,CNDimensional_Func &func,CNDimensional_Rep &rep,bool rep_status,CObject &obj); - static void MinLBFGSOptimize(CMinLBFGSStateShell &state,CNDimensional_Grad &grad,CNDimensional_Rep &rep,bool rep_status,CObject &obj); - static void MinLBFGSResults(CMinLBFGSStateShell &state,double &x[],CMinLBFGSReportShell &rep); - static void MinLBFGSresultsbuf(CMinLBFGSStateShell &state,double &x[],CMinLBFGSReportShell &rep); - static void MinLBFGSRestartFrom(CMinLBFGSStateShell &state,double &x[]); - //--- constrained quadratic programming - static void MinQPCreate(const int n,CMinQPStateShell &state); - static void MinQPSetLinearTerm(CMinQPStateShell &state,double &b[]); - static void MinQPSetQuadraticTerm(CMinQPStateShell &state,CMatrixDouble &a,const bool isupper); - static void MinQPSetQuadraticTerm(CMinQPStateShell &state,CMatrixDouble &a); - static void MinQPSetStartingPoint(CMinQPStateShell &state,double &x[]); - static void MinQPSetOrigin(CMinQPStateShell &state,double &xorigin[]); - static void MinQPSetAlgoCholesky(CMinQPStateShell &state); - static void MinQPSetBC(CMinQPStateShell &state,double &bndl[],double &bndu[]); - static void MinQPOptimize(CMinQPStateShell &state); - static void MinQPResults(CMinQPStateShell &state,double &x[],CMinQPReportShell &rep); - static void MinQPResultsBuf(CMinQPStateShell &state,double &x[],CMinQPReportShell &rep); - //--- Levenberg-Marquardt method - static void MinLMCreateVJ(const int n,const int m,double &x[],CMinLMStateShell &state); - static void MinLMCreateVJ(const int m,double &x[],CMinLMStateShell &state); - static void MinLMCreateV(const int n,const int m,double &x[],double diffstep,CMinLMStateShell &state); - static void MinLMCreateV(const int m,double &x[],const double diffstep,CMinLMStateShell &state); - static void MinLMCreateFGH(const int n,double &x[],CMinLMStateShell &state); - static void MinLMCreateFGH(double &x[],CMinLMStateShell &state); - static void MinLMSetCond(CMinLMStateShell &state,const double epsg,const double epsf,const double epsx,const int maxits); - static void MinLMSetXRep(CMinLMStateShell &state,const bool needxrep); - static void MinLMSetStpMax(CMinLMStateShell &state,const double stpmax); - static void MinLMSetScale(CMinLMStateShell &state,double &s[]); - static void MinLMSetBC(CMinLMStateShell &state,double &bndl[],double &bndu[]); - static void MinLMSetAccType(CMinLMStateShell &state,const int acctype); - static bool MinLMIteration(CMinLMStateShell &state); - static void MinLMOptimize(CMinLMStateShell &state,CNDimensional_FVec &fvec,CNDimensional_Rep &rep,bool rep_status,CObject &obj); - static void MinLMOptimize(CMinLMStateShell &state,CNDimensional_FVec &fvec,CNDimensional_Jac &jac,CNDimensional_Rep &rep,bool rep_status,CObject &obj); - static void MinLMOptimize(CMinLMStateShell &state,CNDimensional_Func &func,CNDimensional_Grad &grad,CNDimensional_Hess &hess,CNDimensional_Rep &rep,bool rep_status,CObject &obj); - static void MinLMOptimize(CMinLMStateShell &state,CNDimensional_Func &func,CNDimensional_Jac &jac,CNDimensional_Rep &rep,bool rep_status,CObject &obj); - static void MinLMOptimize(CMinLMStateShell &state,CNDimensional_Func &func,CNDimensional_Grad &grad,CNDimensional_Jac &jac,CNDimensional_Rep &rep,bool rep_status,CObject &obj); - static void MinLMResults(CMinLMStateShell &state,double &x[],CMinLMReportShell &rep); - static void MinLMResultsBuf(CMinLMStateShell &state,double &x[],CMinLMReportShell &rep); - static void MinLMRestartFrom(CMinLMStateShell &state,double &x[]); - static void MinLMCreateVGJ(const int n,const int m,double &x[],CMinLMStateShell &state); - static void MinLMCreateVGJ(const int m,double &x[],CMinLMStateShell &state); - static void MinLMCreateFGJ(const int n,const int m,double &x[],CMinLMStateShell &state); - static void MinLMCreateFGJ(const int m,double &x[],CMinLMStateShell &state); - static void MinLMCreateFJ(const int n,const int m,double &x[],CMinLMStateShell &state); - static void MinLMCreateFJ(const int m,double &x[],CMinLMStateShell &state); - //--- optimization - static void MinLBFGSSetDefaultPreconditioner(CMinLBFGSStateShell &state); - static void MinLBFGSSetCholeskyPreconditioner(CMinLBFGSStateShell &state,CMatrixDouble &p,bool isupper); - static void MinBLEICSetBarrierWidth(CMinBLEICStateShell &state,const double mu); - static void MinBLEICSetBarrierDecay(CMinBLEICStateShell &state,const double mudecay); - static void MinASACreate(const int n,double &x[],double &bndl[],double &bndu[],CMinASAStateShell &state); - static void MinASACreate(double &x[],double &bndl[],double &bndu[],CMinASAStateShell &state); - static void MinASASetCond(CMinASAStateShell &state,const double epsg,const double epsf,const double epsx,const int maxits); - static void MinASASetXRep(CMinASAStateShell &state,const bool needxrep); - static void MinASASetAlgorithm(CMinASAStateShell &state,const int algotype); - static void MinASASetStpMax(CMinASAStateShell &state,const double stpmax); - static bool MinASAIteration(CMinASAStateShell &state); - static void MinASAOptimize(CMinASAStateShell &state,CNDimensional_Grad &grad,CNDimensional_Rep &rep,bool rep_status,CObject &obj); - static void MinASAResults(CMinASAStateShell &state,double &x[],CMinASAReportShell &rep); - static void MinASAResultsBuf(CMinASAStateShell &state,double &x[],CMinASAReportShell &rep); - static void MinASARestartFrom(CMinASAStateShell &state,double &x[],double &bndl[],double &bndu[]); - //--- function of package solvers - //--- dense solver - static void RMatrixSolve(CMatrixDouble &a,const int n,double &b[],int &info,CDenseSolverReportShell &rep,double &x[]); - static void RMatrixSolveM(CMatrixDouble &a,const int n,CMatrixDouble &b,const int m,const bool rfs,int &info,CDenseSolverReportShell &rep,CMatrixDouble &x); - static void RMatrixLUSolve(CMatrixDouble &lua,int &p[],const int n,double &b[],int &info,CDenseSolverReportShell &rep,double &x[]); - static void RMatrixLUSolveM(CMatrixDouble &lua,int &p[],const int n,CMatrixDouble &b,const int m,int &info,CDenseSolverReportShell &rep,CMatrixDouble &x); - static void RMatrixMixedSolve(CMatrixDouble &a,CMatrixDouble &lua,int &p[],const int n,double &b[],int &info,CDenseSolverReportShell &rep,double &x[]); - static void RMatrixMixedSolveM(CMatrixDouble &a,CMatrixDouble &lua,int &p[],const int n,CMatrixDouble &b,const int m,int &info,CDenseSolverReportShell &rep,CMatrixDouble &x); - static void CMatrixSolveM(CMatrixComplex &a,const int n,CMatrixComplex &b,const int m,const bool rfs,int &info,CDenseSolverReportShell &rep,CMatrixComplex &x); - static void CMatrixSolve(CMatrixComplex &a,const int n,al_complex &b[],int &info,CDenseSolverReportShell &rep,al_complex &x[]); - static void CMatrixLUSolveM(CMatrixComplex &lua,int &p[],const int n,CMatrixComplex &b,const int m,int &info,CDenseSolverReportShell &rep,CMatrixComplex &x); - static void CMatrixLUSolve(CMatrixComplex &lua,int &p[],const int n,al_complex &b[],int &info,CDenseSolverReportShell &rep,al_complex &x[]); - static void CMatrixMixedSolveM(CMatrixComplex &a,CMatrixComplex &lua,int &p[],const int n,CMatrixComplex &b,const int m,int &info,CDenseSolverReportShell &rep,CMatrixComplex &x); - static void CMatrixMixedSolve(CMatrixComplex &a,CMatrixComplex &lua,int &p[],const int n,al_complex &b[],int &info,CDenseSolverReportShell &rep,al_complex &x[]); - static void SPDMatrixSolveM(CMatrixDouble &a,const int n,const bool isupper,CMatrixDouble &b,const int m,int &info,CDenseSolverReportShell &rep,CMatrixDouble &x); - static void SPDMatrixSolve(CMatrixDouble &a,const int n,const bool isupper,double &b[],int &info,CDenseSolverReportShell &rep,double &x[]); - static void SPDMatrixCholeskySolveM(CMatrixDouble &cha,const int n,const bool isupper,CMatrixDouble &b,const int m,int &info,CDenseSolverReportShell &rep,CMatrixDouble &x); - static void SPDMatrixCholeskySolve(CMatrixDouble &cha,const int n,const bool isupper,double &b[],int &info,CDenseSolverReportShell &rep,double &x[]); - static void HPDMatrixSolveM(CMatrixComplex &a,const int n,const bool isupper,CMatrixComplex &b,const int m,int &info,CDenseSolverReportShell &rep,CMatrixComplex &x); - static void HPDMatrixSolve(CMatrixComplex &a,const int n,const bool isupper,al_complex &b[],int &info,CDenseSolverReportShell &rep,al_complex &x[]); - static void HPDMatrixCholeskySolveM(CMatrixComplex &cha,const int n,const bool isupper,CMatrixComplex &b,const int m,int &info,CDenseSolverReportShell &rep,CMatrixComplex &x); - static void HPDMatrixCholeskySolve(CMatrixComplex &cha,const int n,const bool isupper,al_complex &b[],int &info,CDenseSolverReportShell &rep,al_complex &x[]); - static void RMatrixSolveLS(CMatrixDouble &a,const int nrows,const int ncols,double &b[],const double threshold,int &info,CDenseSolverLSReportShell &rep,double &x[]); - //--- solving systems of nonlinear equations - static void NlEqCreateLM(const int n,const int m,double &x[],CNlEqStateShell &state); - static void NlEqCreateLM(const int m,double &x[],CNlEqStateShell &state); - static void NlEqSetCond(CNlEqStateShell &state,const double epsf,const int maxits); - static void NlEqSetXRep(CNlEqStateShell &state,const bool needxrep); - static void NlEqSetStpMax(CNlEqStateShell &state,const double stpmax); - static bool NlEqIteration(CNlEqStateShell &state); - static void NlEqSolve(CNlEqStateShell &state,CNDimensional_Func &func,CNDimensional_Jac &jac,CNDimensional_Rep &rep,bool rep_status,CObject &obj); - static void NlEqResults(CNlEqStateShell &state,double &x[],CNlEqReportShell &rep); - static void NlEqResultsBuf(CNlEqStateShell &state,double &x[],CNlEqReportShell &rep); - static void NlEqRestartFrom(CNlEqStateShell &state,double &x[]); - //--- function of package specialfunctions - //--- gamma function - static double GammaFunction(const double x); - static double LnGamma(const double x,double &sgngam); - //--- normal distribution - static double ErrorFunction(const double x); - static double ErrorFunctionC(const double x); - static double NormalDistribution(const double x); - static double InvErF(double e); - static double InvNormalDistribution(const double y0); - //--- incomplete gamma function - static double IncompleteGamma(const double a,const double x); - static double IncompleteGammaC(const double a,const double x); - static double InvIncompleteGammaC(const double a,const double y0); - //--- airy function - static void Airy(const double x,double &ai,double &aip,double &bi,double &bip); - //--- Bessel function - static double BesselJ0(const double x); - static double BesselJ1(const double x); - static double BesselJN(const int n,const double x); - static double BesselY0(const double x); - static double BesselY1(const double x); - static double BesselYN(const int n,const double x); - static double BesselI0(const double x); - static double BesselI1(const double x); - static double BesselK0(const double x); - static double BesselK1(const double x); - static double BesselKN(const int nn,const double x); - //--- beta function - static double Beta(const double a,const double b); - static double IncompleteBeta(const double a,const double b,const double x); - static double InvIncompleteBeta(const double a,const double b,double y); - //--- binomial distribution - static double BinomialDistribution(const int k,const int n,const double p); - static double BinomialComplDistribution(const int k,const int n,const double p); - static double InvBinomialDistribution(const int k,const int n,const double y); - //--- Chebyshev polynom - static double ChebyshevCalculate(int r,const int n,const double x); - static double ChebyshevSum(double &c[],const int r,const int n,const double x); - static void ChebyshevCoefficients(const int n,double &c[]); - static void FromChebyshev(double &a[],const int n,double &b[]); - //--- chi-square distribution - static double ChiSquareDistribution(const double v,const double x); - static double ChiSquareComplDistribution(const double v,const double x); - static double InvChiSquareDistribution(const double v,const double y); - //--- Dawson's Integral - static double DawsonIntegral(const double x); - //--- elliptic integral - static double EllipticIntegralK(const double m); - static double EllipticIntegralKhighPrecision(const double m1); - static double IncompleteEllipticIntegralK(const double phi,const double m); - static double EllipticIntegralE(const double m); - static double IncompleteEllipticIntegralE(const double phi,const double m); - //--- exponential integral - static double ExponentialIntegralEi(const double x); - static double ExponentialIntegralEn(const double x,const int n); - //--- F distribution functions - static double FDistribution(const int a,const int b,const double x); - static double FComplDistribution(const int a,const int b,const double x); - static double InvFDistribution(const int a,const int b,const double y); - //--- Fresnel integral - static void FresnelIntegral(const double x,double &c,double &s); - //--- Hermite polynomial - static double HermiteCalculate(const int n,const double x); - static double HermiteSum(double &c[],const int n,const double x); - static void HermiteCoefficients(const int n,double &c[]); - //--- Jacobian elliptic functions - static void JacobianEllipticFunctions(const double u,const double m,double &sn,double &cn,double &dn,double &ph); - //--- Laguerre polynomial - static double LaguerreCalculate(const int n,const double x); - static double LaguerreSum(double &c[],const int n,const double x); - static void LaguerreCoefficients(const int n,double &c[]); - //--- Legendre polynomial - static double LegendreCalculate(const int n,const double x); - static double LegendreSum(double &c[],const int n,const double x); - static void LegendreCoefficients(const int n,double &c[]); - //--- Poisson distribution - static double PoissonDistribution(const int k,const double m); - static double PoissonComplDistribution(const int k,const double m); - static double InvPoissonDistribution(const int k,const double y); - //--- psi function - static double Psi(const double x); - //--- Student's t distribution - static double StudenttDistribution(const int k,const double t); - static double InvStudenttDistribution(const int k,const double p); - //--- trigonometric integrals - static void SineCosineIntegrals(const double x,double &si,double &ci); - static void HyperbolicSineCosineIntegrals(const double x,double &shi,double &chi); - //--- function of package statistics - //--- basic statistics methods - static void SampleMoments(const double &x[],const int n,double &mean,double &variance,double &skewness,double &kurtosis); - static void SampleMoments(const double &x[],double &mean,double &variance,double &skewness,double &kurtosis); - static void SampleAdev(const double &x[],const int n,double &adev); - static void SampleAdev(const double &x[],double &adev); - static void SampleMedian(const double &x[],const int n,double &median); - static void SampleMedian(const double &x[],double &median); - static void SamplePercentile(const double &x[],const int n,const double p,double &v); - static void SamplePercentile(const double &x[],const double p,double &v); - static double Cov2(const double &x[],const double &y[],const int n); - static double Cov2(const double &x[],const double &y[]); - static double PearsonCorr2(const double &x[],const double &y[],const int n); - static double PearsonCorr2(const double &x[],const double &y[]); - static double SpearmanCorr2(const double &x[],const double &y[],const int n); - static double SpearmanCorr2(const double &x[],const double &y[]); - static void CovM(const CMatrixDouble &x,const int n,const int m,CMatrixDouble &c); - static void CovM(const CMatrixDouble &x,CMatrixDouble &c); - static void PearsonCorrM(const CMatrixDouble &x,const int n,const int m,CMatrixDouble &c); - static void PearsonCorrM(CMatrixDouble &x,CMatrixDouble &c); - static void SpearmanCorrM(const CMatrixDouble &x,const int n,const int m,CMatrixDouble &c); - static void SpearmanCorrM(const CMatrixDouble &x,CMatrixDouble &c); - static void CovM2(const CMatrixDouble &x,const CMatrixDouble &y,const int n,const int m1,const int m2,CMatrixDouble &c); - static void CovM2(const CMatrixDouble &x,const CMatrixDouble &y,CMatrixDouble &c); - static void PearsonCorrM2(const CMatrixDouble &x,const CMatrixDouble &y,const int n,const int m1,const int m2,CMatrixDouble &c); - static void PearsonCorrM2(const CMatrixDouble &x,const CMatrixDouble &y,CMatrixDouble &c); - static void SpearmanCorrM2(const CMatrixDouble &x,const CMatrixDouble &y,const int n,const int m1,const int m2,CMatrixDouble &c); - static void SpearmanCorrM2(const CMatrixDouble &x,const CMatrixDouble &y,CMatrixDouble &c); - //--- correlation tests - static void PearsonCorrelationSignificance(const double r,const int n,double &bothTails,double &leftTail,double &rightTail); - static void SpearmanRankCorrelationSignificance(const double r,const int n,double &bothTails,double &leftTail,double &rightTail); - //--- Jarque-Bera test - static void JarqueBeraTest(const double &x[],const int n,double &p); - //--- Mann-Whitney U-test - static void MannWhitneyUTest(const double &x[],const int n,const double &y[],const int m,double &bothTails,double &leftTail,double &rightTail); - //--- sign test - static void OneSampleSignTest(const double &x[],const int n,const double median,double &bothTails,double &leftTail,double &rightTail); - //--- Studentt Tests - static void StudentTest1(const double &x[],const int n,const double mean,double &bothTails,double &leftTail,double &rightTail); - static void StudentTest2(const double &x[],const int n,const double &y[],const int m,double &bothTails,double &leftTail,double &rightTail); - static void UnequalVarianceTest(const double &x[],const int n,const double &y[],const int m,double &bothTails,double &leftTail,double &rightTail); - //--- variance tests - static void FTest(const double &x[],const int n,const double &y[],const int m,double &bothTails,double &leftTail,double &rightTail); - static void OneSampleVarianceTest(double &x[],int n,double variance,double &bothTails,double &leftTail,double &rightTail); - //--- Wilcoxon signed-rank test - static void WilcoxonSignedRankTest(const double &x[],const int n,const double e,double &bothTails,double &leftTail,double &rightTail); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CAlglib::CAlglib(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CAlglib::~CAlglib(void) - { - - } -//+------------------------------------------------------------------+ -//| HQRNDState initialization with random values which come from | -//| standard RNG. | -//+------------------------------------------------------------------+ -static void CAlglib::HQRndRandomize(CHighQualityRandStateShell &state) - { -//--- function call - CHighQualityRand::HQRndRandomize(state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| HQRNDState initialization with seed values | -//+------------------------------------------------------------------+ -static void CAlglib::HQRndSeed(const int s1,const int s2,CHighQualityRandStateShell &state) - { -//--- function call - CHighQualityRand::HQRndSeed(s1,s2,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function generates random real number in (0,1), | -//| not including interval boundaries | -//| State structure must be initialized with HQRNDRandomize() or | -//| HQRNDSeed(). | -//+------------------------------------------------------------------+ -static double CAlglib::HQRndUniformR(CHighQualityRandStateShell &state) - { -//--- return result - return(CHighQualityRand::HQRndUniformR(state.GetInnerObj())); - } -//+------------------------------------------------------------------+ -//| This function generates random integer number in [0, N) | -//| 1. N must be less than HQRNDMax-1. | -//| 2. State structure must be initialized with HQRNDRandomize() or | -//| HQRNDSeed() | -//+------------------------------------------------------------------+ -static int CAlglib::HQRndUniformI(CHighQualityRandStateShell &state,const int n) - { -//--- return result - return(CHighQualityRand::HQRndUniformI(state.GetInnerObj(),n)); - } -//+------------------------------------------------------------------+ -//| Random number generator: normal numbers | -//| This function generates one random number from normal | -//| distribution. | -//| Its performance is equal to that of HQRNDNormal2() | -//| State structure must be initialized with HQRNDRandomize() or | -//| HQRNDSeed(). | -//+------------------------------------------------------------------+ -static double CAlglib::HQRndNormal(CHighQualityRandStateShell &state) - { -//--- return result - return(CHighQualityRand::HQRndNormal(state.GetInnerObj())); - } -//+------------------------------------------------------------------+ -//| Random number generator: random X and Y such that X^2+Y^2=1 | -//| State structure must be initialized with HQRNDRandomize() or | -//| HQRNDSeed(). | -//+------------------------------------------------------------------+ -static void CAlglib::HQRndUnit2(CHighQualityRandStateShell &state, - double &x,double &y) - { -//--- initialization - x=0; - y=0; -//--- function call - CHighQualityRand::HQRndUnit2(state.GetInnerObj(),x,y); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Random number generator: normal numbers | -//| This function generates two independent random numbers from | -//| normal distribution. Its performance is equal to that of | -//| HQRNDNormal() | -//| State structure must be initialized with HQRNDRandomize() or | -//| HQRNDSeed(). | -//+------------------------------------------------------------------+ -static void CAlglib::HQRndNormal2(CHighQualityRandStateShell &state, - double &x1,double &x2) - { -//--- initialization - x1=0; - x2=0; -//--- function call - CHighQualityRand::HQRndNormal2(state.GetInnerObj(),x1,x2); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Random number generator: exponential distribution | -//| State structure must be initialized with HQRNDRandomize() or | -//| HQRNDSeed(). | -//+------------------------------------------------------------------+ -static double CAlglib::HQRndExponential(CHighQualityRandStateShell &state, - const double lambdav) - { -//--- return result - return(CHighQualityRand::HQRndExponential(state.GetInnerObj(),lambdav)); - } -//+------------------------------------------------------------------+ -//| This function serializes data structure to string. | -//| Important properties of s_out: | -//| * it contains alphanumeric characters, dots, underscores, minus | -//| signs | -//| * these symbols are grouped into words, which are separated by | -//| spaces and Windows-style (CR+LF) newlines | -//| * although serializer uses spaces and CR+LF as separators, you | -//| can replace any separator character by arbitrary combination | -//| of spaces, tabs, Windows or Unix newlines. It allows flexible | -//| reformatting of the string in case you want to include it into | -//| text or XML file. But you should not insert separators into the| -//| middle of the "words" nor you should change case of letters. | -//| * s_out can be freely moved between 32-bit and 64-bit systems, | -//| little and big endian machines, and so on. You can serialize | -//| structure on 32-bit machine and unserialize it on 64-bit one | -//| (or vice versa), or serialize it on SPARC and unserialize on | -//| x86. You can also serialize it in C# version of ALGLIB and | -//| unserialize in C++ one, and vice versa. | -//+------------------------------------------------------------------+ -static void CAlglib::KDTreeSerialize(CKDTreeShell &obj,string &s_out) - { -//--- object of class - CSerializer s; - s.Alloc_Start(); -//--- function call - CNearestNeighbor::KDTreeAlloc(s,obj.GetInnerObj()); - s.SStart_Str(); -//--- function call - CNearestNeighbor::KDTreeSerialize(s,obj.GetInnerObj()); - s.Stop(); -//--- get result - s_out=s.Get_String(); - } -//+------------------------------------------------------------------+ -//| This function unserializes data structure from string. | -//+------------------------------------------------------------------+ -static void CAlglib::KDTreeUnserialize(string s_in,CKDTreeShell &obj) - { -//--- object of class - CSerializer s; - s.UStart_Str(s_in); -//--- function call - CNearestNeighbor::KDTreeUnserialize(s,obj.GetInnerObj()); - s.Stop(); - } -//+------------------------------------------------------------------+ -//| KD-tree creation | -//| This subroutine creates KD-tree from set of X-values and optional| -//| Y-values | -//| INPUT PARAMETERS | -//| XY - dataset, array[0..N-1,0..NX+NY-1]. | -//| one row corresponds to one point. | -//| first NX columns contain X-values, next NY (NY | -//| may be zero) | -//| columns may contain associated Y-values | -//| N - number of points, N>=1 | -//| NX - space dimension, NX>=1. | -//| NY - number of optional Y-values, NY>=0. | -//| NormType- norm type: | -//| * 0 denotes infinity-norm | -//| * 1 denotes 1-norm | -//| * 2 denotes 2-norm (Euclidean norm) | -//| OUTPUT PARAMETERS | -//| KDT - KD-tree | -//| NOTES | -//| 1. KD-tree creation have O(N*logN) complexity and | -//| O(N*(2*NX+NY)) memory requirements. | -//| 2. Although KD-trees may be used with any combination of N and | -//| NX, they are more efficient than brute-force search only when | -//| N >> 4^NX. So they are most useful in low-dimensional tasks | -//| (NX=2, NX=3). NX=1 is another inefficient case, because | -//| simple binary search (without additional structures) is | -//| much more efficient in such tasks than KD-trees. | -//+------------------------------------------------------------------+ -static void CAlglib::KDTreeBuild(CMatrixDouble &xy,const int n,const int nx, - const int ny,const int normtype,CKDTreeShell &kdt) - { -//--- function call - CNearestNeighbor::KDTreeBuild(xy,n,nx,ny,normtype,kdt.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| KD-tree creation | -//| This subroutine creates KD-tree from set of X-values and optional| -//| Y-values | -//| INPUT PARAMETERS | -//| XY - dataset, array[0..N-1,0..NX+NY-1]. | -//| one row corresponds to one point. | -//| first NX columns contain X-values, next NY (NY | -//| may be zero) | -//| columns may contain associated Y-values | -//| N - number of points, N>=1 | -//| NX - space dimension, NX>=1. | -//| NY - number of optional Y-values, NY>=0. | -//| NormType- norm type: | -//| * 0 denotes infinity-norm | -//| * 1 denotes 1-norm | -//| * 2 denotes 2-norm (Euclidean norm) | -//| OUTPUT PARAMETERS | -//| KDT - KD-tree | -//| NOTES | -//| 1. KD-tree creation have O(N*logN) complexity and | -//| O(N*(2*NX+NY)) memory requirements. | -//| 2. Although KD-trees may be used with any combination of N and | -//| NX, they are more efficient than brute-force search only when | -//| N >> 4^NX. So they are most useful in low-dimensional tasks | -//| (NX=2, NX=3). NX=1 is another inefficient case, because | -//| simple binary search (without additional structures) is | -//| much more efficient in such tasks than KD-trees. | -//+------------------------------------------------------------------+ -static void CAlglib::KDTreeBuild(CMatrixDouble &xy,const int nx,const int ny, - const int normtype,CKDTreeShell &kdt) - { -//--- create a variable - int n=CAp::Rows(xy); -//--- function call - CNearestNeighbor::KDTreeBuild(xy,n,nx,ny,normtype,kdt.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| KD-tree creation | -//| This subroutine creates KD-tree from set of X-values, integer | -//| tags and optional Y-values | -//| INPUT PARAMETERS | -//| XY - dataset, array[0..N-1,0..NX+NY-1]. | -//| one row corresponds to one point. | -//| first NX columns contain X-values, next NY (NY | -//| may be zero) | -//| columns may contain associated Y-values | -//| Tags - tags, array[0..N-1], contains integer tags | -//| associated with points. | -//| N - number of points, N>=1 | -//| NX - space dimension, NX>=1. | -//| NY - number of optional Y-values, NY>=0. | -//| NormType- norm type: | -//| * 0 denotes infinity-norm | -//| * 1 denotes 1-norm | -//| * 2 denotes 2-norm (Euclidean norm) | -//| OUTPUT PARAMETERS | -//| KDT - KD-tree | -//| NOTES | -//| 1. KD-tree creation have O(N*logN) complexity and | -//| O(N*(2*NX+NY)) memory requirements. | -//| 2. Although KD-trees may be used with any combination of N and | -//| NX, they are more efficient than brute-force search only when | -//| N >> 4^NX. So they are most useful in low-dimensional tasks | -//| (NX=2, NX=3). NX=1 is another inefficient case, because simple| -//| binary search (without additional structures) is much more | -//| efficient in such tasks than KD-trees. | -//+------------------------------------------------------------------+ -static void CAlglib::KDTreeBuildTagged(CMatrixDouble &xy,int &tags[], - const int n,const int nx, - const int ny,const int normtype, - CKDTreeShell &kdt) - { -//--- function call - CNearestNeighbor::KDTreeBuildTagged(xy,tags,n,nx,ny,normtype,kdt.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| KD-tree creation | -//| This subroutine creates KD-tree from set of X-values, integer | -//| tags and optional Y-values | -//| INPUT PARAMETERS | -//| XY - dataset, array[0..N-1,0..NX+NY-1]. | -//| one row corresponds to one point. | -//| first NX columns contain X-values, next NY (NY | -//| may be zero) | -//| columns may contain associated Y-values | -//| Tags - tags, array[0..N-1], contains integer tags | -//| associated with points. | -//| N - number of points, N>=1 | -//| NX - space dimension, NX>=1. | -//| NY - number of optional Y-values, NY>=0. | -//| NormType- norm type: | -//| * 0 denotes infinity-norm | -//| * 1 denotes 1-norm | -//| * 2 denotes 2-norm (Euclidean norm) | -//| OUTPUT PARAMETERS | -//| KDT - KD-tree | -//| NOTES | -//| 1. KD-tree creation have O(N*logN) complexity and | -//| O(N*(2*NX+NY)) memory requirements. | -//| 2. Although KD-trees may be used with any combination of N and | -//| NX, they are more efficient than brute-force search only when | -//| N >> 4^NX. So they are most useful in low-dimensional tasks | -//| (NX=2, NX=3). NX=1 is another inefficient case, because simple| -//| binary search (without additional structures) is much more | -//| efficient in such tasks than KD-trees. | -//+------------------------------------------------------------------+ -static void CAlglib::KDTreeBuildTagged(CMatrixDouble &xy,int &tags[], - const int nx,const int ny, - const int normtype,CKDTreeShell &kdt) - { -//--- create a variable - int n; - if((CAp::Rows(xy)!=CAp::Len(tags))) - { - Print(__FUNCTION__+": looks like one of arguments has wrong size"); - CAp::exception_happened=true; - return; - } -//--- initialization - n=CAp::Rows(xy); -//--- function call - CNearestNeighbor::KDTreeBuildTagged(xy,tags,n,nx,ny,normtype,kdt.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| K-NN query: K nearest neighbors | -//| INPUT PARAMETERS | -//| KDT - KD-tree | -//| X - point, array[0..NX-1]. | -//| K - number of neighbors to return, K>=1 | -//| SelfMatch - whether self-matches are allowed: | -//| * if True, nearest neighbor may be the point | -//| itself (if it exists in original dataset) | -//| * if False, then only points with non-zero | -//| distance are returned | -//| * if not given, considered True | -//| RESULT | -//| number of actual neighbors found (either K or N, if K>N). | -//| This subroutine performs query and stores its result in the | -//| internal structures of the KD-tree. You can use following | -//| subroutines to obtain these results: | -//| * KDTreeQueryResultsX() to get X-values | -//| * KDTreeQueryResultsXY() to get X- and Y-values | -//| * KDTreeQueryResultsTags() to get tag values | -//| * KDTreeQueryResultsDistances() to get distances | -//+------------------------------------------------------------------+ -static int CAlglib::KDTreeQueryKNN(CKDTreeShell &kdt,double &x[], - const int k,const bool selfmatch) - { -//--- return result - return(CNearestNeighbor::KDTreeQueryKNN(kdt.GetInnerObj(),x,k,selfmatch)); - } -//+------------------------------------------------------------------+ -//| K-NN query: K nearest neighbors | -//| INPUT PARAMETERS | -//| KDT - KD-tree | -//| X - point, array[0..NX-1]. | -//| K - number of neighbors to return, K>=1 | -//| SelfMatch - whether self-matches are allowed: | -//| * if True, nearest neighbor may be the point | -//| itself (if it exists in original dataset) | -//| * if False, then only points with non-zero | -//| distance are returned | -//| * if not given, considered True | -//| RESULT | -//| number of actual neighbors found (either K or N, if K>N). | -//| This subroutine performs query and stores its result in the | -//| internal structures of the KD-tree. You can use following | -//| subroutines to obtain these results: | -//| * KDTreeQueryResultsX() to get X-values | -//| * KDTreeQueryResultsXY() to get X- and Y-values | -//| * KDTreeQueryResultsTags() to get tag values | -//| * KDTreeQueryResultsDistances() to get distances | -//+------------------------------------------------------------------+ -static int CAlglib::KDTreeQueryKNN(CKDTreeShell &kdt,double &x[],const int k) - { -//--- create a variable - bool selfmatch=true; -//--- return result - return(CNearestNeighbor::KDTreeQueryKNN(kdt.GetInnerObj(),x,k,selfmatch)); - } -//+------------------------------------------------------------------+ -//| R-NN query: all points within R-sphere centered at X | -//| INPUT PARAMETERS | -//| KDT - KD-tree | -//| X - point, array[0..NX-1]. | -//| R - radius of sphere (in corresponding norm), R>0| -//| SelfMatch - whether self-matches are allowed: | -//| * if True, nearest neighbor may be the point | -//| itself (if it exists in original dataset) | -//| * if False, then only points with non-zero | -//| distance are returned | -//| * if not given, considered True | -//| RESULT | -//| number of neighbors found, >=0 | -//| This subroutine performs query and stores its result in the | -//| internal structures of the KD-tree. You can use following | -//| subroutines to obtain actual results: | -//| * KDTreeQueryResultsX() to get X-values | -//| * KDTreeQueryResultsXY() to get X- and Y-values | -//| * KDTreeQueryResultsTags() to get tag values | -//| * KDTreeQueryResultsDistances() to get distances | -//+------------------------------------------------------------------+ -static int CAlglib::KDTreeQueryRNN(CKDTreeShell &kdt,double &x[], - const double r,const bool selfmatch) - { -//--- return result - return(CNearestNeighbor::KDTreeQueryRNN(kdt.GetInnerObj(),x,r,selfmatch)); - } -//+------------------------------------------------------------------+ -//| R-NN query: all points within R-sphere centered at X | -//| INPUT PARAMETERS | -//| KDT - KD-tree | -//| X - point, array[0..NX-1]. | -//| R - radius of sphere (in corresponding norm), R>0| -//| SelfMatch - whether self-matches are allowed: | -//| * if True, nearest neighbor may be the point | -//| itself (if it exists in original dataset) | -//| * if False, then only points with non-zero | -//| distance are returned | -//| * if not given, considered True | -//| RESULT | -//| number of neighbors found, >=0 | -//| This subroutine performs query and stores its result in the | -//| internal structures of the KD-tree. You can use following | -//| subroutines to obtain actual results: | -//| * KDTreeQueryResultsX() to get X-values | -//| * KDTreeQueryResultsXY() to get X- and Y-values | -//| * KDTreeQueryResultsTags() to get tag values | -//| * KDTreeQueryResultsDistances() to get distances | -//+------------------------------------------------------------------+ -static int CAlglib::KDTreeQueryRNN(CKDTreeShell &kdt,double &x[],const double r) - { -//--- create a variable - bool selfmatch=true; -//--- return result - return(CNearestNeighbor::KDTreeQueryRNN(kdt.GetInnerObj(),x,r,selfmatch)); - } -//+------------------------------------------------------------------+ -//| K-NN query: approximate K nearest neighbors | -//| INPUT PARAMETERS | -//| KDT - KD-tree | -//| X - point, array[0..NX-1]. | -//| K - number of neighbors to return, K>=1 | -//| SelfMatch - whether self-matches are allowed: | -//| * if True, nearest neighbor may be the point | -//| itself (if it exists in original dataset) | -//| * if False, then only points with non-zero | -//| distance are returned | -//| * if not given, considered True | -//| Eps - approximation factor, Eps>=0. eps-approximate| -//| nearest neighbor is a neighbor whose distance| -//| from X is at most (1+eps) times distance of | -//| true nearest neighbor. | -//| RESULT | -//| number of actual neighbors found (either K or N, if K>N). | -//| NOTES | -//| significant performance gain may be achieved only when Eps is| -//| on the order of magnitude of 1 or larger. | -//| This subroutine performs query and stores its result in the | -//| internal structures of the KD-tree. You can use following | -//| these subroutines to obtain results: | -//| * KDTreeQueryResultsX() to get X-values | -//| * KDTreeQueryResultsXY() to get X- and Y-values | -//| * KDTreeQueryResultsTags() to get tag values | -//| * KDTreeQueryResultsDistances() to get distances | -//+------------------------------------------------------------------+ -static int CAlglib::KDTreeQueryAKNN(CKDTreeShell &kdt,double &x[], - const int k,const bool selfmatch, - const double eps) - { -//--- return result - return(CNearestNeighbor::KDTreeQueryAKNN(kdt.GetInnerObj(),x,k,selfmatch,eps)); - } -//+------------------------------------------------------------------+ -//| K-NN query: approximate K nearest neighbors | -//| INPUT PARAMETERS | -//| KDT - KD-tree | -//| X - point, array[0..NX-1]. | -//| K - number of neighbors to return, K>=1 | -//| SelfMatch - whether self-matches are allowed: | -//| * if True, nearest neighbor may be the point | -//| itself (if it exists in original dataset) | -//| * if False, then only points with non-zero | -//| distance are returned | -//| * if not given, considered True | -//| Eps - approximation factor, Eps>=0. eps-approximate| -//| nearest neighbor is a neighbor whose distance| -//| from X is at most (1+eps) times distance of | -//| true nearest neighbor. | -//| RESULT | -//| number of actual neighbors found (either K or N, if K>N). | -//| NOTES | -//| significant performance gain may be achieved only when Eps is| -//| on the order of magnitude of 1 or larger. | -//| This subroutine performs query and stores its result in the | -//| internal structures of the KD-tree. You can use following | -//| these subroutines to obtain results: | -//| * KDTreeQueryResultsX() to get X-values | -//| * KDTreeQueryResultsXY() to get X- and Y-values | -//| * KDTreeQueryResultsTags() to get tag values | -//| * KDTreeQueryResultsDistances() to get distances | -//+------------------------------------------------------------------+ -static int CAlglib::KDTreeQueryAKNN(CKDTreeShell &kdt,double &x[], - const int k,const double eps) - { -//--- create a variable - bool selfmatch=true; -//--- return result - return(CNearestNeighbor::KDTreeQueryAKNN(kdt.GetInnerObj(),x,k,selfmatch,eps)); - } -//+------------------------------------------------------------------+ -//| X-values from last query | -//| INPUT PARAMETERS | -//| KDT - KD-tree | -//| X - possibly pre-allocated buffer. If X is too small | -//| to store result, it is resized. If size(X) is | -//| enough to store result, it is left unchanged. | -//| OUTPUT PARAMETERS | -//| X - rows are filled with X-values | -//| NOTES | -//| 1. points are ordered by distance from the query point (first = | -//| closest) | -//| 2. if XY is larger than required to store result, only leading | -//| part will be overwritten; trailing part will be left | -//| unchanged. So if on input XY = [[A,B],[C,D]], and result is | -//| [1,2], then on exit we will get XY = [[1,2],[C,D]]. This is | -//| done purposely to increase performance; if you want function | -//| to resize array according to result size, use function with | -//| same name and suffix 'I'. | -//| SEE ALSO | -//| * KDTreeQueryResultsXY() X- and Y-values | -//| * KDTreeQueryResultsTags() tag values | -//| * KDTreeQueryResultsDistances() distances | -//+------------------------------------------------------------------+ -static void CAlglib::KDTreeQueryResultsX(CKDTreeShell &kdt,CMatrixDouble &x) - { -//--- function call - CNearestNeighbor::KDTreeQueryResultsX(kdt.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ -//| X- and Y-values from last query | -//| INPUT PARAMETERS | -//| KDT - KD-tree | -//| XY - possibly pre-allocated buffer. If XY is too small| -//| to store result, it is resized. If size(XY) is | -//| enough to store result, it is left unchanged. | -//| OUTPUT PARAMETERS | -//| XY - rows are filled with points: first NX columns | -//| with X-values, next NY columns - with Y-values. | -//| NOTES | -//| 1. points are ordered by distance from the query point (first = | -//| closest) | -//| 2. if XY is larger than required to store result, only leading | -//| part will be overwritten; trailing part will be left | -//| unchanged. So if on input XY = [[A,B],[C,D]], and result is | -//| [1,2], then on exit we will get XY = [[1,2],[C,D]]. This is | -//| done purposely to increase performance; if you want function | -//| to resize array according to result size, use function with | -//| same name and suffix 'I'. | -//| SEE ALSO | -//| * KDTreeQueryResultsX() X-values | -//| * KDTreeQueryResultsTags() tag values | -//| * KDTreeQueryResultsDistances() distances | -//+------------------------------------------------------------------+ -static void CAlglib::KDTreeQueryResultsXY(CKDTreeShell &kdt,CMatrixDouble &xy) - { -//--- function call - CNearestNeighbor::KDTreeQueryResultsXY(kdt.GetInnerObj(),xy); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Tags from last query | -//| INPUT PARAMETERS | -//| KDT - KD-tree | -//| Tags - possibly pre-allocated buffer. If X is too small | -//| to store result, it is resized. If size(X) is | -//| enough to store result, it is left unchanged. | -//| OUTPUT PARAMETERS | -//| Tags - filled with tags associated with points, | -//| or, when no tags were supplied, with zeros | -//| NOTES | -//| 1. points are ordered by distance from the query point (first | -//| = closest) | -//| 2. if XY is larger than required to store result, only leading | -//| part will be overwritten; trailing part will be left | -//| unchanged. So if on input XY = [[A,B],[C,D]], and result is | -//| [1,2], then on exit we will get XY = [[1,2],[C,D]]. This is | -//| done purposely to increase performance; if you want function | -//| to resize array according to result size, use function with | -//| same name and suffix 'I'. | -//| SEE ALSO | -//| * KDTreeQueryResultsX() X-values | -//| * KDTreeQueryResultsXY() X- and Y-values | -//| * KDTreeQueryResultsDistances() distances | -//+------------------------------------------------------------------+ -static void CAlglib::KDTreeQueryResultsTags(CKDTreeShell &kdt,int &tags[]) - { -//--- function call - CNearestNeighbor::KDTreeQueryResultsTags(kdt.GetInnerObj(),tags); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Distances from last query | -//| INPUT PARAMETERS | -//| KDT - KD-tree | -//| R - possibly pre-allocated buffer. If X is too small | -//| to store result, it is resized. If size(X) is | -//| enough to store result, it is left unchanged. | -//| OUTPUT PARAMETERS | -//| R - filled with distances (in corresponding norm) | -//| NOTES | -//| 1. points are ordered by distance from the query point (first | -//| = closest) | -//| 2. if XY is larger than required to store result, only leading | -//| part will be overwritten; trailing part will be left | -//| unchanged. So if on input XY = [[A,B],[C,D]], and result is | -//| [1,2], then on exit we will get XY = [[1,2],[C,D]]. This is | -//| done purposely to increase performance; if you want function | -//| to resize array according to result size, use function with | -//| same name and suffix 'I'. | -//| SEE ALSO | -//| * KDTreeQueryResultsX() X-values | -//| * KDTreeQueryResultsXY() X- and Y-values | -//| * KDTreeQueryResultsTags() tag values | -//+------------------------------------------------------------------+ -static void CAlglib::KDTreeQueryResultsDistances(CKDTreeShell &kdt,double &r[]) - { -//--- function call - CNearestNeighbor::KDTreeQueryResultsDistances(kdt.GetInnerObj(),r); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| X-values from last query; 'interactive' variant for languages | -//| like Python which support constructs like "X = | -//| KDTreeQueryResultsXI(KDT)" and interactive mode of interpreter. | -//| This function allocates new array on each call, so it is | -//| significantly slower than its 'non-interactive' counterpart, but | -//| it is more convenient when you call it from command line. | -//+------------------------------------------------------------------+ -static void CAlglib::KDTreeQueryResultsXI(CKDTreeShell &kdt,CMatrixDouble &x) - { -//--- function call - CNearestNeighbor::KDTreeQueryResultsXI(kdt.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| XY-values from last query; 'interactive' variant for languages | -//| like Python which support constructs like "XY = | -//| KDTreeQueryResultsXYI(KDT)" and interactive mode of interpreter. | -//| This function allocates new array on each call, so it is | -//| significantly slower than its 'non-interactive' counterpart, but | -//| it is more convenient when you call it from command line. | -//+------------------------------------------------------------------+ -static void CAlglib::KDTreeQueryResultsXYI(CKDTreeShell &kdt,CMatrixDouble &xy) - { -//--- function call - CNearestNeighbor::KDTreeQueryResultsXYI(kdt.GetInnerObj(),xy); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Tags from last query; 'interactive' variant for languages like | -//| Python which support constructs like "Tags = | -//| KDTreeQueryResultsTagsI(KDT)" and interactive mode of | -//| interpreter. | -//| This function allocates new array on each call, so it is | -//| significantly slower than its 'non-interactive' counterpart, but | -//| it is more convenient when you call it from command line. | -//+------------------------------------------------------------------+ -static void CAlglib::KDTreeQueryResultsTagsI(CKDTreeShell &kdt,int &tags[]) - { -//--- function call - CNearestNeighbor::KDTreeQueryResultsTagsI(kdt.GetInnerObj(),tags); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Distances from last query; 'interactive' variant for languages | -//| like Python which support constructs like "R = | -//| KDTreeQueryResultsDistancesI(KDT)" and interactive mode of | -//| interpreter. | -//| This function allocates new array on each call, so it is | -//| significantly slower than its 'non-interactive' counterpart, but | -//| it is more convenient when you call it from command line. | -//+------------------------------------------------------------------+ -static void CAlglib::KDTreeQueryResultsDistancesI(CKDTreeShell &kdt,double &r[]) - { -//--- function call - CNearestNeighbor::KDTreeQueryResultsDistancesI(kdt.GetInnerObj(),r); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Optimal binary classification | -//| Algorithms finds optimal (=with minimal cross-entropy) binary | -//| partition. | -//| Internal subroutine. | -//| INPUT PARAMETERS: | -//| A - array[0..N-1], variable | -//| C - array[0..N-1], class numbers (0 or 1). | -//| N - array size | -//| OUTPUT PARAMETERS: | -//| Info - completetion code: | -//| * -3, all values of A[] are same (partition is | -//| impossible) | -//| * -2, one of C[] is incorrect (<0, >1) | -//| * -1, incorrect pararemets were passed (N<=0). | -//| * 1, OK | -//| Threshold- partiton boundary. Left part contains values | -//| which are strictly less than Threshold. Right | -//| part contains values which are greater than or | -//| equal to Threshold. | -//| PAL, PBL- probabilities P(0|v=Threshold) and | -//| P(1|v>=Threshold) | -//| CVE - cross-validation estimate of cross-entropy | -//+------------------------------------------------------------------+ -static void CAlglib::DSOptimalSplit2(double &a[],int &c[],const int n, - int &info,double &threshold, - double &pal,double &pbl,double &par, - double &pbr,double &cve) - { -//--- initialization - info=0; - threshold=0; - pal=0; - pbl=0; - par=0; - pbr=0; - cve=0; -//--- function call - CBdSS::DSOptimalSplit2(a,c,n,info,threshold,pal,pbl,par,pbr,cve); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Optimal partition, internal subroutine. Fast version. | -//| Accepts: | -//| A array[0..N-1] array of attributes array[0..N-1]| -//| C array[0..N-1] array of class labels | -//| TiesBuf array[0..N] temporaries (ties) | -//| CntBuf array[0..2*NC-1] temporaries (counts) | -//| Alpha centering factor (0<=alpha<=1, | -//| recommended value - 0.05) | -//| BufR array[0..N-1] temporaries | -//| BufI array[0..N-1] temporaries | -//| Output: | -//| Info error code (">0"=OK, "<0"=bad) | -//| RMS training set RMS error | -//| CVRMS leave-one-out RMS error | -//| Note: | -//| content of all arrays is changed by subroutine; | -//| it doesn't allocate temporaries. | -//+------------------------------------------------------------------+ -static void CAlglib::DSOptimalSplit2Fast(double &a[],int &c[],int &tiesbuf[], - int &cntbuf[],double &bufr[], - int &bufi[],const int n, - const int nc,const double alpha, - int &info,double &threshold, - double &rms,double &cvrms) - { -//--- initialization - info=0; - threshold=0; - rms=0; - cvrms=0; -//--- function call - CBdSS::DSOptimalSplit2Fast(a,c,tiesbuf,cntbuf,bufr,bufi,n,nc,alpha,info,threshold,rms,cvrms); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function serializes data structure to string. | -//| Important properties of s_out: | -//| * it contains alphanumeric characters, dots, underscores, minus | -//| signs | -//| * these symbols are grouped into words, which are separated by | -//| spaces and Windows-style (CR+LF) newlines | -//| * although serializer uses spaces and CR+LF as separators, you| -//| can replace any separator character by arbitrary combination of| -//| spaces, tabs, Windows or Unix newlines. It allows flexible | -//| reformatting of the string in case you want to include it into | -//| text or XML file. But you should not insert separators into the| -//| middle of the "words" nor you should change case of letters. | -//| * s_out can be freely moved between 32-bit and 64-bit systems, | -//| little and big endian machines, and so on. You can serialize | -//| structure on 32-bit machine and unserialize it on 64-bit one | -//| (or vice versa), or serialize it on SPARC and unserialize on | -//| x86. You can also serialize it in C# version of ALGLIB and | -//| unserialize in C++ one, and vice versa. | -//+------------------------------------------------------------------+ -static void CAlglib::DFSerialize(CDecisionForestShell &obj,string &s_out) - { -//--- create a variable - CSerializer s; -//--- serialization start - s.Alloc_Start(); -//--- function call - CDForest::DFAlloc(s,obj.GetInnerObj()); -//--- serialization - s.SStart_Str(); -//--- function call - CDForest::DFSerialize(s,obj.GetInnerObj()); -//--- stop - s.Stop(); -//--- change value - s_out=s.Get_String(); - } -//+------------------------------------------------------------------+ -//| This function unserializes data structure from string. | -//+------------------------------------------------------------------+ -static void CAlglib::DFUnserialize(const string s_in,CDecisionForestShell &obj) - { -//--- create a variable - CSerializer s; -//--- unserialization - s.UStart_Str(s_in); -//--- function call - CDForest::DFUnserialize(s,obj.GetInnerObj()); -//--- stop - s.Stop(); - } -//+------------------------------------------------------------------+ -//| This subroutine builds random decision forest. | -//| INPUT PARAMETERS: | -//| XY - training set | -//| NPoints - training set size, NPoints>=1 | -//| NVars - number of independent variables, NVars>=1 | -//| NClasses - task type: | -//| * NClasses=1 - regression task with one | -//| dependent variable | -//| * NClasses>1 - classification task with | -//| NClasses classes. | -//| NTrees - number of trees in a forest, NTrees>=1. | -//| recommended values: 50-100. | -//| R - percent of a training set used to build | -//| individual trees. 01). | -//| * 1, if task has been solved | -//| DF - model built | -//| Rep - training report, contains error on a training| -//| set and out-of-bag estimates of | -//| generalization error. | -//+------------------------------------------------------------------+ -static void CAlglib::DFBuildRandomDecisionForest(CMatrixDouble &xy,const int npoints, - const int nvars,const int nclasses, - const int ntrees,const double r, - int &info,CDecisionForestShell &df, - CDFReportShell &rep) - { -//--- initialization - info=0; -//--- function call - CDForest::DFBuildRandomDecisionForest(xy,npoints,nvars,nclasses,ntrees,r,info,df.GetInnerObj(),rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This subroutine builds random decision forest. | -//| This function gives ability to tune number of variables used when| -//| choosing best split. | -//| INPUT PARAMETERS: | -//| XY - training set | -//| NPoints - training set size, NPoints>=1 | -//| NVars - number of independent variables, NVars>=1 | -//| NClasses - task type: | -//| * NClasses=1 - regression task with one | -//| dependent variable | -//| * NClasses>1 - classification task with | -//| NClasses classes. | -//| NTrees - number of trees in a forest, NTrees>=1. | -//| recommended values: 50-100. | -//| NRndVars - number of variables used when choosing best | -//| split | -//| R - percent of a training set used to build | -//| individual trees. 01). | -//| * 1, if task has been solved | -//| DF - model built | -//| Rep - training report, contains error on a training| -//| set and out-of-bag estimates of | -//| generalization error. | -//+------------------------------------------------------------------+ -static void CAlglib::DFBuildRandomDecisionForestX1(CMatrixDouble &xy, - const int npoints, - const int nvars, - const int nclasses, - const int ntrees, - int nrndvars, - const double r, - int &info, - CDecisionForestShell &df, - CDFReportShell &rep) - { -//--- initialization - info=0; -//--- function call - CDForest::DFBuildRandomDecisionForestX1(xy,npoints,nvars,nclasses,ntrees,nrndvars,r,info,df.GetInnerObj(),rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Procesing | -//| INPUT PARAMETERS: | -//| DF - decision forest model | -//| X - input vector, array[0..NVars-1]. | -//| OUTPUT PARAMETERS: | -//| Y - result. Regression estimate when solving | -//| regression task, vector of posterior | -//| probabilities for classification task. | -//| See also DFProcessI. | -//+------------------------------------------------------------------+ -static void CAlglib::DFProcess(CDecisionForestShell &df,double &x[], - double &y[]) - { -//--- function call - CDForest::DFProcess(df.GetInnerObj(),x,y); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| 'interactive' variant of DFProcess for languages like Python | -//| which support constructs like "Y = DFProcessI(DF,X)" and | -//| interactive mode of interpreter | -//| This function allocates new array on each call, so it is | -//| significantly slower than its 'non-interactive' counterpart, but | -//| it is more convenient when you call it from command line. | -//+------------------------------------------------------------------+ -static void CAlglib::DFProcessI(CDecisionForestShell &df, - double &x[],double &y[]) - { -//--- function call - CDForest::DFProcessI(df.GetInnerObj(),x,y); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Relative classification error on the test set | -//| INPUT PARAMETERS: | -//| DF - decision forest model | -//| XY - test set | -//| NPoints - test set size | -//| RESULT: | -//| percent of incorrectly classified cases. | -//| Zero if model solves regression task. | -//+------------------------------------------------------------------+ -static double CAlglib::DFRelClsError(CDecisionForestShell &df,CMatrixDouble &xy, - const int npoints) - { -//--- return result - return(CDForest::DFRelClsError(df.GetInnerObj(),xy,npoints)); - } -//+------------------------------------------------------------------+ -//| Average cross-entropy (in bits per element) on the test set | -//| INPUT PARAMETERS: | -//| DF - decision forest model | -//| XY - test set | -//| NPoints - test set size | -//| RESULT: | -//| CrossEntropy/(NPoints*LN(2)). | -//| Zero if model solves regression task. | -//+------------------------------------------------------------------+ -static double CAlglib::DFAvgCE(CDecisionForestShell &df,CMatrixDouble &xy, - const int npoints) - { -//--- return result - return(CDForest::DFAvgCE(df.GetInnerObj(),xy,npoints)); - } -//+------------------------------------------------------------------+ -//| RMS error on the test set | -//| INPUT PARAMETERS: | -//| DF - decision forest model | -//| XY - test set | -//| NPoints - test set size | -//| RESULT: | -//| root mean square error. | -//| Its meaning for regression task is obvious. As for | -//| classification task,RMS error means error when estimating | -//| posterior probabilities. | -//+------------------------------------------------------------------+ -static double CAlglib::DFRMSError(CDecisionForestShell &df,CMatrixDouble &xy, - const int npoints) - { -//--- return result - return(CDForest::DFRMSError(df.GetInnerObj(),xy,npoints)); - } -//+------------------------------------------------------------------+ -//| Average error on the test set | -//| INPUT PARAMETERS: | -//| DF - decision forest model | -//| XY - test set | -//| NPoints - test set size | -//| RESULT: | -//| Its meaning for regression task is obvious. As for | -//| classification task, it means average error when estimating | -//| posterior probabilities. | -//+------------------------------------------------------------------+ -static double CAlglib::DFAvgError(CDecisionForestShell &df,CMatrixDouble &xy, - const int npoints) - { -//--- return result - return(CDForest::DFAvgError(df.GetInnerObj(),xy,npoints)); - } -//+------------------------------------------------------------------+ -//| Average relative error on the test set | -//| INPUT PARAMETERS: | -//| DF - decision forest model | -//| XY - test set | -//| NPoints - test set size | -//| RESULT: | -//| Its meaning for regression task is obvious. As for | -//| classification task, it means average relative error when | -//| estimating posterior probability of belonging to the correct | -//| class. | -//+------------------------------------------------------------------+ -static double CAlglib::DFAvgRelError(CDecisionForestShell &df,CMatrixDouble &xy, - const int npoints) - { -//--- return result - return(CDForest::DFAvgRelError(df.GetInnerObj(),xy,npoints)); - } -//+------------------------------------------------------------------+ -//| k-means++ clusterization | -//| INPUT PARAMETERS: | -//| XY - dataset, array [0..NPoints-1,0..NVars-1]. | -//| NPoints - dataset size, NPoints>=K | -//| NVars - number of variables, NVars>=1 | -//| K - desired number of clusters, K>=1 | -//| Restarts - number of restarts, Restarts>=1 | -//| OUTPUT PARAMETERS: | -//| Info - return code: | -//| * -3, if task is degenerate (number of | -//| distinct points is less than K) | -//| * -1, if incorrect | -//| NPoints/NFeatures/K/Restarts was passed| -//| * 1, if subroutine finished successfully | -//| C - array[0..NVars-1,0..K-1].matrix whose columns| -//| store cluster's centers | -//| XYC - array[NPoints], which contains cluster | -//| indexes | -//+------------------------------------------------------------------+ -static void CAlglib::KMeansGenerate(CMatrixDouble &xy,const int npoints, - const int nvars,const int k, - const int restarts,int &info, - CMatrixDouble &c,int &xyc[]) - { -//--- initialization - info=0; -//--- function call - CKMeans::KMeansGenerate(xy,npoints,nvars,k,restarts,info,c,xyc); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Multiclass Fisher LDA | -//| Subroutine finds coefficients of linear combination which | -//| optimally separates training set on classes. | -//| INPUT PARAMETERS: | -//| XY - training set, array[0..NPoints-1,0..NVars]. | -//| First NVars columns store values of | -//| independent variables, next column stores | -//| number of class (from 0 to NClasses-1) which | -//| dataset element belongs to. Fractional values| -//| are rounded to nearest integer. | -//| NPoints - training set size, NPoints>=0 | -//| NVars - number of independent variables, NVars>=1 | -//| NClasses - number of classes, NClasses>=2 | -//| OUTPUT PARAMETERS: | -//| Info - return code: | -//| * -4, if internal EVD subroutine hasn't | -//| converged | -//| * -2, if there is a point with class number | -//| outside of [0..NClasses-1]. | -//| * -1, if incorrect parameters was passed | -//| (NPoints<0, NVars<1, NClasses<2) | -//| * 1, if task has been solved | -//| * 2, if there was a multicollinearity in | -//| training set, but task has been solved.| -//| W - linear combination coefficients, | -//| array[0..NVars-1] | -//+------------------------------------------------------------------+ -static void CAlglib::FisherLDA(CMatrixDouble &xy,const int npoints, - const int nvars,const int nclasses, - int &info,double &w[]) - { -//--- initialization - info=0; -//--- function call - CLDA::FisherLDA(xy,npoints,nvars,nclasses,info,w); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| N-dimensional multiclass Fisher LDA | -//| Subroutine finds coefficients of linear combinations which | -//| optimally separates | -//| training set on classes. It returns N-dimensional basis whose | -//| vector are sorted | -//| by quality of training set separation (in descending order). | -//| INPUT PARAMETERS: | -//| XY - training set, array[0..NPoints-1,0..NVars]. | -//| First NVars columns store values of | -//| independent variables, next column stores | -//| number of class (from 0 to NClasses-1) which | -//| dataset element belongs to. Fractional values| -//| are rounded to nearest integer. | -//| NPoints - training set size, NPoints>=0 | -//| NVars - number of independent variables, NVars>=1 | -//| NClasses - number of classes, NClasses>=2 | -//| OUTPUT PARAMETERS: | -//| Info - return code: | -//| * -4, if internal EVD subroutine hasn't | -//| converged | -//| * -2, if there is a point with class number | -//| outside of [0..NClasses-1]. | -//| * -1, if incorrect parameters was passed | -//| (NPoints<0, NVars<1, NClasses<2) | -//| * 1, if task has been solved | -//| * 2, if there was a multicollinearity in | -//| training set, but task has been solved.| -//| W - basis, array[0..NVars-1,0..NVars-1] | -//| columns of matrix stores basis vectors, | -//| sorted by quality of training set separation | -//| (in descending order) | -//+------------------------------------------------------------------+ -static void CAlglib::FisherLDAN(CMatrixDouble &xy,const int npoints, - const int nvars,const int nclasses, - int &info,CMatrixDouble &w) - { -//--- initialization - info=0; -//--- function call - CLDA::FisherLDAN(xy,npoints,nvars,nclasses,info,w); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Linear regression | -//| Subroutine builds model: | -//| Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + A(N) | -//| and model found in ALGLIB format, covariation matrix, training | -//| set errors (rms, average, average relative) and leave-one-out | -//| cross-validation estimate of the generalization error. CV | -//| estimate calculated using fast algorithm with O(NPoints*NVars) | -//| complexity. | -//| When covariation matrix is calculated standard deviations of| -//| function values are assumed to be equal to RMS error on the | -//| training set. | -//| INPUT PARAMETERS: | -//| XY - training set, array [0..NPoints-1,0..NVars]: | -//| * NVars columns - independent variables | -//| * last column - dependent variable | -//| NPoints - training set size, NPoints>NVars+1 | -//| NVars - number of independent variables | -//| OUTPUT PARAMETERS: | -//| Info - return code: | -//| * -255, in case of unknown internal error | -//| * -4, if internal SVD subroutine haven't | -//| converged | -//| * -1, if incorrect parameters was passed | -//| (NPoints0. | -//| NPoints - training set size, NPoints>NVars+1 | -//| NVars - number of independent variables | -//| OUTPUT PARAMETERS: | -//| Info - return code: | -//| * -255, in case of unknown internal error | -//| * -4, if internal SVD subroutine haven't | -//| converged | -//| * -1, if incorrect parameters was passed | -//| (NPointsA will result in positive length returned | -//| * B=2, N>=2 | -//| Output parameters: | -//| C - spline interpolant | -//+------------------------------------------------------------------+ -static void CAlglib::Spline2DBuildBilinear(double &x[],double &y[], - CMatrixDouble &f,const int m, - const int n,CSpline2DInterpolantShell &c) - { -//--- function call - CSpline2D::Spline2DBuildBilinear(x,y,f,m,n,c.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This subroutine builds bicubic spline coefficients table. | -//| Input parameters: | -//| X - spline abscissas, array[0..N-1] | -//| Y - spline ordinates, array[0..M-1] | -//| F - function values, array[0..M-1,0..N-1] | -//| M,N - grid size, M>=2, N>=2 | -//| Output parameters: | -//| C - spline interpolant | -//+------------------------------------------------------------------+ -static void CAlglib::Spline2DBuildBicubic(double &x[],double &y[],CMatrixDouble &f, - const int m,const int n, - CSpline2DInterpolantShell &c) - { -//--- function call - CSpline2D::Spline2DBuildBicubic(x,y,f,m,n,c.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This subroutine calculates the value of the bilinear or bicubic | -//| spline at the given point X. | -//| Input parameters: | -//| C - coefficients table. | -//| Built by BuildBilinearSpline or BuildBicubicSpline. | -//| X, Y- point | -//| Result: | -//| S(x,y) | -//+------------------------------------------------------------------+ -static double CAlglib::Spline2DCalc(CSpline2DInterpolantShell &c, - const double x,const double y) - { -//--- return result - return(CSpline2D::Spline2DCalc(c.GetInnerObj(),x,y)); - } -//+------------------------------------------------------------------+ -//| This subroutine calculates the value of the bilinear or bicubic | -//| spline at the given point X and its derivatives. | -//| Input parameters: | -//| C - spline interpolant. | -//| X, Y- point | -//| Output parameters: | -//| F - S(x,y) | -//| FX - dS(x,y)/dX | -//| FY - dS(x,y)/dY | -//| FXY - d2S(x,y)/dXdY | -//+------------------------------------------------------------------+ -static void CAlglib::Spline2DDiff(CSpline2DInterpolantShell &c,const double x, - const double y,double &f,double &fx, - double &fy,double &fxy) - { -//--- initialization - f=0; - fx=0; - fy=0; - fxy=0; -//--- function call - CSpline2D::Spline2DDiff(c.GetInnerObj(),x,y,f,fx,fy,fxy); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This subroutine unpacks two-dimensional spline into the | -//| coefficients table | -//| Input parameters: | -//| C - spline interpolant. | -//| Result: | -//| M, N- grid size (x-axis and y-axis) | -//| Tbl - coefficients table, unpacked format, | -//| [0..(N-1)*(M-1)-1, 0..19]. | -//| For I = 0...M-2, J=0..N-2: | -//| K = I*(N-1)+J | -//| Tbl[K,0] = X[j] | -//| Tbl[K,1] = X[j+1] | -//| Tbl[K,2] = Y[i] | -//| Tbl[K,3] = Y[i+1] | -//| Tbl[K,4] = C00 | -//| Tbl[K,5] = C01 | -//| Tbl[K,6] = C02 | -//| Tbl[K,7] = C03 | -//| Tbl[K,8] = C10 | -//| Tbl[K,9] = C11 | -//| ... | -//| Tbl[K,19] = C33 | -//| On each grid square spline is equals to: | -//| S(x) = SUM(c[i,j]*(x^i)*(y^j), i=0..3, j=0..3) | -//| t = x-x[j] | -//| u = y-y[i] | -//+------------------------------------------------------------------+ -static void CAlglib::Spline2DUnpack(CSpline2DInterpolantShell &c,int &m, - int &n,CMatrixDouble &tbl) - { -//--- initialization - m=0; - n=0; -//--- function call - CSpline2D::Spline2DUnpack(c.GetInnerObj(),m,n,tbl); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This subroutine performs linear transformation of the spline | -//| argument. | -//| Input parameters: | -//| C - spline interpolant | -//| AX, BX - transformation coefficients: x = A*t + B | -//| AY, BY - transformation coefficients: y = A*u + B | -//| Result: | -//| C - transformed spline | -//+------------------------------------------------------------------+ -static void CAlglib::Spline2DLinTransXY(CSpline2DInterpolantShell &c, - const double ax,const double bx, - const double ay,const double by) - { -//--- function call - CSpline2D::Spline2DLinTransXY(c.GetInnerObj(),ax,bx,ay,by); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This subroutine performs linear transformation of the spline. | -//| Input parameters: | -//| C - spline interpolant. | -//| A, B- transformation coefficients: S2(x,y) = A*S(x,y) + B | -//| Output parameters: | -//| C - transformed spline | -//+------------------------------------------------------------------+ -static void CAlglib::Spline2DLinTransF(CSpline2DInterpolantShell &c, - const double a,const double b) - { -//--- function call - CSpline2D::Spline2DLinTransF(c.GetInnerObj(),a,b); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Bicubic spline resampling | -//| Input parameters: | -//| A - function values at the old grid, | -//| array[0..OldHeight-1, 0..OldWidth-1] | -//| OldHeight - old grid height, OldHeight>1 | -//| OldWidth - old grid width, OldWidth>1 | -//| NewHeight - new grid height, NewHeight>1 | -//| NewWidth - new grid width, NewWidth>1 | -//| Output parameters: | -//| B - function values at the new grid, | -//| array[0..NewHeight-1, 0..NewWidth-1] | -//+------------------------------------------------------------------+ -static void CAlglib::Spline2DResampleBicubic(CMatrixDouble &a,const int oldheight, - const int oldwidth,CMatrixDouble &b, - const int newheight,const int newwidth) - { -//--- function call - CSpline2D::Spline2DResampleBicubic(a,oldheight,oldwidth,b,newheight,newwidth); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Bilinear spline resampling | -//| Input parameters: | -//| A - function values at the old grid, | -//| array[0..OldHeight-1, 0..OldWidth-1] | -//| OldHeight - old grid height, OldHeight>1 | -//| OldWidth - old grid width, OldWidth>1 | -//| NewHeight - new grid height, NewHeight>1 | -//| NewWidth - new grid width, NewWidth>1 | -//| Output parameters: | -//| B - function values at the new grid, | -//| array[0..NewHeight-1, 0..NewWidth-1] | -//+------------------------------------------------------------------+ -static void CAlglib::Spline2DResampleBilinear(CMatrixDouble &a,const int oldheight, - const int oldwidth,CMatrixDouble &b, - const int newheight,const int newwidth) - { -//--- function call - CSpline2D::Spline2DResampleBilinear(a,oldheight,oldwidth,b,newheight,newwidth); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Cache-oblivous complex "copy-and-transpose" | -//| Input parameters: | -//| M - number of rows | -//| N - number of columns | -//| A - source matrix, MxN submatrix is copied and transposed| -//| IA - submatrix offset (row index) | -//| JA - submatrix offset (column index) | -//| A - destination matrix | -//| IB - submatrix offset (row index) | -//| JB - submatrix offset (column index) | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixTranspose(const int m,const int n,CMatrixComplex &a, - const int ia,const int ja,CMatrixComplex &b, - const int ib,const int jb) - { -//--- function call - CAblas::CMatrixTranspose(m,n,a,ia,ja,b,ib,jb); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Cache-oblivous real "copy-and-transpose" | -//| Input parameters: | -//| M - number of rows | -//| N - number of columns | -//| A - source matrix, MxN submatrix is copied and transposed| -//| IA - submatrix offset (row index) | -//| JA - submatrix offset (column index) | -//| A - destination matrix | -//| IB - submatrix offset (row index) | -//| JB - submatrix offset (column index) | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixTranspose(const int m,const int n,CMatrixDouble &a, - const int ia,const int ja,CMatrixDouble &b, - const int ib,const int jb) - { -//--- function call - CAblas::RMatrixTranspose(m,n,a,ia,ja,b,ib,jb); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Copy | -//| Input parameters: | -//| M - number of rows | -//| N - number of columns | -//| A - source matrix, MxN submatrix is copied and transposed| -//| IA - submatrix offset (row index) | -//| JA - submatrix offset (column index) | -//| B - destination matrix | -//| IB - submatrix offset (row index) | -//| JB - submatrix offset (column index) | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixCopy(const int m,const int n,CMatrixComplex &a, - const int ia,const int ja,CMatrixComplex &b, - const int ib,const int jb) - { -//--- function call - CAblas::CMatrixCopy(m,n,a,ia,ja,b,ib,jb); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Copy | -//| Input parameters: | -//| M - number of rows | -//| N - number of columns | -//| A - source matrix, MxN submatrix is copied and transposed| -//| IA - submatrix offset (row index) | -//| JA - submatrix offset (column index) | -//| B - destination matrix | -//| IB - submatrix offset (row index) | -//| JB - submatrix offset (column index) | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixCopy(const int m,const int n,CMatrixDouble &a, - const int ia,const int ja,CMatrixDouble &b, - const int ib,const int jb) - { -//--- function call - CAblas::RMatrixCopy(m,n,a,ia,ja,b,ib,jb); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Rank-1 correction: A := A + u*v' | -//| INPUT PARAMETERS: | -//| M - number of rows | -//| N - number of columns | -//| A - target matrix, MxN submatrix is updated | -//| IA - submatrix offset (row index) | -//| JA - submatrix offset (column index) | -//| U - vector #1 | -//| IU - subvector offset | -//| V - vector #2 | -//| IV - subvector offset | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixRank1(const int m,const int n,CMatrixComplex &a, - const int ia,const int ja,al_complex &u[], - const int iu,al_complex &v[],const int iv) - { -//--- function call - CAblas::CMatrixRank1(m,n,a,ia,ja,u,iu,v,iv); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Rank-1 correction: A := A + u*v' | -//| INPUT PARAMETERS: | -//| M - number of rows | -//| N - number of columns | -//| A - target matrix, MxN submatrix is updated | -//| IA - submatrix offset (row index) | -//| JA - submatrix offset (column index) | -//| U - vector #1 | -//| IU - subvector offset | -//| V - vector #2 | -//| IV - subvector offset | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixRank1(const int m,const int n,CMatrixDouble &a, - const int ia,const int ja,double &u[], - const int iu,double &v[],const int iv) - { -//--- function call - CAblas::RMatrixRank1(m,n,a,ia,ja,u,iu,v,iv); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Matrix-vector product: y := op(A)*x | -//| INPUT PARAMETERS: | -//| M - number of rows of op(A) | -//| M>=0 | -//| N - number of columns of op(A) | -//| N>=0 | -//| A - target matrix | -//| IA - submatrix offset (row index) | -//| JA - submatrix offset (column index) | -//| OpA - operation type: | -//| * OpA=0 => op(A) = A | -//| * OpA=1 => op(A) = A^T | -//| * OpA=2 => op(A) = A^H | -//| X - input vector | -//| IX - subvector offset | -//| IY - subvector offset | -//| OUTPUT PARAMETERS: | -//| Y - vector which stores result | -//| if M=0, then subroutine does nothing. | -//| if N=0, Y is filled by zeros. | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixMVect(const int m,const int n,CMatrixComplex &a, - const int ia,const int ja,const int opa, - al_complex &x[],const int ix,al_complex &y[], - const int iy) - { -//--- function call - CAblas::CMatrixMVect(m,n,a,ia,ja,opa,x,ix,y,iy); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Matrix-vector product: y := op(A)*x | -//| INPUT PARAMETERS: | -//| M - number of rows of op(A) | -//| N - number of columns of op(A) | -//| A - target matrix | -//| IA - submatrix offset (row index) | -//| JA - submatrix offset (column index) | -//| OpA - operation type: | -//| * OpA=0 => op(A) = A | -//| * OpA=1 => op(A) = A^T | -//| X - input vector | -//| IX - subvector offset | -//| IY - subvector offset | -//| OUTPUT PARAMETERS: | -//| Y - vector which stores result | -//| if M=0, then subroutine does nothing. | -//| if N=0, Y is filled by zeros. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixMVect(const int m,const int n,CMatrixDouble &a, - const int ia,const int ja,const int opa, - double &x[],const int ix,double &y[], - const int iy) - { -//--- function call - CAblas::RMatrixMVect(m,n,a,ia,ja,opa,x,ix,y,iy); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This subroutine calculates X*op(A^-1) where: | -//| * X is MxN general matrix | -//| * A is NxN upper/lower triangular/unitriangular matrix | -//| * "op" may be identity transformation, transposition, conjugate | -//| transposition | -//| Multiplication result replaces X. | -//| Cache-oblivious algorithm is used. | -//| INPUT PARAMETERS | -//| N - matrix size, N>=0 | -//| M - matrix size, N>=0 | -//| A - matrix, actial matrix is stored in | -//| A[I1:I1+N-1,J1:J1+N-1] | -//| I1 - submatrix offset | -//| J1 - submatrix offset | -//| IsUpper - whether matrix is upper triangular | -//| IsUnit - whether matrix is unitriangular | -//| OpType - transformation type: | -//| * 0 - no transformation | -//| * 1 - transposition | -//| * 2 - conjugate transposition | -//| C - matrix, actial matrix is stored in | -//| C[I2:I2+M-1,J2:J2+N-1] | -//| I2 - submatrix offset | -//| J2 - submatrix offset | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixRightTrsM(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) - { -//--- function call - CAblas::CMatrixRightTrsM(m,n,a,i1,j1,isupper,isunit,optype,x,i2,j2); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This subroutine calculates op(A^-1)*X where: | -//| * X is MxN general matrix | -//| * A is MxM upper/lower triangular/unitriangular matrix | -//| * "op" may be identity transformation, transposition, conjugate | -//| transposition | -//| Multiplication result replaces X. | -//| Cache-oblivious algorithm is used. | -//| INPUT PARAMETERS | -//| N - matrix size, N>=0 | -//| M - matrix size, N>=0 | -//| A - matrix, actial matrix is stored in | -//| A[I1:I1+M-1,J1:J1+M-1] | -//| I1 - submatrix offset | -//| J1 - submatrix offset | -//| IsUpper - whether matrix is upper triangular | -//| IsUnit - whether matrix is unitriangular | -//| OpType - transformation type: | -//| * 0 - no transformation | -//| * 1 - transposition | -//| * 2 - conjugate transposition | -//| C - matrix, actial matrix is stored in | -//| C[I2:I2+M-1,J2:J2+N-1] | -//| I2 - submatrix offset | -//| J2 - submatrix offset | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixLeftTrsM(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) - { -//--- function call - CAblas::CMatrixLeftTrsM(m,n,a,i1,j1,isupper,isunit,optype,x,i2,j2); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Same as CMatrixRightTRSM, but for real matrices | -//| OpType may be only 0 or 1. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixRightTrsM(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) - { -//--- function call - CAblas::RMatrixRightTrsM(m,n,a,i1,j1,isupper,isunit,optype,x,i2,j2); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Same as CMatrixLeftTRSM, but for real matrices | -//| OpType may be only 0 or 1. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixLeftTrsM(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) - { -//--- function call - CAblas::RMatrixLeftTrsM(m,n,a,i1,j1,isupper,isunit,optype,x,i2,j2); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This subroutine calculates C=alpha*A*A^H+beta*C or | -//| C=alpha*A^H*A+beta*C where: | -//| * C is NxN Hermitian matrix given by its upper/lower triangle | -//| * A is NxK matrix when A*A^H is calculated, KxN matrix otherwise | -//| Additional info: | -//| * cache-oblivious algorithm is used. | -//| * multiplication result replaces C. If Beta=0, C elements are not| -//| used in calculations (not multiplied by zero - just not | -//| referenced) | -//| * if Alpha=0, A is not used (not multiplied by zero - just not | -//| referenced) | -//| * if both Beta and Alpha are zero, C is filled by zeros. | -//| INPUT PARAMETERS | -//| N - matrix size, N>=0 | -//| K - matrix size, K>=0 | -//| Alpha - coefficient | -//| A - matrix | -//| IA - submatrix offset | -//| JA - submatrix offset | -//| OpTypeA - multiplication type: | -//| * 0 - A*A^H is calculated | -//| * 2 - A^H*A is calculated | -//| Beta - coefficient | -//| C - matrix | -//| IC - submatrix offset | -//| JC - submatrix offset | -//| IsUpper - whether C is upper triangular or lower triangular| -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixSyrk(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) - { -//--- function call - CAblas::CMatrixSyrk(n,k,alpha,a,ia,ja,optypea,beta,c,ic,jc,isupper); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Same as CMatrixSYRK, but for real matrices | -//| OpType may be only 0 or 1. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixSyrk(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) - { -//--- function call - CAblas::RMatrixSyrk(n,k,alpha,a,ia,ja,optypea,beta,c,ic,jc,isupper); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where:| -//| * C is MxN general matrix | -//| * op1(A) is MxK matrix | -//| * op2(B) is KxN matrix | -//| * "op" may be identity transformation, transposition, conjugate | -//| transposition | -//| Additional info: | -//| * cache-oblivious algorithm is used. | -//| * multiplication result replaces C. If Beta=0, C elements are not| -//| used in calculations (not multiplied by zero - just not | -//| referenced) | -//| * if Alpha=0, A is not used (not multiplied by zero - just not | -//| referenced) | -//| * if both Beta and Alpha are zero, C is filled by zeros. | -//| INPUT PARAMETERS | -//| N - matrix size, N>0 | -//| M - matrix size, N>0 | -//| K - matrix size, K>0 | -//| Alpha - coefficient | -//| A - matrix | -//| IA - submatrix offset | -//| JA - submatrix offset | -//| OpTypeA - transformation type: | -//| * 0 - no transformation | -//| * 1 - transposition | -//| * 2 - conjugate transposition | -//| B - matrix | -//| IB - submatrix offset | -//| JB - submatrix offset | -//| OpTypeB - transformation type: | -//| * 0 - no transformation | -//| * 1 - transposition | -//| * 2 - conjugate transposition | -//| Beta - coefficient | -//| C - matrix | -//| IC - submatrix offset | -//| JC - submatrix offset | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixGemm(const int m,const int n,const int k, - al_complex &alpha,CMatrixComplex &a, - const int ia,const int ja,const int optypea, - CMatrixComplex &b,const int ib,const int jb, - const int optypeb,al_complex &beta,CMatrixComplex &c, - const int ic,const int jc) - { -//--- function call - CAblas::CMatrixGemm(m,n,k,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Same as CMatrixGEMM, but for real numbers. | -//| OpType may be only 0 or 1. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixGemm(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) - { -//--- function call - CAblas::RMatrixGemm(m,n,k,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| QR decomposition of a rectangular matrix of size MxN | -//| Input parameters: | -//| A - matrix A whose indexes range within [0..M-1, 0..N-1].| -//| M - number of rows in matrix A. | -//| N - number of columns in matrix A. | -//| Output parameters: | -//| A - matrices Q and R in compact form (see below). | -//| Tau - array of scalar factors which are used to form | -//| matrix Q. Array whose index ranges within | -//| [0.. Min(M-1,N-1)]. | -//| Matrix A is represented as A = QR, where Q is an orthogonal | -//| matrix of size MxM, R - upper triangular (or upper trapezoid) | -//| matrix of size M x N. | -//| The elements of matrix R are located on and above the main | -//| diagonal of matrix A. The elements which are located in Tau | -//| array and below the main diagonal of matrix A are used to form | -//| matrix Q as follows: | -//| Matrix Q is represented as a product of elementary reflections | -//| Q = H(0)*H(2)*...*H(k-1), | -//| where k = min(m,n), and each H(i) is in the form | -//| H(i) = 1 - tau * v * (v^T) | -//| where tau is a scalar stored in Tau[I]; v - real vector, | -//| so that v(0:i-1) = 0, v(i) = 1, v(i+1:m-1) stored in | -//| A(i+1:m-1,i). | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixQR(CMatrixDouble &a,const int m,const int n, - double &tau[]) - { -//--- function call - COrtFac::RMatrixQR(a,m,n,tau); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| LQ decomposition of a rectangular matrix of size MxN | -//| Input parameters: | -//| A - matrix A whose indexes range within [0..M-1, 0..N-1].| -//| M - number of rows in matrix A. | -//| N - number of columns in matrix A. | -//| Output parameters: | -//| A - matrices L and Q in compact form (see below) | -//| Tau - array of scalar factors which are used to form | -//| matrix Q. Array whose index ranges within | -//| [0..Min(M,N)-1]. | -//| Matrix A is represented as A = LQ, where Q is an orthogonal | -//| matrix of size MxM, L - lower triangular (or lower trapezoid) | -//| matrix of size M x N. | -//| The elements of matrix L are located on and below the main | -//| diagonal of matrix A. The elements which are located in Tau | -//| array and above the main diagonal of matrix A are used to form | -//| matrix Q as follows: | -//| Matrix Q is represented as a product of elementary reflections | -//| Q = H(k-1)*H(k-2)*...*H(1)*H(0), | -//| where k = min(m,n), and each H(i) is of the form | -//| H(i) = 1 - tau * v * (v^T) | -//| where tau is a scalar stored in Tau[I]; v - real vector, so that | -//| v(0:i-1)=0, v(i) = 1, v(i+1:n-1) stored in A(i,i+1:n-1). | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixLQ(CMatrixDouble &a,const int m,const int n, - double &tau[]) - { -//--- function call - COrtFac::RMatrixLQ(a,m,n,tau); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| QR decomposition of a rectangular complex matrix of size MxN | -//| Input parameters: | -//| A - matrix A whose indexes range within [0..M-1, 0..N-1] | -//| M - number of rows in matrix A. | -//| N - number of columns in matrix A. | -//| Output parameters: | -//| A - matrices Q and R in compact form | -//| Tau - array of scalar factors which are used to form | -//| matrix Q. Array whose indexes range within | -//| [0.. Min(M,N)-1] | -//| Matrix A is represented as A = QR, where Q is an orthogonal | -//| matrix of size MxM, R - upper triangular (or upper trapezoid) | -//| matrix of size MxN. | -//| -- LAPACK routine (version 3.0) -- | -//| Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., | -//| Courant Institute, Argonne National Lab, and Rice University| -//| September 30, 1994 | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixQR(CMatrixComplex &a,const int m,const int n, - al_complex &tau[]) - { -//--- function call - COrtFac::CMatrixQR(a,m,n,tau); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| LQ decomposition of a rectangular complex matrix of size MxN | -//| Input parameters: | -//| A - matrix A whose indexes range within [0..M-1, 0..N-1] | -//| M - number of rows in matrix A. | -//| N - number of columns in matrix A. | -//| Output parameters: | -//| A - matrices Q and L in compact form | -//| Tau - array of scalar factors which are used to form | -//| matrix Q. Array whose indexes range within | -//| [0.. Min(M,N)-1] | -//| Matrix A is represented as A = LQ, where Q is an orthogonal | -//| matrix of size MxM, L - lower triangular (or lower trapezoid) | -//| matrix of size MxN. | -//| -- LAPACK routine (version 3.0) -- | -//| Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., | -//| Courant Institute, Argonne National Lab, and Rice University| -//| September 30, 1994 | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixLQ(CMatrixComplex &a,const int m,const int n, - al_complex &tau[]) - { -//--- function call - COrtFac::CMatrixLQ(a,m,n,tau); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Partial unpacking of matrix Q from the QR decomposition of a | -//| matrix A | -//| Input parameters: | -//| A - matrices Q and R in compact form. | -//| Output of RMatrixQR subroutine. | -//| M - number of rows in given matrix A. M>=0. | -//| N - number of columns in given matrix A. N>=0. | -//| Tau - scalar factors which are used to form Q. | -//| Output of the RMatrixQR subroutine. | -//| QColumns - required number of columns of matrix Q. | -//| M>=QColumns>=0. | -//| Output parameters: | -//| Q - first QColumns columns of matrix Q. | -//| Array whose indexes range within | -//| [0..M-1, 0..QColumns-1]. | -//| If QColumns=0, the array remains unchanged. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixQRUnpackQ(CMatrixDouble &a,const int m,const int n, - double &tau[],const int qcolumns, - CMatrixDouble &q) - { -//--- function call - COrtFac::RMatrixQRUnpackQ(a,m,n,tau,qcolumns,q); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Unpacking of matrix R from the QR decomposition of a matrix A | -//| Input parameters: | -//| A - matrices Q and R in compact form. | -//| Output of RMatrixQR subroutine. | -//| M - number of rows in given matrix A. M>=0. | -//| N - number of columns in given matrix A. N>=0. | -//| Output parameters: | -//| R - matrix R, array[0..M-1, 0..N-1]. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixQRUnpackR(CMatrixDouble &a,const int m, - const int n,CMatrixDouble &r) - { -//--- function call - COrtFac::RMatrixQRUnpackR(a,m,n,r); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Partial unpacking of matrix Q from LQ decomposition of a complex | -//| matrix A. | -//| Input parameters: | -//| A - matrices Q and R in compact form. | -//| Output of CMatrixLQ subroutine. | -//| M - number of rows in matrix A. M>=0. | -//| N - number of columns in matrix A. N>=0. | -//| Tau - scalar factors which are used to form Q. | -//| Output of CMatrixLQ subroutine . | -//| QRows - required number of rows in matrix Q. | -//| N>=QColumns>=0. | -//| Output parameters: | -//| Q - first QRows rows of matrix Q. | -//| Array whose index ranges within [0..QRows-1, | -//| 0..N-1]. | -//| If QRows=0, array isn't changed. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixLQUnpackQ(CMatrixDouble &a,const int m,const int n, - double &tau[],const int qrows, - CMatrixDouble &q) - { -//--- function call - COrtFac::RMatrixLQUnpackQ(a,m,n,tau,qrows,q); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Unpacking of matrix L from the LQ decomposition of a matrix A | -//| Input parameters: | -//| A -matrices Q and L in compact form. | -//| Output of RMatrixLQ subroutine. | -//| M -number of rows in given matrix A. M>=0. | -//| N -number of columns in given matrix A. N>=0. | -//| Output parameters: | -//| L -matrix L, array[0..M-1,0..N-1]. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixLQUnpackL(CMatrixDouble &a,const int m, - const int n,CMatrixDouble &l) - { -//--- function call - COrtFac::RMatrixLQUnpackL(a,m,n,l); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Partial unpacking of matrix Q from QR decomposition of a complex | -//| matrix A. | -//| Input parameters: | -//| A - matrices Q and R in compact form. | -//| Output of CMatrixQR subroutine . | -//| M - number of rows in matrix A. M>=0. | -//| N - number of columns in matrix A. N>=0. | -//| Tau - scalar factors which are used to form Q. | -//| Output of CMatrixQR subroutine . | -//| QColumns - required number of columns in matrix Q. | -//| M>=QColumns>=0. | -//| Output parameters: | -//| Q - first QColumns columns of matrix Q. | -//| Array whose index ranges within [0..M-1, | -//| 0..QColumns-1]. | -//| If QColumns=0, array isn't changed. | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixQRUnpackQ(CMatrixComplex &a,const int m, - const int n,al_complex &tau[], - const int qcolumns,CMatrixComplex &q) - { -//--- function call - COrtFac::CMatrixQRUnpackQ(a,m,n,tau,qcolumns,q); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Unpacking of matrix R from the QR decomposition of a matrix A | -//| Input parameters: | -//| A - matrices Q and R in compact form. | -//| Output of CMatrixQR subroutine. | -//| M - number of rows in given matrix A. M>=0. | -//| N - number of columns in given matrix A. N>=0. | -//| Output parameters: | -//| R - matrix R, array[0..M-1, 0..N-1]. | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixQRUnpackR(CMatrixComplex &a,const int m, - const int n,CMatrixComplex &r) - { -//--- function call - COrtFac::CMatrixQRUnpackR(a,m,n,r); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Partial unpacking of matrix Q from LQ decomposition of a complex | -//| matrix A. | -//| Input parameters: | -//| A - matrices Q and R in compact form. | -//| Output of CMatrixLQ subroutine. | -//| M - number of rows in matrix A. M>=0. | -//| N - number of columns in matrix A. N>=0. | -//| Tau - scalar factors which are used to form Q. | -//| Output of CMatrixLQ subroutine . | -//| QRows - required number of rows in matrix Q. | -//| N>=QColumns>=0. | -//| Output parameters: | -//| Q - first QRows rows of matrix Q. | -//| Array whose index ranges within [0..QRows-1, | -//| 0..N-1]. | -//| If QRows=0, array isn't changed. | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixLQUnpackQ(CMatrixComplex &a,const int m, - const int n,al_complex &tau[], - const int qrows,CMatrixComplex &q) - { -//--- function call - COrtFac::CMatrixLQUnpackQ(a,m,n,tau,qrows,q); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Unpacking of matrix L from the LQ decomposition of a matrix A | -//| Input parameters: | -//| A - matrices Q and L in compact form. | -//| Output of CMatrixLQ subroutine. | -//| M - number of rows in given matrix A. M>=0. | -//| N - number of columns in given matrix A. N>=0. | -//| Output parameters: | -//| L - matrix L, array[0..M-1, 0..N-1]. | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixLQUnpackL(CMatrixComplex &a,const int m, - const int n,CMatrixComplex &l) - { -//--- function call - COrtFac::CMatrixLQUnpackL(a,m,n,l); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Reduction of a rectangular matrix to bidiagonal form | -//| The algorithm reduces the rectangular matrix A to bidiagonal | -//| form by orthogonal transformations P and Q: A = Q*B*P. | -//| Input parameters: | -//| A - source matrix. array[0..M-1, 0..N-1] | -//| M - number of rows in matrix A. | -//| N - number of columns in matrix A. | -//| Output parameters: | -//| A - matrices Q, B, P in compact form (see below). | -//| TauQ - scalar factors which are used to form matrix Q. | -//| TauP - scalar factors which are used to form matrix P. | -//| The main diagonal and one of the secondary diagonals of matrix A | -//| are replaced with bidiagonal matrix B. Other elements contain | -//| elementary reflections which form MxM matrix Q and NxN matrix P, | -//| respectively. | -//| If M>=N, B is the upper bidiagonal MxN matrix and is stored in | -//| the corresponding elements of matrix A. Matrix Q is represented | -//| as a product of elementary reflections Q = H(0)*H(1)*...*H(n-1), | -//| where H(i) = 1-tau*v*v'. Here tau is a scalar which is stored in | -//| TauQ[i], and vector v has the following structure: v(0:i-1)=0, | -//| v(i)=1, v(i+1:m-1) is stored in elements A(i+1:m-1,i).Matrix P is| -//| as follows: P = G(0)*G(1)*...*G(n-2), where G(i) = 1 - tau*u*u'. | -//| Tau is stored in TauP[i], u(0:i)=0, u(i+1)=1, u(i+2:n-1) is | -//| stored in elements A(i,i+2:n-1). | -//| If M n): m=5, n=6 (m < n): | -//| ( d e u1 u1 u1 ) ( d u1 u1 u1 u1 u1 ) | -//| ( v1 d e u2 u2 ) ( e d u2 u2 u2 u2 ) | -//| ( v1 v2 d e u3 ) ( v1 e d u3 u3 u3 ) | -//| ( v1 v2 v3 d e ) ( v1 v2 e d u4 u4 ) | -//| ( v1 v2 v3 v4 d ) ( v1 v2 v3 e d u5 ) | -//| ( v1 v2 v3 v4 v5 ) | -//| Here vi and ui are vectors which form H(i) and G(i), and d and | -//| e - are the diagonal and off-diagonal elements of matrix B. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixBD(CMatrixDouble &a,const int m,const int n, - double &tauq[],double &taup[]) - { -//--- function call - COrtFac::RMatrixBD(a,m,n,tauq,taup); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Unpacking matrix Q which reduces a matrix to bidiagonal form. | -//| Input parameters: | -//| QP - matrices Q and P in compact form. | -//| Output of ToBidiagonal subroutine. | -//| M - number of rows in matrix A. | -//| N - number of columns in matrix A. | -//| TAUQ - scalar factors which are used to form Q. | -//| Output of ToBidiagonal subroutine. | -//| QColumns - required number of columns in matrix Q. | -//| M>=QColumns>=0. | -//| Output parameters: | -//| Q - first QColumns columns of matrix Q. | -//| Array[0..M-1, 0..QColumns-1] | -//| If QColumns=0, the array is not modified. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixBDUnpackQ(CMatrixDouble &qp,const int m, - const int n,double &tauq[], - const int qcolumns,CMatrixDouble &q) - { -//--- function call - COrtFac::RMatrixBDUnpackQ(qp,m,n,tauq,qcolumns,q); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Multiplication by matrix Q which reduces matrix A to bidiagonal | -//| form. | -//| The algorithm allows pre- or post-multiply by Q or Q'. | -//| Input parameters: | -//| QP - matrices Q and P in compact form. | -//| Output of ToBidiagonal subroutine. | -//| M - number of rows in matrix A. | -//| N - number of columns in matrix A. | -//| TAUQ - scalar factors which are used to form Q. | -//| Output of ToBidiagonal subroutine. | -//| Z - multiplied matrix. | -//| array[0..ZRows-1,0..ZColumns-1] | -//| ZRows - number of rows in matrix Z. If FromTheRight= | -//| =False, ZRows=M, otherwise ZRows can be | -//| arbitrary. | -//| ZColumns - number of columns in matrix Z. If | -//| FromTheRight=True, ZColumns=M, otherwise | -//| ZColumns can be arbitrary. | -//| FromTheRight - pre- or post-multiply. | -//| DoTranspose - multiply by Q or Q'. | -//| Output parameters: | -//| Z - product of Z and Q. | -//| Array[0..ZRows-1,0..ZColumns-1] | -//| If ZRows=0 or ZColumns=0, the array is not | -//| modified. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixBDMultiplyByQ(CMatrixDouble &qp,const int m, - const int n,double &tauq[], - CMatrixDouble &z,const int zrows, - const int zcolumns,const bool fromtheright, - const bool dotranspose) - { -//--- function call - COrtFac::RMatrixBDMultiplyByQ(qp,m,n,tauq,z,zrows,zcolumns,fromtheright,dotranspose); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Unpacking matrix P which reduces matrix A to bidiagonal form. | -//| The subroutine returns transposed matrix P. | -//| Input parameters: | -//| QP - matrices Q and P in compact form. | -//| Output of ToBidiagonal subroutine. | -//| M - number of rows in matrix A. | -//| N - number of columns in matrix A. | -//| TAUP - scalar factors which are used to form P. | -//| Output of ToBidiagonal subroutine. | -//| PTRows - required number of rows of matrix P^T. | -//| N >= PTRows >= 0. | -//| Output parameters: | -//| PT - first PTRows columns of matrix P^T | -//| Array[0..PTRows-1, 0..N-1] | -//| If PTRows=0, the array is not modified. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixBDUnpackPT(CMatrixDouble &qp,const int m, - const int n,double &taup[], - const int ptrows,CMatrixDouble &pt) - { -//--- function call - COrtFac::RMatrixBDUnpackPT(qp,m,n,taup,ptrows,pt); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Multiplication by matrix P which reduces matrix A to bidiagonal | -//| form. | -//| The algorithm allows pre- or post-multiply by P or P'. | -//| Input parameters: | -//| QP - matrices Q and P in compact form. | -//| Output of RMatrixBD subroutine. | -//| M - number of rows in matrix A. | -//| N - number of columns in matrix A. | -//| TAUP - scalar factors which are used to form P. | -//| Output of RMatrixBD subroutine. | -//| Z - multiplied matrix. | -//| Array whose indexes range within | -//| [0..ZRows-1,0..ZColumns-1]. | -//| ZRows - number of rows in matrix Z. If | -//| FromTheRight=False, ZRows=N, otherwise ZRows | -//| can be arbitrary. | -//| ZColumns - number of columns in matrix Z. If | -//| FromTheRight=True, ZColumns=N, otherwise | -//| ZColumns can be arbitrary. | -//| FromTheRight - pre- or post-multiply. | -//| DoTranspose - multiply by P or P'. | -//| Output parameters: | -//| Z - product of Z and P. | -//| Array whose indexes range within | -//| [0..ZRows-1,0..ZColumns-1]. If ZRows=0 or | -//| ZColumns=0, the array is not modified. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixBDMultiplyByP(CMatrixDouble &qp,const int m, - const int n,double &taup[], - CMatrixDouble &z,const int zrows, - const int zcolumns,const bool fromtheright, - const bool dotranspose) - { -//--- function call - COrtFac::RMatrixBDMultiplyByP(qp,m,n,taup,z,zrows,zcolumns,fromtheright,dotranspose); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Unpacking of the main and secondary diagonals of bidiagonal | -//| decomposition of matrix A. | -//| Input parameters: | -//| B - output of RMatrixBD subroutine. | -//| M - number of rows in matrix B. | -//| N - number of columns in matrix B. | -//| Output parameters: | -//| IsUpper - True, if the matrix is upper bidiagonal. | -//| otherwise IsUpper is False. | -//| D - the main diagonal. | -//| Array whose index ranges within [0..Min(M,N)-1]. | -//| E - the secondary diagonal (upper or lower, depending| -//| on the value of IsUpper). | -//| Array index ranges within [0..Min(M,N)-1], the | -//| last element is not used. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixBDUnpackDiagonals(CMatrixDouble &b,const int m, - const int n,bool &isupper, - double &d[],double &e[]) - { -//--- initialization - isupper=false; -//--- function call - COrtFac::RMatrixBDUnpackDiagonals(b,m,n,isupper,d,e); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Reduction of a square matrix to upper Hessenberg form: | -//| Q'*A*Q = H, where Q is an orthogonal matrix, H - Hessenberg | -//| matrix. | -//| Input parameters: | -//| A - matrix A with elements [0..N-1, 0..N-1] | -//| N - size of matrix A. | -//| Output parameters: | -//| A - matrices Q and P in compact form (see below). | -//| Tau - array of scalar factors which are used to form | -//| matrix Q. | -//| Array whose index ranges within [0..N-2] | -//| Matrix H is located on the main diagonal, on the lower secondary | -//| diagonal and above the main diagonal of matrix A. The elements | -//| which are used to form matrix Q are situated in array Tau and | -//| below the lower secondary diagonal of matrix A as follows: | -//| Matrix Q is represented as a product of elementary reflections | -//| Q = H(0)*H(2)*...*H(n-2), | -//| where each H(i) is given by | -//| H(i) = 1 - tau * v * (v^T) | -//| where tau is a scalar stored in Tau[I]; v - is a real vector, | -//| so that v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) stored in | -//| A(i+2:n-1,i). | -//| -- LAPACK routine (version 3.0) -- | -//| Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., | -//| Courant Institute, Argonne National Lab, and Rice University| -//| October 31, 1992 | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixHessenberg(CMatrixDouble &a,const int n, - double &tau[]) - { -//--- function call - COrtFac::RMatrixHessenberg(a,n,tau); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Unpacking matrix Q which reduces matrix A to upper Hessenberg | -//| form | -//| Input parameters: | -//| A - output of RMatrixHessenberg subroutine. | -//| N - size of matrix A. | -//| Tau - scalar factors which are used to form Q. | -//| Output of RMatrixHessenberg subroutine. | -//| Output parameters: | -//| Q - matrix Q. | -//| Array whose indexes range within [0..N-1, 0..N-1]. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixHessenbergUnpackQ(CMatrixDouble &a,const int n, - double &tau[],CMatrixDouble &q) - { -//--- function call - COrtFac::RMatrixHessenbergUnpackQ(a,n,tau,q); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Unpacking matrix H (the result of matrix A reduction to upper | -//| Hessenberg form) | -//| Input parameters: | -//| A - output of RMatrixHessenberg subroutine. | -//| N - size of matrix A. | -//| Output parameters: | -//| H - matrix H. Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixHessenbergUnpackH(CMatrixDouble &a,const int n, - CMatrixDouble &h) - { -//--- function call - COrtFac::RMatrixHessenbergUnpackH(a,n,h); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Reduction of a symmetric matrix which is given by its higher or | -//| lower triangular part to a tridiagonal matrix using orthogonal | -//| similarity transformation: Q'*A*Q=T. | -//| Input parameters: | -//| A - matrix to be transformed | -//| array with elements [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| IsUpper - storage format. If IsUpper = True, then matrix A | -//| is given by its upper triangle, and the lower | -//| triangle is not used and not modified by the | -//| algorithm, and vice versa if IsUpper = False. | -//| Output parameters: | -//| A - matrices T and Q in compact form (see lower) | -//| Tau - array of factors which are forming matrices H(i) | -//| array with elements [0..N-2]. | -//| D - main diagonal of symmetric matrix T. | -//| array with elements [0..N-1]. | -//| E - secondary diagonal of symmetric matrix T. | -//| array with elements [0..N-2]. | -//| If IsUpper=True, the matrix Q is represented as a product of | -//| elementary reflectors | -//| Q = H(n-2) . . . H(2) H(0). | -//| Each H(i) has the form | -//| H(i) = I - tau * v * v' | -//| where tau is a real scalar, and v is a real vector with | -//| v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in | -//| A(0:i-1,i+1), and tau in TAU(i). | -//| If IsUpper=False, the matrix Q is represented as a product of | -//| elementary reflectors | -//| Q = H(0) H(2) . . . H(n-2). | -//| Each H(i) has the form | -//| H(i) = I - tau * v * v' | -//| where tau is a real scalar, and v is a real vector with | -//| v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in | -//| A(i+2:n-1,i), and tau in TAU(i). | -//| The contents of A on exit are illustrated by the following | -//| examples with n = 5: | -//| if UPLO = 'U': if UPLO = 'L': | -//| ( d e v1 v2 v3 ) ( d ) | -//| ( d e v2 v3 ) ( e d ) | -//| ( d e v3 ) ( v0 e d ) | -//| ( d e ) ( v0 v1 e d ) | -//| ( d ) ( v0 v1 v2 e d ) | -//| where d and e denote diagonal and off-diagonal elements of T, | -//| and vi denotes an element of the vector defining H(i). | -//| -- LAPACK routine (version 3.0) -- | -//| Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., | -//| Courant Institute, Argonne National Lab, and Rice University| -//| October 31, 1992 | -//+------------------------------------------------------------------+ -static void CAlglib::SMatrixTD(CMatrixDouble &a,const int n,const bool isupper, - double &tau[],double &d[],double &e[]) - { -//--- function call - COrtFac::SMatrixTD(a,n,isupper,tau,d,e); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Unpacking matrix Q which reduces symmetric matrix to a | -//| tridiagonal form. | -//| Input parameters: | -//| A - the result of a SMatrixTD subroutine | -//| N - size of matrix A. | -//| IsUpper - storage format (a parameter of SMatrixTD | -//| subroutine) | -//| Tau - the result of a SMatrixTD subroutine | -//| Output parameters: | -//| Q - transformation matrix. | -//| array with elements [0..N-1, 0..N-1]. | -//+------------------------------------------------------------------+ -static void CAlglib::SMatrixTDUnpackQ(CMatrixDouble &a,const int n, - const bool isupper,double &tau[], - CMatrixDouble &q) - { -//--- function call - COrtFac::SMatrixTDUnpackQ(a,n,isupper,tau,q); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Reduction of a Hermitian matrix which is given by its higher or | -//| lower triangular part to a real tridiagonal matrix using unitary | -//| similarity transformation: Q'*A*Q = T. | -//| Input parameters: | -//| A - matrix to be transformed | -//| array with elements [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| IsUpper - storage format. If IsUpper = True, then matrix A | -//| is given by its upper triangle, and the lower | -//| triangle is not used and not modified by the | -//| algorithm, and vice versa if IsUpper = False. | -//| Output parameters: | -//| A - matrices T and Q in compact form (see lower) | -//| Tau - array of factors which are forming matrices H(i) | -//| array with elements [0..N-2]. | -//| D - main diagonal of real symmetric matrix T. | -//| array with elements [0..N-1]. | -//| E - secondary diagonal of real symmetric matrix T. | -//| array with elements [0..N-2]. | -//| If IsUpper=True, the matrix Q is represented as a product of | -//| elementary reflectors | -//| Q = H(n-2) . . . H(2) H(0). | -//| Each H(i) has the form | -//| H(i) = I - tau * v * v' | -//| where tau is a complex scalar, and v is a complex vector with | -//| v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in | -//| A(0:i-1,i+1), and tau in TAU(i). | -//| If IsUpper=False, the matrix Q is represented as a product of | -//| elementary reflectors | -//| Q = H(0) H(2) . . . H(n-2). | -//| Each H(i) has the form | -//| H(i) = I - tau * v * v' | -//| where tau is a complex scalar, and v is a complex vector with | -//| v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in | -//| A(i+2:n-1,i), and tau in TAU(i). | -//| The contents of A on exit are illustrated by the following | -//| examples with n = 5: | -//| if UPLO = 'U': if UPLO = 'L': | -//| ( d e v1 v2 v3 ) ( d ) | -//| ( d e v2 v3 ) ( e d ) | -//| ( d e v3 ) ( v0 e d ) | -//| ( d e ) ( v0 v1 e d ) | -//| ( d ) ( v0 v1 v2 e d ) | -//| where d and e denote diagonal and off-diagonal elements of T, and| -//| vi denotes an element of the vector defining H(i). | -//| -- LAPACK routine (version 3.0) -- | -//| Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., | -//| Courant Institute, Argonne National Lab, and Rice University| -//| October 31, 1992 | -//+------------------------------------------------------------------+ -static void CAlglib::HMatrixTD(CMatrixComplex &a,const int n,const bool isupper, - al_complex &tau[],double &d[],double &e[]) - { -//--- function call - COrtFac::HMatrixTD(a,n,isupper,tau,d,e); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Unpacking matrix Q which reduces a Hermitian matrix to a real | -//| tridiagonal form. | -//| Input parameters: | -//| A - the result of a HMatrixTD subroutine | -//| N - size of matrix A. | -//| IsUpper - storage format (a parameter of HMatrixTD | -//| subroutine) | -//| Tau - the result of a HMatrixTD subroutine | -//| Output parameters: | -//| Q - transformation matrix. | -//| array with elements [0..N-1, 0..N-1]. | -//+------------------------------------------------------------------+ -static void CAlglib::HMatrixTDUnpackQ(CMatrixComplex &a,const int n, - const bool isupper,al_complex &tau[], - CMatrixComplex &q) - { -//--- function call - COrtFac::HMatrixTDUnpackQ(a,n,isupper,tau,q); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Finding the eigenvalues and eigenvectors of a symmetric matrix | -//| The algorithm finds eigen pairs of a symmetric matrix by reducing| -//| it to tridiagonal form and using the QL/QR algorithm. | -//| Input parameters: | -//| A - symmetric matrix which is given by its upper or | -//| lower triangular part. | -//| Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| ZNeeded - flag controlling whether the eigenvectors are | -//| needed or not. | -//| If ZNeeded is equal to: | -//| * 0, the eigenvectors are not returned; | -//| * 1, the eigenvectors are returned. | -//| IsUpper - storage format. | -//| Output parameters: | -//| D - eigenvalues in ascending order. | -//| Array whose index ranges within [0..N-1]. | -//| Z - if ZNeeded is equal to: | -//| * 0, Z hasn?t changed; | -//| * 1, Z contains the eigenvectors. | -//| Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| The eigenvectors are stored in the matrix | -//| columns. | -//| Result: | -//| True, if the algorithm has converged. | -//| False, if the algorithm hasn't converged (rare case). | -//+------------------------------------------------------------------+ -static bool CAlglib::SMatrixEVD(CMatrixDouble &a,const int n,int zneeded, - const bool isupper,double &d[], - CMatrixDouble &z) - { -//--- return result - return(CEigenVDetect::SMatrixEVD(a,n,zneeded,isupper,d,z)); - } -//+------------------------------------------------------------------+ -//| Subroutine for finding the eigenvalues (and eigenvectors) of a | -//| symmetric matrix in a given half open interval (A, B] by using a | -//| bisection and inverse iteration | -//| Input parameters: | -//| A - symmetric matrix which is given by its upper or | -//| lower triangular part. Array [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| ZNeeded - flag controlling whether the eigenvectors are | -//| needed or not. | -//| If ZNeeded is equal to: | -//| * 0, the eigenvectors are not returned; | -//| * 1, the eigenvectors are returned. | -//| IsUpperA - storage format of matrix A. | -//| B1, B2 - half open interval (B1, B2] to search | -//| eigenvalues in. | -//| Output parameters: | -//| M - number of eigenvalues found in a given | -//| half-interval (M>=0). | -//| W - array of the eigenvalues found. | -//| Array whose index ranges within [0..M-1]. | -//| Z - if ZNeeded is equal to: | -//| * 0, Z hasn?t changed; | -//| * 1, Z contains eigenvectors. | -//| Array whose indexes range within | -//| [0..N-1, 0..M-1]. | -//| The eigenvectors are stored in the matrix | -//| columns. | -//| Result: | -//| True, if successful. M contains the number of eigenvalues in | -//| the given half-interval (could be equal to 0), W contains the| -//| eigenvalues, Z contains the eigenvectors (if needed). | -//| False, if the bisection method subroutine wasn't able to find| -//| the eigenvalues in the given interval or if the inverse | -//| iteration subroutine wasn't able to find all the | -//| corresponding eigenvectors. In that case, the eigenvalues | -//| and eigenvectors are not returned, M is equal to 0. | -//+------------------------------------------------------------------+ -static bool CAlglib::SMatrixEVDR(CMatrixDouble &a,const int n,int zneeded, - const bool isupper,double b1,double b2, - int &m,double &w[],CMatrixDouble &z) - { -//--- initialization - m=0; -//--- return result - return(CEigenVDetect::SMatrixEVDR(a,n,zneeded,isupper,b1,b2,m,w,z)); - } -//+------------------------------------------------------------------+ -//| Subroutine for finding the eigenvalues and eigenvectors of a | -//| symmetric matrix with given indexes by using bisection and | -//| inverse iteration methods. | -//| Input parameters: | -//| A - symmetric matrix which is given by its upper or | -//| lower triangular part. Array whose indexes range | -//| within [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| ZNeeded - flag controlling whether the eigenvectors are | -//| needed or not. | -//| If ZNeeded is equal to: | -//| * 0, the eigenvectors are not returned; | -//| * 1, the eigenvectors are returned. | -//| IsUpperA - storage format of matrix A. | -//| I1, I2 - index interval for searching (from I1 to I2). | -//| 0 <= I1 <= I2 <= N-1. | -//| Output parameters: | -//| W - array of the eigenvalues found. | -//| Array whose index ranges within [0..I2-I1]. | -//| Z - if ZNeeded is equal to: | -//| * 0, Z hasn?t changed; | -//| * 1, Z contains eigenvectors. | -//| Array whose indexes range within | -//| [0..N-1, 0..I2-I1]. | -//| In that case, the eigenvectors are stored in the | -//| matrix columns. | -//| Result: | -//| True, if successful. W contains the eigenvalues, Z contains | -//| the eigenvectors (if needed). | -//| False, if the bisection method subroutine wasn't able to find| -//| the eigenvalues in the given interval or if the inverse | -//| iteration subroutine wasn't able to find all the | -//| corresponding eigenvectors. In that case, the eigenvalues | -//| and eigenvectors are not returned. | -//+------------------------------------------------------------------+ -static bool CAlglib::SMatrixEVDI(CMatrixDouble &a,const int n,int zneeded, - const bool isupper,const int i1, - const int i2,double &w[],CMatrixDouble &z) - { -//--- return result - return(CEigenVDetect::SMatrixEVDI(a,n,zneeded,isupper,i1,i2,w,z)); - } -//+------------------------------------------------------------------+ -//| Finding the eigenvalues and eigenvectors of a Hermitian matrix | -//| The algorithm finds eigen pairs of a Hermitian matrix by reducing| -//| it to real tridiagonal form and using the QL/QR algorithm. | -//| Input parameters: | -//| A - Hermitian matrix which is given by its upper or | -//| lower triangular part. | -//| Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| IsUpper - storage format. | -//| ZNeeded - flag controlling whether the eigenvectors are | -//| needed or not. If ZNeeded is equal to: | -//| * 0, the eigenvectors are not returned; | -//| * 1, the eigenvectors are returned. | -//| Output parameters: | -//| D - eigenvalues in ascending order. | -//| Array whose index ranges within [0..N-1]. | -//| Z - if ZNeeded is equal to: | -//| * 0, Z hasn?t changed; | -//| * 1, Z contains the eigenvectors. | -//| Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| The eigenvectors are stored in the matrix | -//| columns. | -//| Result: | -//| True, if the algorithm has converged. | -//| False, if the algorithm hasn't converged (rare case). | -//| Note: | -//| eigenvectors of Hermitian matrix are defined up to | -//| multiplication by a complex number L, such that |L|=1. | -//+------------------------------------------------------------------+ -static bool CAlglib::HMatrixEVD(CMatrixComplex &a,const int n,const int zneeded, - const bool isupper,double &d[],CMatrixComplex &z) - { -//--- return result - return(CEigenVDetect::HMatrixEVD(a,n,zneeded,isupper,d,z)); - } -//+------------------------------------------------------------------+ -//| Subroutine for finding the eigenvalues (and eigenvectors) of a | -//| Hermitian matrix in a given half-interval (A, B] by using a | -//| bisection and inverse iteration | -//| Input parameters: | -//| A - Hermitian matrix which is given by its upper or | -//| lower triangular part. Array whose indexes range | -//| within [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| ZNeeded - flag controlling whether the eigenvectors are | -//| needed or not. If ZNeeded is equal to: | -//| * 0, the eigenvectors are not returned; | -//| * 1, the eigenvectors are returned. | -//| IsUpperA - storage format of matrix A. | -//| B1, B2 - half-interval (B1, B2] to search eigenvalues in. | -//| Output parameters: | -//| M - number of eigenvalues found in a given | -//| half-interval, M>=0 | -//| W - array of the eigenvalues found. | -//| Array whose index ranges within [0..M-1]. | -//| Z - if ZNeeded is equal to: | -//| * 0, Z hasn?t changed; | -//| * 1, Z contains eigenvectors. | -//| Array whose indexes range within | -//| [0..N-1, 0..M-1]. | -//| The eigenvectors are stored in the matrix | -//| columns. | -//| Result: | -//| True, if successful. M contains the number of eigenvalues | -//| in the given half-interval (could be equal to 0), W contains | -//| the eigenvalues, Z contains the eigenvectors (if needed). | -//| False, if the bisection method subroutine wasn't able to find| -//| the eigenvalues in the given interval or if the inverse | -//| iteration subroutine wasn't able to find all the | -//| corresponding eigenvectors. In that case, the eigenvalues and| -//| eigenvectors are not returned, M is equal to 0. | -//| Note: | -//| eigen vectors of Hermitian matrix are defined up to | -//| multiplication by a complex number L, such as |L|=1. | -//+------------------------------------------------------------------+ -static bool CAlglib::HMatrixEVDR(CMatrixComplex &a,const int n,const int zneeded, - const bool isupper,double b1,double b2, - int &m,double &w[],CMatrixComplex &z) - { -//--- initialization - m=0; -//--- return result - return(CEigenVDetect::HMatrixEVDR(a,n,zneeded,isupper,b1,b2,m,w,z)); - } -//+------------------------------------------------------------------+ -//| Subroutine for finding the eigenvalues and eigenvectors of a | -//| Hermitian matrix with given indexes by using bisection and | -//| inverse iteration methods | -//| Input parameters: | -//| A - Hermitian matrix which is given by its upper or | -//| lower triangular part. | -//| Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| ZNeeded - flag controlling whether the eigenvectors are | -//| needed or not. If ZNeeded is equal to: | -//| * 0, the eigenvectors are not returned; | -//| * 1, the eigenvectors are returned. | -//| IsUpperA - storage format of matrix A. | -//| I1, I2 - index interval for searching (from I1 to I2). | -//| 0 <= I1 <= I2 <= N-1. | -//| Output parameters: | -//| W - array of the eigenvalues found. | -//| Array whose index ranges within [0..I2-I1]. | -//| Z - if ZNeeded is equal to: | -//| * 0, Z hasn?t changed; | -//| * 1, Z contains eigenvectors. | -//| Array whose indexes range within | -//| [0..N-1, 0..I2-I1]. | -//| In that case, the eigenvectors are stored in | -//| the matrix columns. | -//| Result: | -//| True, if successful. W contains the eigenvalues, Z contains | -//| the eigenvectors (if needed). | -//| False, if the bisection method subroutine wasn't able to find| -//| the eigenvalues in the given interval or if the inverse | -//| corresponding eigenvectors. iteration subroutine wasn't able | -//| to find all the corresponding eigenvectors. In that case, | -//| the eigenvalues and eigenvectors are not returned. | -//| Note: | -//| eigen vectors of Hermitian matrix are defined up to | -//| multiplication by a complex number L, such as |L|=1. | -//+------------------------------------------------------------------+ -static bool CAlglib::HMatrixEVDI(CMatrixComplex &a,const int n,const int zneeded, - const bool isupper,const int i1,const int i2, - double &w[],CMatrixComplex &z) - { -//--- return result - return(CEigenVDetect::HMatrixEVDI(a,n,zneeded,isupper,i1,i2,w,z)); - } -//+------------------------------------------------------------------+ -//| Finding the eigenvalues and eigenvectors of a tridiagonal | -//| symmetric matrix | -//| The algorithm finds the eigen pairs of a tridiagonal symmetric | -//| matrix by using an QL/QR algorithm with implicit shifts. | -//| Input parameters: | -//| D - the main diagonal of a tridiagonal matrix. | -//| Array whose index ranges within [0..N-1]. | -//| E - the secondary diagonal of a tridiagonal matrix. | -//| Array whose index ranges within [0..N-2]. | -//| N - size of matrix A. | -//| ZNeeded - flag controlling whether the eigenvectors are | -//| needed or not. | -//| If ZNeeded is equal to: | -//| * 0, the eigenvectors are not needed; | -//| * 1, the eigenvectors of a tridiagonal matrix | -//| are multiplied by the square matrix Z. It is | -//| used if the tridiagonal matrix is obtained by | -//| the similarity transformation of a symmetric | -//| matrix; | -//| * 2, the eigenvectors of a tridiagonal matrix | -//| replace the square matrix Z; | -//| * 3, matrix Z contains the first row of the | -//| eigenvectors matrix. | -//| Z - if ZNeeded=1, Z contains the square matrix by | -//| which the eigenvectors are multiplied. | -//| Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| Output parameters: | -//| D - eigenvalues in ascending order. | -//| Array whose index ranges within [0..N-1]. | -//| Z - if ZNeeded is equal to: | -//| * 0, Z hasn?t changed; | -//| * 1, Z contains the product of a given matrix | -//| (from the left) and the eigenvectors matrix | -//| (from the right); | -//| * 2, Z contains the eigenvectors. | -//| * 3, Z contains the first row of the | -//| eigenvectors matrix. | -//| If ZNeeded<3, Z is the array whose indexes range | -//| within [0..N-1, 0..N-1]. | -//| In that case, the eigenvectors are stored in the | -//| matrix columns. | -//| If ZNeeded=3, Z is the array whose indexes range | -//| within [0..0, 0..N-1]. | -//| Result: | -//| True, if the algorithm has converged. | -//| False, if the algorithm hasn't converged. | -//| -- LAPACK routine (version 3.0) -- | -//| Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., | -//| Courant Institute, Argonne National Lab, and Rice University| -//| September 30, 1994 | -//+------------------------------------------------------------------+ -static bool CAlglib::SMatrixTdEVD(double &d[],double &e[],const int n, - const int zneeded,CMatrixDouble &z) - { -//--- return result - return(CEigenVDetect::SMatrixTdEVD(d,e,n,zneeded,z)); - } -//+------------------------------------------------------------------+ -//| Subroutine for finding the tridiagonal matrix eigenvalues/vectors| -//| in a given half-interval (A, B] by using bisection and inverse | -//| iteration. | -//| Input parameters: | -//| D - the main diagonal of a tridiagonal matrix. | -//| Array whose index ranges within [0..N-1]. | -//| E - the secondary diagonal of a tridiagonal matrix. | -//| Array whose index ranges within [0..N-2]. | -//| N - size of matrix, N>=0. | -//| ZNeeded - flag controlling whether the eigenvectors are | -//| needed or not. If ZNeeded is equal to: | -//| * 0, the eigenvectors are not needed; | -//| * 1, the eigenvectors of a tridiagonal matrix | -//| are multiplied by the square matrix Z. It is | -//| used if the tridiagonal matrix is obtained by | -//| the similarity transformation of a symmetric | -//| matrix. | -//| * 2, the eigenvectors of a tridiagonal matrix | -//| replace matrix Z. | -//| A, B - half-interval (A, B] to search eigenvalues in. | -//| Z - if ZNeeded is equal to: | -//| * 0, Z isn't used and remains unchanged; | -//| * 1, Z contains the square matrix (array whose | -//| indexes range within [0..N-1, 0..N-1]) which | -//| reduces the given symmetric matrix to | -//| tridiagonal form; | -//| * 2, Z isn't used (but changed on the exit). | -//| Output parameters: | -//| D - array of the eigenvalues found. | -//| Array whose index ranges within [0..M-1]. | -//| M - number of eigenvalues found in the given | -//| half-interval (M>=0). | -//| Z - if ZNeeded is equal to: | -//| * 0, doesn't contain any information; | -//| * 1, contains the product of a given NxN matrix | -//| Z (from the left) and NxM matrix of the | -//| eigenvectors found (from the right). Array | -//| whose indexes range within [0..N-1, 0..M-1]. | -//| * 2, contains the matrix of the eigenvectors | -//| found. Array whose indexes range within | -//| [0..N-1, 0..M-1]. | -//| Result: | -//| True, if successful. In that case, M contains the number of | -//| eigenvalues in the given half-interval (could be equal to 0),| -//| D contains the eigenvalues, Z contains the eigenvectors (if | -//| needed). It should be noted that the subroutine changes the | -//| size of arrays D and Z. | -//| False, if the bisection method subroutine wasn't able to find| -//| the eigenvalues in the given interval or if the inverse | -//| iteration subroutine wasn't able to find all the | -//| corresponding eigenvectors. In that case, the eigenvalues and| -//| eigenvectors are not returned, M is equal to 0. | -//+------------------------------------------------------------------+ -static bool CAlglib::SMatrixTdEVDR(double &d[],double &e[],const int n, - const int zneeded,const double a, - const double b,int &m,CMatrixDouble &z) - { -//--- initialization - m=0; -//--- return result - return(CEigenVDetect::SMatrixTdEVDR(d,e,n,zneeded,a,b,m,z)); - } -//+------------------------------------------------------------------+ -//| Subroutine for finding tridiagonal matrix eigenvalues/vectors | -//| with given indexes (in ascending order) by using the bisection | -//| and inverse iteraion. | -//| Input parameters: | -//| D - the main diagonal of a tridiagonal matrix. | -//| Array whose index ranges within [0..N-1]. | -//| E - the secondary diagonal of a tridiagonal matrix. | -//| Array whose index ranges within [0..N-2]. | -//| N - size of matrix. N>=0. | -//| ZNeeded - flag controlling whether the eigenvectors are | -//| needed or not. If ZNeeded is equal to: | -//| * 0, the eigenvectors are not needed; | -//| * 1, the eigenvectors of a tridiagonal matrix | -//| are multiplied by the square matrix Z. It is | -//| used if the tridiagonal matrix is obtained by | -//| the similarity transformation of a symmetric | -//| matrix. | -//| * 2, the eigenvectors of a tridiagonal matrix | -//| replace matrix Z. | -//| I1, I2 - index interval for searching (from I1 to I2). | -//| 0 <= I1 <= I2 <= N-1. | -//| Z - if ZNeeded is equal to: | -//| * 0, Z isn't used and remains unchanged; | -//| * 1, Z contains the square matrix (array whose | -//| indexes range within [0..N-1, 0..N-1]) which | -//| reduces the given symmetric matrix to | -//| tridiagonal form; | -//| * 2, Z isn't used (but changed on the exit). | -//| Output parameters: | -//| D - array of the eigenvalues found. | -//| Array whose index ranges within [0..I2-I1]. | -//| Z - if ZNeeded is equal to: | -//| * 0, doesn't contain any information; | -//| * 1, contains the product of a given NxN matrix | -//| Z (from the left) and Nx(I2-I1) matrix of the | -//| eigenvectors found (from the right). Array | -//| whose indexes range within [0..N-1, 0..I2-I1].| -//| * 2, contains the matrix of the eigenvalues | -//| found. Array whose indexes range within | -//| [0..N-1, 0..I2-I1]. | -//| Result: | -//| True, if successful. In that case, D contains the | -//| eigenvalues, Z contains the eigenvectors (if needed). | -//| It should be noted that the subroutine changes the size of | -//| arrays D and Z. | -//| False, if the bisection method subroutine wasn't able to find| -//| the eigenvalues in the given interval or if the inverse | -//| iteration subroutine wasn't able to find all the | -//| corresponding eigenvectors. In that case, the eigenvalues and| -//| eigenvectors are not returned. | -//+------------------------------------------------------------------+ -static bool CAlglib::SMatrixTdEVDI(double &d[],double &e[],const int n, - const int zneeded,const int i1, - const int i2,CMatrixDouble &z) - { -//--- return result - return(CEigenVDetect::SMatrixTdEVDI(d,e,n,zneeded,i1,i2,z)); - } -//+------------------------------------------------------------------+ -//| Finding eigenvalues and eigenvectors of a general matrix | -//| The algorithm finds eigenvalues and eigenvectors of a general | -//| matrix by using the QR algorithm with multiple shifts. The | -//| algorithm can find eigenvalues and both left and right | -//| eigenvectors. | -//| The right eigenvector is a vector x such that A*x = w*x, and the | -//| left eigenvector is a vector y such that y'*A = w*y' (here y' | -//| implies a complex conjugate transposition of vector y). | -//| Input parameters: | -//| A - matrix. Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| VNeeded - flag controlling whether eigenvectors are needed | -//| or not. If VNeeded is equal to: | -//| * 0, eigenvectors are not returned; | -//| * 1, right eigenvectors are returned; | -//| * 2, left eigenvectors are returned; | -//| * 3, both left and right eigenvectors are | -//| returned. | -//| Output parameters: | -//| WR - real parts of eigenvalues. | -//| Array whose index ranges within [0..N-1]. | -//| WR - imaginary parts of eigenvalues. | -//| Array whose index ranges within [0..N-1]. | -//| VL, VR - arrays of left and right eigenvectors (if they | -//| are needed). If WI[i]=0, the respective | -//| eigenvalue is a real number, and it corresponds | -//| to the column number I of matrices VL/VR. If | -//| WI[i]>0, we have a pair of complex conjugate | -//| numbers with positive and negative imaginary | -//| parts: the first eigenvalue WR[i] + | -//| + sqrt(-1)*WI[i]; the second eigenvalue | -//| WR[i+1] + sqrt(-1)*WI[i+1]; | -//| WI[i]>0 | -//| WI[i+1] = -WI[i] < 0 | -//| In that case, the eigenvector corresponding to | -//| the first eigenvalue is located in i and i+1 | -//| columns of matrices VL/VR (the column number i | -//| contains the real part, and the column number | -//| i+1 contains the imaginary part), and the vector | -//| corresponding to the second eigenvalue is a | -//| complex conjugate to the first vector. | -//| Arrays whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| Result: | -//| True, if the algorithm has converged. | -//| False, if the algorithm has not converged. | -//| Note 1: | -//| Some users may ask the following question: what if WI[N-1]>0?| -//| WI[N] must contain an eigenvalue which is complex conjugate | -//| to the N-th eigenvalue, but the array has only size N? | -//| The answer is as follows: such a situation cannot occur | -//| because the algorithm finds a pairs of eigenvalues, | -//| therefore, if WI[i]>0, I is strictly less than N-1. | -//| Note 2: | -//| The algorithm performance depends on the value of the | -//| internal parameter NS of the InternalSchurDecomposition | -//| subroutine which defines the number of shifts in the QR | -//| algorithm (similarly to the block width in block-matrix | -//| algorithms of linear algebra). If you require maximum | -//| performance on your machine, it is recommended to adjust | -//| this parameter manually. | -//| See also the InternalTREVC subroutine. | -//| The algorithm is based on the LAPACK 3.0 library. | -//+------------------------------------------------------------------+ -static bool CAlglib::RMatrixEVD(CMatrixDouble &a,const int n,const int vneeded, - double &wr[],double &wi[],CMatrixDouble &vl, - CMatrixDouble &vr) - { - bool result=CEigenVDetect::RMatrixEVD(a,n,vneeded,wr,wi,vl,vr); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Generation of a random uniformly distributed (Haar) orthogonal | -//| matrix | -//| INPUT PARAMETERS: | -//| N - matrix size, N>=1 | -//| OUTPUT PARAMETERS: | -//| A - orthogonal NxN matrix, array[0..N-1,0..N-1] | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixRndOrthogonal(const int n,CMatrixDouble &a) - { -//--- function call - CMatGen::RMatrixRndOrthogonal(n,a); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Generation of random NxN matrix with given condition number and | -//| norm2(A)=1 | -//| INPUT PARAMETERS: | -//| N - matrix size | -//| C - condition number (in 2-norm) | -//| OUTPUT PARAMETERS: | -//| A - random matrix with norm2(A)=1 and cond(A)=C | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixRndCond(const int n,const double c, - CMatrixDouble &a) - { -//--- function call - CMatGen::RMatrixRndCond(n,c,a); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Generation of a random Haar distributed orthogonal complex matrix| -//| INPUT PARAMETERS: | -//| N - matrix size, N>=1 | -//| OUTPUT PARAMETERS: | -//| A - orthogonal NxN matrix, array[0..N-1,0..N-1] | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixRndOrthogonal(const int n,CMatrixComplex &a) - { -//--- function call - CMatGen::CMatrixRndOrthogonal(n,a); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Generation of random NxN complex matrix with given condition | -//| number C and norm2(A)=1 | -//| INPUT PARAMETERS: | -//| N - matrix size | -//| C - condition number (in 2-norm) | -//| OUTPUT PARAMETERS: | -//| A - random matrix with norm2(A)=1 and cond(A)=C | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixRndCond(const int n,const double c, - CMatrixComplex &a) - { -//--- function call - CMatGen::CMatrixRndCond(n,c,a); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Generation of random NxN symmetric matrix with given condition | -//| number and norm2(A)=1 | -//| INPUT PARAMETERS: | -//| N - matrix size | -//| C - condition number (in 2-norm) | -//| OUTPUT PARAMETERS: | -//| A - random matrix with norm2(A)=1 and cond(A)=C | -//+------------------------------------------------------------------+ -static void CAlglib::SMatrixRndCond(const int n,const double c, - CMatrixDouble &a) - { -//--- function call - CMatGen::SMatrixRndCond(n,c,a); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Generation of random NxN symmetric positive definite matrix with | -//| given condition number and norm2(A)=1 | -//| INPUT PARAMETERS: | -//| N - matrix size | -//| C - condition number (in 2-norm) | -//| OUTPUT PARAMETERS: | -//| A - random SPD matrix with norm2(A)=1 and cond(A)=C | -//+------------------------------------------------------------------+ -static void CAlglib::SPDMatrixRndCond(const int n,const double c, - CMatrixDouble &a) - { -//--- function call - CMatGen::SPDMatrixRndCond(n,c,a); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Generation of random NxN Hermitian matrix with given condition | -//| number and norm2(A)=1 | -//| INPUT PARAMETERS: | -//| N - matrix size | -//| C - condition number (in 2-norm) | -//| OUTPUT PARAMETERS: | -//| A - random matrix with norm2(A)=1 and cond(A)=C | -//+------------------------------------------------------------------+ -static void CAlglib::HMatrixRndCond(const int n,const double c, - CMatrixComplex &a) - { -//--- function call - CMatGen::HMatrixRndCond(n,c,a); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Generation of random NxN Hermitian positive definite matrix with | -//| given condition number and norm2(A)=1 | -//| INPUT PARAMETERS: | -//| N - matrix size | -//| C - condition number (in 2-norm) | -//| OUTPUT PARAMETERS: | -//| A - random HPD matrix with norm2(A)=1 and cond(A)=C | -//+------------------------------------------------------------------+ -static void CAlglib::HPDMatrixRndCond(const int n,const double c, - CMatrixComplex &a) - { -//--- function call - CMatGen::HPDMatrixRndCond(n,c,a); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Multiplication of MxN matrix by NxN random Haar distributed | -//| orthogonal matrix | -//| INPUT PARAMETERS: | -//| A - matrix, array[0..M-1, 0..N-1] | -//| M, N- matrix size | -//| OUTPUT PARAMETERS: | -//| A - A*Q, where Q is random NxN orthogonal matrix | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixRndOrthogonalFromTheRight(CMatrixDouble &a, - const int m,const int n) - { -//--- function call - CMatGen::RMatrixRndOrthogonalFromTheRight(a,m,n); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Multiplication of MxN matrix by MxM random Haar distributed | -//| orthogonal matrix | -//| INPUT PARAMETERS: | -//| A - matrix, array[0..M-1, 0..N-1] | -//| M, N- matrix size | -//| OUTPUT PARAMETERS: | -//| A - Q*A, where Q is random MxM orthogonal matrix | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixRndOrthogonalFromTheLeft(CMatrixDouble &a, - const int m,const int n) - { -//--- function call - CMatGen::RMatrixRndOrthogonalFromTheLeft(a,m,n); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Multiplication of MxN complex matrix by NxN random Haar | -//| distributed complex orthogonal matrix | -//| INPUT PARAMETERS: | -//| A - matrix, array[0..M-1, 0..N-1] | -//| M, N- matrix size | -//| OUTPUT PARAMETERS: | -//| A - A*Q, where Q is random NxN orthogonal matrix | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixRndOrthogonalFromTheRight(CMatrixComplex &a, - const int m,const int n) - { -//--- function call - CMatGen::CMatrixRndOrthogonalFromTheRight(a,m,n); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Multiplication of MxN complex matrix by MxM random Haar | -//| distributed complex orthogonal matrix | -//| INPUT PARAMETERS: | -//| A - matrix, array[0..M-1, 0..N-1] | -//| M, N- matrix size | -//| OUTPUT PARAMETERS: | -//| A - Q*A, where Q is random MxM orthogonal matrix | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixRndOrthogonalFromTheLeft(CMatrixComplex &a, - const int m,const int n) - { -//--- function call - CMatGen::CMatrixRndOrthogonalFromTheLeft(a,m,n); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Symmetric multiplication of NxN matrix by random Haar | -//| distributed orthogonal matrix | -//| INPUT PARAMETERS: | -//| A - matrix, array[0..N-1, 0..N-1] | -//| N - matrix size | -//| OUTPUT PARAMETERS: | -//| A - Q'*A*Q, where Q is random NxN orthogonal matrix | -//+------------------------------------------------------------------+ -static void CAlglib::SMatrixRndMultiply(CMatrixDouble &a,const int n) - { -//--- function call - CMatGen::SMatrixRndMultiply(a,n); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Hermitian multiplication of NxN matrix by random Haar distributed| -//| complex orthogonal matrix | -//| INPUT PARAMETERS: | -//| A - matrix, array[0..N-1, 0..N-1] | -//| N - matrix size | -//| OUTPUT PARAMETERS: | -//| A - Q^H*A*Q, where Q is random NxN orthogonal matrix | -//+------------------------------------------------------------------+ -static void CAlglib::HMatrixRndMultiply(CMatrixComplex &a,const int n) - { -//--- function call - CMatGen::HMatrixRndMultiply(a,n); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| LU decomposition of a general real matrix with row pivoting | -//| A is represented as A = P*L*U, where: | -//| * L is lower unitriangular matrix | -//| * U is upper triangular matrix | -//| * P = P0*P1*...*PK, K=min(M,N)-1, | -//| Pi - permutation matrix for I and Pivots[I] | -//| This is cache-oblivous implementation of LU decomposition. | -//| It is optimized for square matrices. As for rectangular matrices:| -//| * best case - M>>N | -//| * worst case - N>>M, small M, large N, matrix does not fit in CPU| -//| cache | -//| INPUT PARAMETERS: | -//| A - array[0..M-1, 0..N-1]. | -//| M - number of rows in matrix A. | -//| N - number of columns in matrix A. | -//| OUTPUT PARAMETERS: | -//| A - matrices L and U in compact form: | -//| * L is stored under main diagonal | -//| * U is stored on and above main diagonal | -//| Pivots - permutation matrix in compact form. | -//| array[0..Min(M-1,N-1)]. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixLU(CMatrixDouble &a,const int m,const int n, - int &pivots[]) - { -//--- function call - CTrFac::RMatrixLU(a,m,n,pivots); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| LU decomposition of a general complex matrix with row pivoting | -//| A is represented as A = P*L*U, where: | -//| * L is lower unitriangular matrix | -//| * U is upper triangular matrix | -//| * P = P0*P1*...*PK, K=min(M,N)-1, | -//| Pi - permutation matrix for I and Pivots[I] | -//| This is cache-oblivous implementation of LU decomposition. It is | -//| optimized for square matrices. As for rectangular matrices: | -//| * best case - M>>N | -//| * worst case - N>>M, small M, large N, matrix does not fit in CPU| -//| cache | -//| INPUT PARAMETERS: | -//| A - array[0..M-1, 0..N-1]. | -//| M - number of rows in matrix A. | -//| N - number of columns in matrix A. | -//| OUTPUT PARAMETERS: | -//| A - matrices L and U in compact form: | -//| * L is stored under main diagonal | -//| * U is stored on and above main diagonal | -//| Pivots - permutation matrix in compact form. | -//| array[0..Min(M-1,N-1)]. | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixLU(CMatrixComplex &a,const int m,const int n, - int &pivots[]) - { -//--- function call - CTrFac::CMatrixLU(a,m,n,pivots); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Cache-oblivious Cholesky decomposition | -//| The algorithm computes Cholesky decomposition of a Hermitian | -//| positive - definite matrix. The result of an algorithm is a | -//| representation of A as A=U'*U or A=L*L' (here X' detones | -//| conj(X^T)). | -//| INPUT PARAMETERS: | -//| A - upper or lower triangle of a factorized matrix. | -//| array with elements [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| IsUpper - if IsUpper=True, then A contains an upper | -//| triangle of a symmetric matrix, otherwise A | -//| contains a lower one. | -//| OUTPUT PARAMETERS: | -//| A - the result of factorization. If IsUpper=True, | -//| then the upper triangle contains matrix U, so | -//| that A = U'*U, and the elements below the main | -//| diagonal are not modified. Similarly, if | -//| IsUpper = False. | -//| RESULT: | -//| If the matrix is positive-definite, the function returns | -//| True. Otherwise, the function returns False. Contents of A is| -//| not determined in such case. | -//+------------------------------------------------------------------+ -static bool CAlglib::HPDMatrixCholesky(CMatrixComplex &a,const int n, - const bool isupper) - { -//--- return result - return(CTrFac::HPDMatrixCholesky(a,n,isupper)); - } -//+------------------------------------------------------------------+ -//| Cache-oblivious Cholesky decomposition | -//| The algorithm computes Cholesky decomposition of a symmetric | -//| positive - definite matrix. The result of an algorithm is a | -//| representation of A as A=U^T*U or A=L*L^T | -//| INPUT PARAMETERS: | -//| A - upper or lower triangle of a factorized matrix. | -//| array with elements [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| IsUpper - if IsUpper=True, then A contains an upper | -//| triangle of a symmetric matrix, otherwise A | -//| contains a lower one. | -//| OUTPUT PARAMETERS: | -//| A - the result of factorization. If IsUpper=True, | -//| then the upper triangle contains matrix U, so | -//| that A = U^T*U, and the elements below the main | -//| diagonal are not modified. Similarly, if | -//| IsUpper = False. | -//| RESULT: | -//| If the matrix is positive-definite, the function returns | -//| True. Otherwise, the function returns False. Contents of A is| -//| not determined in such case. | -//+------------------------------------------------------------------+ -static bool CAlglib::SPDMatrixCholesky(CMatrixDouble &a,const int n, - const bool isupper) - { -//--- return result - return(CTrFac::SPDMatrixCholesky(a,n,isupper)); - } -//+------------------------------------------------------------------+ -//| Estimate of a matrix condition number (1-norm) | -//| The algorithm calculates a lower bound of the condition number. | -//| In this case, the algorithm does not return a lower bound of the | -//| condition number, but an inverse number (to avoid an overflow in | -//| case of a singular matrix). | -//| Input parameters: | -//| A - matrix. Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| Result: 1/LowerBound(cond(A)) | -//| NOTE: | -//| if k(A) is very large, then matrix is assumed degenerate, | -//| k(A)=INF, 0.0 is returned in such cases. | -//+------------------------------------------------------------------+ -static double CAlglib::RMatrixRCond1(CMatrixDouble &a,const int n) - { -//--- return result - return(CRCond::RMatrixRCond1(a,n)); - } -//+------------------------------------------------------------------+ -//| Estimate of a matrix condition number (infinity-norm). | -//| The algorithm calculates a lower bound of the condition number. | -//| In this case, the algorithm does not return a lower bound of the | -//| condition number, but an inverse number (to avoid an overflow in | -//| case of a singular matrix). | -//| Input parameters: | -//| A - matrix. Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| Result: 1/LowerBound(cond(A)) | -//| NOTE: | -//| if k(A) is very large, then matrix is assumed degenerate, | -//| k(A)=INF, 0.0 is returned in such cases. | -//+------------------------------------------------------------------+ -static double CAlglib::RMatrixRCondInf(CMatrixDouble &a,const int n) - { -//--- return result - return(CRCond::RMatrixRCondInf(a,n)); - } -//+------------------------------------------------------------------+ -//| Condition number estimate of a symmetric positive definite | -//| matrix. | -//| The algorithm calculates a lower bound of the condition number. | -//| In this case, the algorithm does not return a lower bound of the | -//| condition number, but an inverse number (to avoid an overflow in | -//| case of a singular matrix). | -//| It should be noted that 1-norm and inf-norm of condition numbers | -//| of symmetric matrices are equal, so the algorithm doesn't take | -//| into account the differences between these types of norms. | -//| Input parameters: | -//| A - symmetric positive definite matrix which is given| -//| by its upper or lower triangle depending on the | -//| value of IsUpper. Array with elements | -//| [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| IsUpper - storage format. | -//| Result: | -//| 1/LowerBound(cond(A)), if matrix A is positive definite, | -//| -1, if matrix A is not positive definite, and its condition | -//| number could not be found by this algorithm. | -//| NOTE: | -//| if k(A) is very large, then matrix is assumed degenerate, | -//| k(A)=INF, 0.0 is returned in such cases. | -//+------------------------------------------------------------------+ -static double CAlglib::SPDMatrixRCond(CMatrixDouble &a,const int n, - const bool isupper) - { -//--- return result - return(CRCond::SPDMatrixRCond(a,n,isupper)); - } -//+------------------------------------------------------------------+ -//| Triangular matrix: estimate of a condition number (1-norm) | -//| The algorithm calculates a lower bound of the condition number. | -//| In this case, the algorithm does not return a lower bound of the | -//| condition number, but an inverse number (to avoid an overflow in | -//| case of a singular matrix). | -//| Input parameters: | -//| A - matrix. Array[0..N-1, 0..N-1]. | -//| N - size of A. | -//| IsUpper - True, if the matrix is upper triangular. | -//| IsUnit - True, if the matrix has a unit diagonal. | -//| Result: 1/LowerBound(cond(A)) | -//| NOTE: | -//| if k(A) is very large, then matrix is assumed degenerate, | -//| k(A)=INF, 0.0 is returned in such cases. | -//+------------------------------------------------------------------+ -static double CAlglib::RMatrixTrRCond1(CMatrixDouble &a,const int n, - const bool isupper,const bool isunit) - { -//--- return result - return(CRCond::RMatrixTrRCond1(a,n,isupper,isunit)); - } -//+-------------------------------------------------------------------+ -//| Triangular matrix: estimate of a matrix condition number | -//| (infinity-norm). | -//| The algorithm calculates a lower bound of the condition number. In| -//| this case, the algorithm does not return a lower bound of the | -//| condition number, but an inverse number (to avoid an overflow in | -//| case of a singular matrix). | -//| Input parameters: | -//| A - matrix. Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| IsUpper - True, if the matrix is upper triangular. | -//| IsUnit - True, if the matrix has a unit diagonal. | -//| Result: 1/LowerBound(cond(A)) | -//| NOTE: | -//| if k(A) is very large, then matrix is assumed degenerate, | -//| k(A)=INF, 0.0 is returned in such cases. | -//+-------------------------------------------------------------------+ -static double CAlglib::RMatrixTrRCondInf(CMatrixDouble &a,const int n, - const bool isupper,const bool isunit) - { -//--- return result - return(CRCond::RMatrixTrRCondInf(a,n,isupper,isunit)); - } -//+------------------------------------------------------------------+ -//| Condition number estimate of a Hermitian positive definite | -//| matrix. | -//| The algorithm calculates a lower bound of the condition number. | -//| In this case, the algorithm does not return a lower bound of the | -//| condition number, but an inverse number (to avoid an overflow in | -//| case of a singular matrix). | -//| It should be noted that 1-norm and inf-norm of condition numbers | -//| of symmetric matrices are equal, so the algorithm doesn't take | -//| into account the differences between these types of norms. | -//| Input parameters: | -//| A - Hermitian positive definite matrix which is given| -//| by its upper or lower triangle depending on the | -//| value of IsUpper. Array with elements | -//| [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| IsUpper - storage format. | -//| Result: | -//| 1/LowerBound(cond(A)), if matrix A is positive definite, | -//| -1, if matrix A is not positive definite, and its condition | -//| number could not be found by this algorithm. | -//| NOTE: | -//| if k(A) is very large, then matrix is assumed degenerate, | -//| k(A)=INF, 0.0 is returned in such cases. | -//+------------------------------------------------------------------+ -static double CAlglib::HPDMatrixRCond(CMatrixComplex &a,const int n, - const bool isupper) - { -//--- return result - return(CRCond::HPDMatrixRCond(a,n,isupper)); - } -//+------------------------------------------------------------------+ -//| Estimate of a matrix condition number (1-norm) | -//| The algorithm calculates a lower bound of the condition number. | -//| In this case, the algorithm does not return a lower bound of the | -//| condition number, but an inverse number (to avoid an overflow in | -//| case of a singular matrix). | -//| Input parameters: | -//| A - matrix. Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| Result: 1/LowerBound(cond(A)) | -//| NOTE: | -//| if k(A) is very large, then matrix is assumed degenerate, | -//| k(A)=INF, 0.0 is returned in such cases. | -//+------------------------------------------------------------------+ -static double CAlglib::CMatrixRCond1(CMatrixComplex &a,const int n) - { -//--- return result - return(CRCond::CMatrixRCond1(a,n)); - } -//+------------------------------------------------------------------+ -//| Estimate of a matrix condition number (infinity-norm). | -//| The algorithm calculates a lower bound of the condition number. | -//| In this case, the algorithm does not return a lower bound of the | -//| condition number, but an inverse number (to avoid an overflow in | -//| case of a singular matrix). | -//| Input parameters: | -//| A - matrix. Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| Result: 1/LowerBound(cond(A)) | -//| NOTE: | -//| if k(A) is very large, then matrix is assumed degenerate, | -//| k(A)=INF, 0.0 is returned in such cases. | -//+------------------------------------------------------------------+ -static double CAlglib::CMatrixRCondInf(CMatrixComplex &a,const int n) - { -//--- return result - return(CRCond::CMatrixRCondInf(a,n)); - } -//+------------------------------------------------------------------+ -//| Estimate of the condition number of a matrix given by its LU | -//| decomposition (1-norm) | -//| The algorithm calculates a lower bound of the condition number. | -//| In this case, the algorithm does not return a lower bound of the | -//| condition number, but an inverse number (to avoid an overflow in | -//| case of a singular matrix). | -//| Input parameters: | -//| LUA - LU decomposition of a matrix in compact form.| -//| Output of the RMatrixLU subroutine. | -//| N - size of matrix A. | -//| Result: 1/LowerBound(cond(A)) | -//| NOTE: | -//| if k(A) is very large, then matrix is assumed degenerate, | -//| k(A)=INF, 0.0 is returned in such cases. | -//+------------------------------------------------------------------+ -static double CAlglib::RMatrixLURCond1(CMatrixDouble &lua,const int n) - { -//--- return result - return(CRCond::RMatrixLURCond1(lua,n)); - } -//+------------------------------------------------------------------+ -//| Estimate of the condition number of a matrix given by its LU | -//| decomposition (infinity norm). | -//| The algorithm calculates a lower bound of the condition number. | -//| In this case, the algorithm does not return a lower bound of the | -//| condition number, but an inverse number (to avoid an overflow in | -//| case of a singular matrix). | -//| Input parameters: | -//| LUA - LU decomposition of a matrix in compact form. | -//| Output of the RMatrixLU subroutine. | -//| N - size of matrix A. | -//| Result: 1/LowerBound(cond(A)) | -//| NOTE: | -//| if k(A) is very large, then matrix is assumed degenerate, | -//| k(A)=INF, 0.0 is returned in such cases. | -//+------------------------------------------------------------------+ -static double CAlglib::RMatrixLURCondInf(CMatrixDouble &lua,const int n) - { -//--- return result - return(CRCond::RMatrixLURCondInf(lua,n)); - } -//+------------------------------------------------------------------+ -//| Condition number estimate of a symmetric positive definite matrix| -//| given by Cholesky decomposition. | -//| The algorithm calculates a lower bound of the condition number. | -//| In this case, the algorithm does not return a lower bound of the | -//| condition number, but an inverse number (to avoid an overflow in | -//| case of a singular matrix). | -//| It should be noted that 1-norm and inf-norm condition numbers of | -//| symmetric matrices are equal, so the algorithm doesn't take into | -//| account the differences between these types of norms. | -//| Input parameters: | -//| CD - Cholesky decomposition of matrix A, | -//| output of SMatrixCholesky subroutine. | -//| N - size of matrix A. | -//| Result: 1/LowerBound(cond(A)) | -//| NOTE: | -//| if k(A) is very large, then matrix is assumed degenerate, | -//| k(A)=INF, 0.0 is returned in such cases. | -//+------------------------------------------------------------------+ -static double CAlglib::SPDMatrixCholeskyRCond(CMatrixDouble &a,const int n, - const bool isupper) - { -//--- return result - return(CRCond::SPDMatrixCholeskyRCond(a,n,isupper)); - } -//+------------------------------------------------------------------+ -//| Condition number estimate of a Hermitian positive definite matrix| -//| given by Cholesky decomposition. | -//| The algorithm calculates a lower bound of the condition number. | -//| In this case, the algorithm does not return a lower bound of the | -//| condition number, but an inverse number (to avoid an overflow in | -//| case of a singular matrix). | -//| It should be noted that 1-norm and inf-norm condition numbers of | -//| symmetric matrices are equal, so the algorithm doesn't take into | -//| account the differences between these types of norms. | -//| Input parameters: | -//| CD - Cholesky decomposition of matrix A, | -//| output of SMatrixCholesky subroutine. | -//| N - size of matrix A. | -//| Result: 1/LowerBound(cond(A)) | -//| NOTE: | -//| if k(A) is very large, then matrix is assumed degenerate, | -//| k(A)=INF, 0.0 is returned in such cases. | -//+------------------------------------------------------------------+ -static double CAlglib::HPDMatrixCholeskyRCond(CMatrixComplex &a,const int n, - const bool isupper) - { -//--- return result - return(CRCond::HPDMatrixCholeskyRCond(a,n,isupper)); - } -//+------------------------------------------------------------------+ -//| Estimate of the condition number of a matrix given by its LU | -//| decomposition (1-norm) | -//| The algorithm calculates a lower bound of the condition number. | -//| In this case, the algorithm does not return a lower bound of the | -//| condition number, but an inverse number (to avoid an overflow in | -//| case of a singular matrix). | -//| Input parameters: | -//| LUA - LU decomposition of a matrix in compact form.| -//| Output of the CMatrixLU subroutine. | -//| N - size of matrix A. | -//| Result: 1/LowerBound(cond(A)) | -//| NOTE: | -//| if k(A) is very large, then matrix is assumed degenerate, | -//| k(A)=INF, 0.0 is returned in such cases. | -//+------------------------------------------------------------------+ -static double CAlglib::CMatrixLURCond1(CMatrixComplex &lua,const int n) - { -//--- return result - return(CRCond::CMatrixLURCond1(lua,n)); - } -//+------------------------------------------------------------------+ -//| Estimate of the condition number of a matrix given by its LU | -//| decomposition (infinity norm). | -//| The algorithm calculates a lower bound of the condition number. | -//| In this case, the algorithm does not return a lower bound of the | -//| condition number, but an inverse number (to avoid an overflow in | -//| case of a singular matrix). | -//| Input parameters: | -//| LUA - LU decomposition of a matrix in compact form. | -//| Output of the CMatrixLU subroutine. | -//| N - size of matrix A. | -//| Result: 1/LowerBound(cond(A)) | -//| NOTE: | -//| if k(A) is very large, then matrix is assumed degenerate, | -//| k(A)=INF, 0.0 is returned in such cases. | -//+------------------------------------------------------------------+ -static double CAlglib::CMatrixLURCondInf(CMatrixComplex &lua,const int n) - { -//--- return result - return(CRCond::CMatrixLURCondInf(lua,n)); - } -//+------------------------------------------------------------------+ -//| Triangular matrix: estimate of a condition number (1-norm) | -//| The algorithm calculates a lower bound of the condition number. | -//| In this case, the algorithm does not return a lower bound of the | -//| condition number, but an inverse number (to avoid an overflow in | -//| case of a singular matrix). | -//| Input parameters: | -//| A - matrix. Array[0..N-1, 0..N-1]. | -//| N - size of A. | -//| IsUpper - True, if the matrix is upper triangular. | -//| IsUnit - True, if the matrix has a unit diagonal. | -//| Result: 1/LowerBound(cond(A)) | -//| NOTE: | -//| if k(A) is very large, then matrix is assumed degenerate, | -//| k(A)=INF, 0.0 is returned in such cases. | -//+------------------------------------------------------------------+ -static double CAlglib::CMatrixTrRCond1(CMatrixComplex &a,const int n, - const bool isupper,const bool isunit) - { -//--- return result - return(CRCond::CMatrixTrRCond1(a,n,isupper,isunit)); - } -//+------------------------------------------------------------------+ -//| Triangular matrix: estimate of a matrix condition number | -//| (infinity-norm). | -//| The algorithm calculates a lower bound of the condition number. | -//| In this case, the algorithm does not return a lower bound of the | -//| condition number, but an inverse number (to avoid an overflow in | -//| case of a singular matrix). | -//| Input parameters: | -//| A - matrix. Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| IsUpper - True, if the matrix is upper triangular. | -//| IsUnit - True, if the matrix has a unit diagonal. | -//| Result: 1/LowerBound(cond(A)) | -//| NOTE: | -//| if k(A) is very large, then matrix is assumed degenerate, | -//| k(A)=INF, 0.0 is returned in such cases. | -//+------------------------------------------------------------------+ -static double CAlglib::CMatrixTrRCondInf(CMatrixComplex &a,const int n, - const bool isupper,const bool isunit) - { -//--- return result - return(CRCond::CMatrixTrRCondInf(a,n,isupper,isunit)); - } -//+------------------------------------------------------------------+ -//| Inversion of a matrix given by its LU decomposition. | -//| INPUT PARAMETERS: | -//| A - LU decomposition of the matrix | -//| (output of RMatrixLU subroutine). | -//| Pivots - table of permutations | -//| (the output of RMatrixLU subroutine). | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| OUTPUT PARAMETERS: | -//| Info - return code: | -//| * -3 A is singular, or VERY close to singular.| -//| it is filled by zeros in such cases. | -//| * 1 task is solved (but matrix A may be | -//| ill-conditioned, check R1/RInf parameters| -//| for condition numbers). | -//| Rep - solver report, see below for more info | -//| A - inverse of matrix A. | -//| Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| SOLVER REPORT | -//| Subroutine sets following fields of the Rep structure: | -//| * R1 reciprocal of condition number: 1/cond(A), 1-norm. | -//| * RInf reciprocal of condition number: 1/cond(A), inf-norm. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixLUInverse(CMatrixDouble &a,int &pivots[], - const int n,int &info, - CMatInvReportShell &rep) - { -//--- initialization - info=0; -//--- function call - CMatInv::RMatrixLUInverse(a,pivots,n,info,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Inversion of a matrix given by its LU decomposition. | -//| INPUT PARAMETERS: | -//| A - LU decomposition of the matrix | -//| (output of RMatrixLU subroutine). | -//| Pivots - table of permutations | -//| (the output of RMatrixLU subroutine). | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| OUTPUT PARAMETERS: | -//| Info - return code: | -//| * -3 A is singular, or VERY close to singular.| -//| it is filled by zeros in such cases. | -//| * 1 task is solved (but matrix A may be | -//| ill-conditioned, check R1/RInf parameters| -//| for condition numbers). | -//| Rep - solver report, see below for more info | -//| A - inverse of matrix A. | -//| Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| SOLVER REPORT | -//| Subroutine sets following fields of the Rep structure: | -//| * R1 reciprocal of condition number: 1/cond(A), 1-norm. | -//| * RInf reciprocal of condition number: 1/cond(A), inf-norm. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixLUInverse(CMatrixDouble &a,int &pivots[], - int &info,CMatInvReportShell &rep) - { -//--- create a variable - int n; -//--- check - if((CAp::Cols(a)!=CAp::Rows(a)) || (CAp::Cols(a)!=CAp::Len(pivots))) - { - Print(__FUNCTION__+": looks like one of arguments has wrong size"); - CAp::exception_happened=true; - return; - } -//--- initialization - info=0; - n=CAp::Cols(a); -//--- function call - CMatInv::RMatrixLUInverse(a,pivots,n,info,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Inversion of a general matrix. | -//| Input parameters: | -//| A - matrix. | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| Output parameters: | -//| Info - return code, same as in RMatrixLUInverse | -//| Rep - solver report, same as in RMatrixLUInverse | -//| A - inverse of matrix A, same as in RMatrixLUInverse | -//| Result: | -//| True, if the matrix is not singular. | -//| False, if the matrix is singular. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixInverse(CMatrixDouble &a,const int n,int &info, - CMatInvReportShell &rep) - { -//--- initialization - info=0; -//--- function call - CMatInv::RMatrixInverse(a,n,info,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Inversion of a general matrix. | -//| Input parameters: | -//| A - matrix. | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| Output parameters: | -//| Info - return code, same as in RMatrixLUInverse | -//| Rep - solver report, same as in RMatrixLUInverse | -//| A - inverse of matrix A, same as in RMatrixLUInverse | -//| Result: | -//| True, if the matrix is not singular. | -//| False, if the matrix is singular. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixInverse(CMatrixDouble &a,int &info, - CMatInvReportShell &rep) - { -//--- create a variable - int n; -//--- check - if((CAp::Cols(a)!=CAp::Rows(a))) - { - Print(__FUNCTION__+": looks like one of arguments has wrong size"); - CAp::exception_happened=true; - return; - } -//--- initialization - info=0; - n=CAp::Cols(a); -//--- function call - CMatInv::RMatrixInverse(a,n,info,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Inversion of a matrix given by its LU decomposition. | -//| INPUT PARAMETERS: | -//| A - LU decomposition of the matrix | -//| (output of CMatrixLU subroutine). | -//| Pivots - table of permutations | -//| (the output of CMatrixLU subroutine). | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| OUTPUT PARAMETERS: | -//| Info - return code, same as in RMatrixLUInverse | -//| Rep - solver report, same as in RMatrixLUInverse | -//| A - inverse of matrix A, same as in RMatrixLUInverse | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixLUInverse(CMatrixComplex &a,int &pivots[], - const int n,int &info, - CMatInvReportShell &rep) - { -//--- initialization - info=0; -//--- function call - CMatInv::CMatrixLUInverse(a,pivots,n,info,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Inversion of a matrix given by its LU decomposition. | -//| INPUT PARAMETERS: | -//| A - LU decomposition of the matrix | -//| (output of CMatrixLU subroutine). | -//| Pivots - table of permutations | -//| (the output of CMatrixLU subroutine). | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| OUTPUT PARAMETERS: | -//| Info - return code, same as in RMatrixLUInverse | -//| Rep - solver report, same as in RMatrixLUInverse | -//| A - inverse of matrix A, same as in RMatrixLUInverse | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixLUInverse(CMatrixComplex &a,int &pivots[], - int &info,CMatInvReportShell &rep) - { -//--- create a variable - int n; -//--- check - if((CAp::Cols(a)!=CAp::Rows(a)) || (CAp::Cols(a)!=CAp::Len(pivots))) - { - Print(__FUNCTION__+": looks like one of arguments has wrong size"); - CAp::exception_happened=true; - return; - } -//--- initialization - info=0; - n=CAp::Cols(a); -//--- function call - CMatInv::CMatrixLUInverse(a,pivots,n,info,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Inversion of a general matrix. | -//| Input parameters: | -//| A - matrix | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| Output parameters: | -//| Info - return code, same as in RMatrixLUInverse | -//| Rep - solver report, same as in RMatrixLUInverse | -//| A - inverse of matrix A, same as in RMatrixLUInverse | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixInverse(CMatrixComplex &a,const int n,int &info, - CMatInvReportShell &rep) - { -//--- initialization - info=0; -//--- function call - CMatInv::CMatrixInverse(a,n,info,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Inversion of a general matrix. | -//| Input parameters: | -//| A - matrix | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| Output parameters: | -//| Info - return code, same as in RMatrixLUInverse | -//| Rep - solver report, same as in RMatrixLUInverse | -//| A - inverse of matrix A, same as in RMatrixLUInverse | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixInverse(CMatrixComplex &a,int &info, - CMatInvReportShell &rep) - { -//--- create a variable - int n; -//--- check - if((CAp::Cols(a)!=CAp::Rows(a))) - { - Print(__FUNCTION__+": looks like one of arguments has wrong size"); - CAp::exception_happened=true; - return; - } -//--- initialization - info=0; - n=CAp::Cols(a); -//--- function call - CMatInv::CMatrixInverse(a,n,info,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Inversion of a symmetric positive definite matrix which is given | -//| by Cholesky decomposition. | -//| Input parameters: | -//| A - Cholesky decomposition of the matrix to be | -//| inverted: A=U?*U or A = L*L'. | -//| Output of SPDMatrixCholesky subroutine. | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| IsUpper - storage type (optional): | -//| * if True, symmetric matrix A is given by its | -//| upper triangle, and the lower triangle isn?t | -//| used/changed by function | -//| * if False, symmetric matrix A is given by its | -//| lower triangle, and the upper triangle isn?t | -//| used/changed by function | -//| * if not given, lower half is used. | -//| Output parameters: | -//| Info - return code, same as in RMatrixLUInverse | -//| Rep - solver report, same as in RMatrixLUInverse | -//| A - inverse of matrix A, same as in RMatrixLUInverse | -//+------------------------------------------------------------------+ -static void CAlglib::SPDMatrixCholeskyInverse(CMatrixDouble &a,const int n, - const bool isupper,int &info, - CMatInvReportShell &rep) - { -//--- initialization - info=0; -//--- function call - CMatInv::SPDMatrixCholeskyInverse(a,n,isupper,info,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Inversion of a symmetric positive definite matrix which is given | -//| by Cholesky decomposition. | -//| Input parameters: | -//| A - Cholesky decomposition of the matrix to be | -//| inverted: A=U?*U or A = L*L'. | -//| Output of SPDMatrixCholesky subroutine. | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| IsUpper - storage type (optional): | -//| * if True, symmetric matrix A is given by its | -//| upper triangle, and the lower triangle isn?t | -//| used/changed by function | -//| * if False, symmetric matrix A is given by its | -//| lower triangle, and the upper triangle isn?t | -//| used/changed by function | -//| * if not given, lower half is used. | -//| Output parameters: | -//| Info - return code, same as in RMatrixLUInverse | -//| Rep - solver report, same as in RMatrixLUInverse | -//| A - inverse of matrix A, same as in RMatrixLUInverse | -//+------------------------------------------------------------------+ -static void CAlglib::SPDMatrixCholeskyInverse(CMatrixDouble &a,int &info, - CMatInvReportShell &rep) - { -//--- create variables - int n; - bool isupper; -//--- check - if((CAp::Cols(a)!=CAp::Rows(a))) - { - Print(__FUNCTION__+": looks like one of arguments has wrong size"); - CAp::exception_happened=true; - return; - } -//--- initialization - info=0; - n=CAp::Cols(a); -//--- initialization - isupper=false; -//--- function call - CMatInv::SPDMatrixCholeskyInverse(a,n,isupper,info,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Inversion of a symmetric positive definite matrix. | -//| Given an upper or lower triangle of a symmetric positive definite| -//| matrix, the algorithm generates matrix A^-1 and saves the upper | -//| or lower triangle depending on the input. | -//| Input parameters: | -//| A - matrix to be inverted (upper or lower triangle). | -//| Array with elements [0..N-1,0..N-1]. | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| IsUpper - storage type (optional): | -//| * if True, symmetric matrix A is given by its | -//| upper triangle, and the lower triangle isn?t | -//| used/changed by function | -//| * if False, symmetric matrix A is given by its | -//| lower triangle, and the upper triangle isn?t | -//| used/changed by function | -//| * if not given, both lower and upper triangles | -//| must be filled. | -//| Output parameters: | -//| Info - return code, same as in RMatrixLUInverse | -//| Rep - solver report, same as in RMatrixLUInverse | -//| A - inverse of matrix A, same as in RMatrixLUInverse | -//+------------------------------------------------------------------+ -static void CAlglib::SPDMatrixInverse(CMatrixDouble &a,const int n, - const bool isupper,int &info, - CMatInvReportShell &rep) - { -//--- initialization - info=0; -//--- function call - CMatInv::SPDMatrixInverse(a,n,isupper,info,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Inversion of a symmetric positive definite matrix. | -//| Given an upper or lower triangle of a symmetric positive definite| -//| matrix, the algorithm generates matrix A^-1 and saves the upper | -//| or lower triangle depending on the input. | -//| Input parameters: | -//| A - matrix to be inverted (upper or lower triangle). | -//| Array with elements [0..N-1,0..N-1]. | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| IsUpper - storage type (optional): | -//| * if True, symmetric matrix A is given by its | -//| upper triangle, and the lower triangle isn?t | -//| used/changed by function | -//| * if False, symmetric matrix A is given by its | -//| lower triangle, and the upper triangle isn?t | -//| used/changed by function | -//| * if not given, both lower and upper triangles | -//| must be filled. | -//| Output parameters: | -//| Info - return code, same as in RMatrixLUInverse | -//| Rep - solver report, same as in RMatrixLUInverse | -//| A - inverse of matrix A, same as in RMatrixLUInverse | -//+------------------------------------------------------------------+ -static void CAlglib::SPDMatrixInverse(CMatrixDouble &a,int &info, - CMatInvReportShell &rep) - { -//--- create variables - int n; - bool isupper; -//--- check - if((CAp::Cols(a)!=CAp::Rows(a))) - { - Print(__FUNCTION__+": looks like one of arguments has wrong size"); - CAp::exception_happened=true; - return; - } -//--- check - if(!CAp::IsSymmetric(a)) - { - Print(__FUNCTION__+": 'a' parameter is not symmetric matrix"); - CAp::exception_happened=true; - return; - } -//--- initialization - info=0; - n=CAp::Cols(a); - isupper=false; -//--- function call - CMatInv::SPDMatrixInverse(a,n,isupper,info,rep.GetInnerObj()); -//--- check - if(!CAp::ForceSymmetric(a)) - { - Print(__FUNCTION__+": Internal error while forcing symmetricity of 'a' parameter"); - CAp::exception_happened=true; - return; - } -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Inversion of a Hermitian positive definite matrix which is given | -//| by Cholesky decomposition. | -//| Input parameters: | -//| A - Cholesky decomposition of the matrix to be | -//| inverted: A=U?*U or A = L*L'. | -//| Output of HPDMatrixCholesky subroutine. | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| IsUpper - storage type (optional): | -//| * if True, symmetric matrix A is given by its | -//| upper triangle, and the lower triangle isn?t | -//| used/changed by function | -//| * if False, symmetric matrix A is given by its | -//| lower triangle, and the upper triangle isn?t | -//| used/changed by function | -//| * if not given, lower half is used. | -//| Output parameters: | -//| Info - return code, same as in RMatrixLUInverse | -//| Rep - solver report, same as in RMatrixLUInverse | -//| A - inverse of matrix A, same as in RMatrixLUInverse | -//+------------------------------------------------------------------+ -static void CAlglib::HPDMatrixCholeskyInverse(CMatrixComplex &a,const int n, - const bool isupper,int &info, - CMatInvReportShell &rep) - { -//--- initialization - info=0; -//--- function call - CMatInv::HPDMatrixCholeskyInverse(a,n,isupper,info,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Inversion of a Hermitian positive definite matrix which is given | -//| by Cholesky decomposition. | -//| Input parameters: | -//| A - Cholesky decomposition of the matrix to be | -//| inverted: A=U?*U or A = L*L'. | -//| Output of HPDMatrixCholesky subroutine. | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| IsUpper - storage type (optional): | -//| * if True, symmetric matrix A is given by its | -//| upper triangle, and the lower triangle isn?t | -//| used/changed by function | -//| * if False, symmetric matrix A is given by its | -//| lower triangle, and the upper triangle isn?t | -//| used/changed by function | -//| * if not given, lower half is used. | -//| Output parameters: | -//| Info - return code, same as in RMatrixLUInverse | -//| Rep - solver report, same as in RMatrixLUInverse | -//| A - inverse of matrix A, same as in RMatrixLUInverse | -//+------------------------------------------------------------------+ -static void CAlglib::HPDMatrixCholeskyInverse(CMatrixComplex &a,int &info, - CMatInvReportShell &rep) - { -//--- create variables - int n; - bool isupper; -//--- check - if((CAp::Cols(a)!=CAp::Rows(a))) - { - Print(__FUNCTION__+": looks like one of arguments has wrong size"); - CAp::exception_happened=true; - return; - } -//--- initialization - info=0; - n=CAp::Cols(a); - isupper=false; -//--- function call - CMatInv::HPDMatrixCholeskyInverse(a,n,isupper,info,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Inversion of a Hermitian positive definite matrix. | -//| Given an upper or lower triangle of a Hermitian positive definite| -//| matrix, the algorithm generates matrix A^-1 and saves the upper | -//| or lower triangle depending on the input. | -//| Input parameters: | -//| A - matrix to be inverted (upper or lower triangle). | -//| Array with elements [0..N-1,0..N-1]. | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| IsUpper - storage type (optional): | -//| * if True, symmetric matrix A is given by its | -//| upper triangle, and the lower triangle isn?t | -//| used/changed by function | -//| * if False, symmetric matrix A is given by its | -//| lower triangle, and the upper triangle isn?t | -//| used/changed by function | -//| * if not given, both lower and upper triangles | -//| must be filled. | -//| Output parameters: | -//| Info - return code, same as in RMatrixLUInverse | -//| Rep - solver report, same as in RMatrixLUInverse | -//| A - inverse of matrix A, same as in RMatrixLUInverse | -//+------------------------------------------------------------------+ -static void CAlglib::HPDMatrixInverse(CMatrixComplex &a,const int n, - const bool isupper,int &info, - CMatInvReportShell &rep) - { -//--- initialization - info=0; -//--- function call - CMatInv::HPDMatrixInverse(a,n,isupper,info,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Inversion of a Hermitian positive definite matrix. | -//| Given an upper or lower triangle of a Hermitian positive definite| -//| matrix, the algorithm generates matrix A^-1 and saves the upper | -//| or lower triangle depending on the input. | -//| Input parameters: | -//| A - matrix to be inverted (upper or lower triangle). | -//| Array with elements [0..N-1,0..N-1]. | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| IsUpper - storage type (optional): | -//| * if True, symmetric matrix A is given by its | -//| upper triangle, and the lower triangle isn?t | -//| used/changed by function | -//| * if False, symmetric matrix A is given by its | -//| lower triangle, and the upper triangle isn?t | -//| used/changed by function | -//| * if not given, both lower and upper triangles | -//| must be filled. | -//| Output parameters: | -//| Info - return code, same as in RMatrixLUInverse | -//| Rep - solver report, same as in RMatrixLUInverse | -//| A - inverse of matrix A, same as in RMatrixLUInverse | -//+------------------------------------------------------------------+ -static void CAlglib::HPDMatrixInverse(CMatrixComplex &a,int &info, - CMatInvReportShell &rep) - { -//--- create variables - int n; - bool isupper; -//--- check - if((CAp::Cols(a)!=CAp::Rows(a))) - { - Print(__FUNCTION__+": looks like one of arguments has wrong size"); - CAp::exception_happened=true; - return; - } -//--- check - if(!CAp::IsHermitian(a)) - { - Print(__FUNCTION__+": 'a' parameter is not Hermitian matrix"); - CAp::exception_happened=true; - return; - } -//--- initialization - info=0; - n=CAp::Cols(a); - isupper=false; -//--- function call - CMatInv::HPDMatrixInverse(a,n,isupper,info,rep.GetInnerObj()); -//--- check - if(!CAp::ForceHermitian(a)) - { - Print(__FUNCTION__+": Internal error while forcing Hermitian properties of 'a' parameter"); - CAp::exception_happened=true; - return; - } -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Triangular matrix inverse (real) | -//| The subroutine inverts the following types of matrices: | -//| * upper triangular | -//| * upper triangular with unit diagonal | -//| * lower triangular | -//| * lower triangular with unit diagonal | -//| In case of an upper (lower) triangular matrix, the inverse matrix| -//| will also be upper (lower) triangular, and after the end of the | -//| algorithm, the inverse matrix replaces the source matrix. The | -//| elements below (above) the main diagonal are not changed by the | -//| algorithm. | -//| If the matrix has a unit diagonal, the inverse matrix also has a | -//| unit diagonal, and the diagonal elements are not passed to the | -//| algorithm. | -//| Input parameters: | -//| A - matrix, array[0..N-1, 0..N-1]. | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| IsUpper - True, if the matrix is upper triangular. | -//| IsUnit - diagonal type (optional): | -//| * if True, matrix has unit diagonal (a[i,i] are | -//| NOT used) | -//| * if False, matrix diagonal is arbitrary | -//| * if not given, False is assumed | -//| Output parameters: | -//| Info - same as for RMatrixLUInverse | -//| Rep - same as for RMatrixLUInverse | -//| A - same as for RMatrixLUInverse. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixTrInverse(CMatrixDouble &a,const int n, - const bool isupper,const bool isunit, - int &info,CMatInvReportShell &rep) - { -//--- initialization - info=0; -//--- function call - CMatInv::RMatrixTrInverse(a,n,isupper,isunit,info,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Triangular matrix inverse (real) | -//| The subroutine inverts the following types of matrices: | -//| * upper triangular | -//| * upper triangular with unit diagonal | -//| * lower triangular | -//| * lower triangular with unit diagonal | -//| In case of an upper (lower) triangular matrix, the inverse matrix| -//| will also be upper (lower) triangular, and after the end of the | -//| algorithm, the inverse matrix replaces the source matrix. The | -//| elements below (above) the main diagonal are not changed by the | -//| algorithm. | -//| If the matrix has a unit diagonal, the inverse matrix also has a | -//| unit diagonal, and the diagonal elements are not passed to the | -//| algorithm. | -//| Input parameters: | -//| A - matrix, array[0..N-1, 0..N-1]. | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| IsUpper - True, if the matrix is upper triangular. | -//| IsUnit - diagonal type (optional): | -//| * if True, matrix has unit diagonal (a[i,i] are | -//| NOT used) | -//| * if False, matrix diagonal is arbitrary | -//| * if not given, False is assumed | -//| Output parameters: | -//| Info - same as for RMatrixLUInverse | -//| Rep - same as for RMatrixLUInverse | -//| A - same as for RMatrixLUInverse. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixTrInverse(CMatrixDouble &a,const bool isupper, - int &info,CMatInvReportShell &rep) - { -//--- create variables - int n; - bool isunit; -//--- check - if((CAp::Cols(a)!=CAp::Rows(a))) - { - Print(__FUNCTION__+": looks like one of arguments has wrong size"); - CAp::exception_happened=true; - return; - } -//--- initialization - info=0; - n=CAp::Cols(a); - isunit=false; -//--- function call - CMatInv::RMatrixTrInverse(a,n,isupper,isunit,info,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Triangular matrix inverse (complex) | -//| The subroutine inverts the following types of matrices: | -//| * upper triangular | -//| * upper triangular with unit diagonal | -//| * lower triangular | -//| * lower triangular with unit diagonal | -//| In case of an upper (lower) triangular matrix, the inverse matrix| -//| will also be upper (lower) triangular, and after the end of the | -//| algorithm, the inverse matrix replaces the source matrix. The | -//| elements below (above) the main diagonal are not changed by the | -//| algorithm. | -//| If the matrix has a unit diagonal, the inverse matrix also has a | -//| unit diagonal, and the diagonal elements are not passed to the | -//| algorithm. | -//| Input parameters: | -//| A - matrix, array[0..N-1, 0..N-1]. | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| IsUpper - True, if the matrix is upper triangular. | -//| IsUnit - diagonal type (optional): | -//| * if True, matrix has unit diagonal (a[i,i] are | -//| NOT used) | -//| * if False, matrix diagonal is arbitrary | -//| * if not given, False is assumed | -//| Output parameters: | -//| Info - same as for RMatrixLUInverse | -//| Rep - same as for RMatrixLUInverse | -//| A - same as for RMatrixLUInverse. | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixTrInverse(CMatrixComplex &a,const int n, - const bool isupper,const bool isunit, - int &info,CMatInvReportShell &rep) - { -//--- initialization - info=0; -//--- function call - CMatInv::CMatrixTrInverse(a,n,isupper,isunit,info,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Triangular matrix inverse (complex) | -//| The subroutine inverts the following types of matrices: | -//| * upper triangular | -//| * upper triangular with unit diagonal | -//| * lower triangular | -//| * lower triangular with unit diagonal | -//| In case of an upper (lower) triangular matrix, the inverse matrix| -//| will also be upper (lower) triangular, and after the end of the | -//| algorithm, the inverse matrix replaces the source matrix. The | -//| elements below (above) the main diagonal are not changed by the | -//| algorithm. | -//| If the matrix has a unit diagonal, the inverse matrix also has a | -//| unit diagonal, and the diagonal elements are not passed to the | -//| algorithm. | -//| Input parameters: | -//| A - matrix, array[0..N-1, 0..N-1]. | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| IsUpper - True, if the matrix is upper triangular. | -//| IsUnit - diagonal type (optional): | -//| * if True, matrix has unit diagonal (a[i,i] are | -//| NOT used) | -//| * if False, matrix diagonal is arbitrary | -//| * if not given, False is assumed | -//| Output parameters: | -//| Info - same as for RMatrixLUInverse | -//| Rep - same as for RMatrixLUInverse | -//| A - same as for RMatrixLUInverse. | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixTrInverse(CMatrixComplex &a,const bool isupper, - int &info,CMatInvReportShell &rep) - { -//--- create variables - int n; - bool isunit; -//--- check - if((CAp::Cols(a)!=CAp::Rows(a))) - { - Print(__FUNCTION__+": looks like one of arguments has wrong size"); - CAp::exception_happened=true; - return; - } -//--- initialization - info=0; - n=CAp::Cols(a); - isunit=false; -//--- function call - CMatInv::CMatrixTrInverse(a,n,isupper,isunit,info,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Singular value decomposition of a bidiagonal matrix (extended | -//| algorithm) | -//| The algorithm performs the singular value decomposition of a | -//| bidiagonal matrix B (upper or lower) representing it as | -//| B = Q*S*P^T, where Q and P - orthogonal matrices, S - diagonal | -//| matrix with non-negative elements on the main diagonal, in | -//| descending order. | -//| The algorithm finds singular values. In addition, the algorithm | -//| can calculate matrices Q and P (more precisely, not the matrices,| -//| but their product with given matrices U and VT - U*Q and | -//| (P^T)*VT)). Of course, matrices U and VT can be of any type, | -//| including identity. Furthermore, the algorithm can calculate Q'*C| -//| (this product is calculated more effectively than U*Q, because | -//| this calculation operates with rows instead of matrix columns). | -//| The feature of the algorithm is its ability to find all singular | -//| values including those which are arbitrarily close to 0 with | -//| relative accuracy close to machine precision. If the parameter | -//| IsFractionalAccuracyRequired is set to True, all singular values | -//| will have high relative accuracy close to machine precision. If | -//| the parameter is set to False, only the biggest singular value | -//| will have relative accuracy close to machine precision. The | -//| absolute error of other singular values is equal to the absolute | -//| error of the biggest singular value. | -//| Input parameters: | -//| D - main diagonal of matrix B. | -//| Array whose index ranges within [0..N-1]. | -//| E - superdiagonal (or subdiagonal) of matrix B. | -//| Array whose index ranges within [0..N-2]. | -//| N - size of matrix B. | -//| IsUpper - True, if the matrix is upper bidiagonal. | -//| IsFractionalAccuracyRequired - | -//| accuracy to search singular values with. | -//| U - matrix to be multiplied by Q. | -//| Array whose indexes range within | -//| [0..NRU-1, 0..N-1]. | -//| The matrix can be bigger, in that case only the | -//| submatrix [0..NRU-1, 0..N-1] will be multiplied | -//| by Q. | -//| NRU - number of rows in matrix U. | -//| C - matrix to be multiplied by Q'. | -//| Array whose indexes range within | -//| [0..N-1, 0..NCC-1]. | -//| The matrix can be bigger, in that case only the | -//| submatrix [0..N-1, 0..NCC-1] will be multiplied | -//| by Q'. | -//| NCC - number of columns in matrix C. | -//| VT - matrix to be multiplied by P^T. | -//| Array whose indexes range within | -//| [0..N-1, 0..NCVT-1]. | -//| The matrix can be bigger, in that case only the | -//| submatrix [0..N-1, 0..NCVT-1] will be multiplied | -//| by P^T. | -//| NCVT - number of columns in matrix VT. | -//| Output parameters: | -//| D - singular values of matrix B in descending order. | -//| U - if NRU>0, contains matrix U*Q. | -//| VT - if NCVT>0, contains matrix (P^T)*VT. | -//| C - if NCC>0, contains matrix Q'*C. | -//| Result: | -//| True, if the algorithm has converged. | -//| False, if the algorithm hasn't converged (rare case). | -//| Additional information: | -//| The type of convergence is controlled by the internal | -//| parameter TOL. If the parameter is greater than 0, the | -//| singular values will have relative accuracy TOL. If TOL<0, | -//| the singular values will have absolute accuracy | -//| ABS(TOL)*norm(B). By default, |TOL| falls within the range of| -//| 10*Epsilon and 100*Epsilon, where Epsilon is the machine | -//| precision. It is not recommended to use TOL less than | -//| 10*Epsilon since this will considerably slow down the | -//| algorithm and may not lead to error decreasing. | -//| History: | -//| * 31 March, 2007. | -//| changed MAXITR from 6 to 12. | -//| -- LAPACK routine (version 3.0) -- | -//| Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., | -//| Courant Institute, Argonne National Lab, and Rice University| -//| October 31, 1999. | -//+------------------------------------------------------------------+ -static bool CAlglib::RMatrixBdSVD(double &d[],double &e[],const int n, - const bool isupper, - bool isfractionalaccuracyrequired, - CMatrixDouble &u,const int nru, - CMatrixDouble &c,const int ncc, - CMatrixDouble &vt,const int ncvt) - { -//--- return result - return(CBdSingValueDecompose::RMatrixBdSVD(d,e,n,isupper,isfractionalaccuracyrequired,u,nru,c,ncc,vt,ncvt)); - } -//+------------------------------------------------------------------+ -//| Singular value decomposition of a rectangular matrix. | -//| The algorithm calculates the singular value decomposition of a | -//| matrix of size MxN: A = U * S * V^T | -//| The algorithm finds the singular values and, optionally, matrices| -//| U and V^T. The algorithm can find both first min(M,N) columns of | -//| matrix U and rows of matrix V^T (singular vectors), and matrices | -//| U and V^T wholly (of sizes MxM and NxN respectively). | -//| Take into account that the subroutine does not return matrix V | -//| but V^T. | -//| Input parameters: | -//| A - matrix to be decomposed. | -//| Array whose indexes range within | -//| [0..M-1, 0..N-1]. | -//| M - number of rows in matrix A. | -//| N - number of columns in matrix A. | -//| UNeeded - 0, 1 or 2. See the description of the | -//| parameter U. | -//| VTNeeded - 0, 1 or 2. See the description of the | -//| parameter VT. | -//| AdditionalMemory - | -//| If the parameter: | -//| * equals 0, the algorithm doesn?t use | -//| additional memory (lower requirements, | -//| lower performance). | -//| * equals 1, the algorithm uses additional | -//| memory of size min(M,N)*min(M,N) of real | -//| numbers. It often speeds up the algorithm.| -//| * equals 2, the algorithm uses additional | -//| memory of size M*min(M,N) of real numbers.| -//| It allows to get a maximum performance. | -//| The recommended value of the parameter is 2. | -//| Output parameters: | -//| W - contains singular values in descending order.| -//| U - if UNeeded=0, U isn't changed, the left | -//| singular vectors are not calculated. | -//| if Uneeded=1, U contains left singular | -//| vectors (first min(M,N) columns of matrix U).| -//| Array whose indexes range within | -//| [0..M-1, 0..Min(M,N)-1]. if UNeeded=2, U | -//| contains matrix U wholly. Array whose indexes| -//| range within [0..M-1, 0..M-1]. | -//| VT - if VTNeeded=0, VT isn?t changed, the right | -//| singular vectors are not calculated. | -//| if VTNeeded=1, VT contains right singular | -//| vectors (first min(M,N) rows of matrix V^T). | -//| Array whose indexes range within | -//| [0..min(M,N)-1, 0..N-1]. if VTNeeded=2, VT | -//| contains matrix V^T wholly. Array whose | -//| indexes range within [0..N-1, 0..N-1]. | -//+------------------------------------------------------------------+ -static bool CAlglib::RMatrixSVD(CMatrixDouble &a,const int m,const int n, - const int uneeded,const int vtneeded, - const int additionalmemory,double &w[], - CMatrixDouble &u,CMatrixDouble &vt) - { -//--- return result - return(CSingValueDecompose::RMatrixSVD(a,m,n,uneeded,vtneeded,additionalmemory,w,u,vt)); - } -//+------------------------------------------------------------------+ -//| Determinant calculation of the matrix given by its LU | -//| decomposition. | -//| Input parameters: | -//| A - LU decomposition of the matrix (output of | -//| RMatrixLU subroutine). | -//| Pivots - table of permutations which were made during | -//| the LU decomposition. | -//| Output of RMatrixLU subroutine. | -//| N - (optional) size of matrix A: | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, automatically determined from | -//| matrix size (A must be square matrix) | -//| Result: matrix determinant. | -//+------------------------------------------------------------------+ -static double CAlglib::RMatrixLUDet(CMatrixDouble &a,int &pivots[],const int n) - { -//--- return result - return(CMatDet::RMatrixLUDet(a,pivots,n)); - } -//+------------------------------------------------------------------+ -//| Determinant calculation of the matrix given by its LU | -//| decomposition. | -//| Input parameters: | -//| A - LU decomposition of the matrix (output of | -//| RMatrixLU subroutine). | -//| Pivots - table of permutations which were made during | -//| the LU decomposition. | -//| Output of RMatrixLU subroutine. | -//| N - (optional) size of matrix A: | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, automatically determined from | -//| matrix size (A must be square matrix) | -//| Result: matrix determinant. | -//+------------------------------------------------------------------+ -static double CAlglib::RMatrixLUDet(CMatrixDouble &a,int &pivots[]) - { -//--- create a variable - int n; -//--- check - if((CAp::Rows(a)!=CAp::Cols(a)) || (CAp::Rows(a)!=CAp::Len(pivots))) - { - Print(__FUNCTION__+": looks like one of arguments has wrong size"); - CAp::exception_happened=true; - return(EMPTY_VALUE); - } -//--- initialization - n=CAp::Rows(a); -//--- return result - return(CMatDet::RMatrixLUDet(a,pivots,n)); - } -//+------------------------------------------------------------------+ -//| Calculation of the determinant of a general matrix | -//| Input parameters: | -//| A - matrix, array[0..N-1, 0..N-1] | -//| N - (optional) size of matrix A: | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, automatically determined from | -//| matrix size (A must be square matrix) | -//| Result: determinant of matrix A. | -//+------------------------------------------------------------------+ -static double CAlglib::RMatrixDet(CMatrixDouble &a,const int n) - { -//--- return result - return(CMatDet::RMatrixDet(a,n)); - } -//+------------------------------------------------------------------+ -//| Calculation of the determinant of a general matrix | -//| Input parameters: | -//| A - matrix, array[0..N-1, 0..N-1] | -//| N - (optional) size of matrix A: | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, automatically determined from | -//| matrix size (A must be square matrix) | -//| Result: determinant of matrix A. | -//+------------------------------------------------------------------+ -static double CAlglib::RMatrixDet(CMatrixDouble &a) - { -//--- create a variable - int n; -//--- check - if((CAp::Rows(a)!=CAp::Cols(a))) - { - Print(__FUNCTION__+": looks like one of arguments has wrong size"); - CAp::exception_happened=true; - return(EMPTY_VALUE); - } -//--- initialization - n=CAp::Rows(a); -//--- return result - return(CMatDet::RMatrixDet(a,n)); - } -//+------------------------------------------------------------------+ -//| Determinant calculation of the matrix given by its LU | -//| decomposition. | -//| Input parameters: | -//| A - LU decomposition of the matrix (output of | -//| RMatrixLU subroutine). | -//| Pivots - table of permutations which were made during | -//| the LU decomposition. | -//| Output of RMatrixLU subroutine. | -//| N - (optional) size of matrix A: | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, automatically determined from | -//| matrix size (A must be square matrix) | -//| Result: matrix determinant. | -//+------------------------------------------------------------------+ -static al_complex CAlglib::CMatrixLUDet(CMatrixComplex &a,int &pivots[], - const int n) - { -//--- return result - return(CMatDet::CMatrixLUDet(a,pivots,n)); - } -//+------------------------------------------------------------------+ -//| Determinant calculation of the matrix given by its LU | -//| decomposition. | -//| Input parameters: | -//| A - LU decomposition of the matrix (output of | -//| RMatrixLU subroutine). | -//| Pivots - table of permutations which were made during | -//| the LU decomposition. | -//| Output of RMatrixLU subroutine. | -//| N - (optional) size of matrix A: | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, automatically determined from | -//| matrix size (A must be square matrix) | -//| Result: matrix determinant. | -//+------------------------------------------------------------------+ -static al_complex CAlglib::CMatrixLUDet(CMatrixComplex &a,int &pivots[]) - { -//--- create a variable - int n; -//--- check - if((CAp::Rows(a)!=CAp::Cols(a)) || (CAp::Rows(a)!=CAp::Len(pivots))) - { - Print(__FUNCTION__+": looks like one of arguments has wrong size"); - CAp::exception_happened=true; - return(EMPTY_VALUE); - } -//--- initialization - n=CAp::Rows(a); -//--- return result - return(CMatDet::CMatrixLUDet(a,pivots,n)); - } -//+------------------------------------------------------------------+ -//| Calculation of the determinant of a general matrix | -//| Input parameters: | -//| A - matrix, array[0..N-1, 0..N-1] | -//| N - (optional) size of matrix A: | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, automatically determined from | -//| matrix size (A must be square matrix) | -//| Result: determinant of matrix A. | -//+------------------------------------------------------------------+ -static al_complex CAlglib::CMatrixDet(CMatrixComplex &a,const int n) - { -//--- return result - return(CMatDet::CMatrixDet(a,n)); - } -//+------------------------------------------------------------------+ -//| Calculation of the determinant of a general matrix | -//| Input parameters: | -//| A - matrix, array[0..N-1, 0..N-1] | -//| N - (optional) size of matrix A: | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, automatically determined from | -//| matrix size (A must be square matrix) | -//| Result: determinant of matrix A. | -//+------------------------------------------------------------------+ -static al_complex CAlglib::CMatrixDet(CMatrixComplex &a) - { -//--- create a variable - int n; -//--- check - if((CAp::Rows(a)!=CAp::Cols(a))) - { - Print(__FUNCTION__+": looks like one of arguments has wrong size"); - CAp::exception_happened=true; - return(EMPTY_VALUE); - } -//--- initialization - n=CAp::Rows(a); -//--- return result - return(CMatDet::CMatrixDet(a,n)); - } -//+------------------------------------------------------------------+ -//| Determinant calculation of the matrix given by the Cholesky | -//| decomposition. | -//| Input parameters: | -//| A - Cholesky decomposition, | -//| output of SMatrixCholesky subroutine. | -//| N - (optional) size of matrix A: | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, automatically determined from | -//| matrix size (A must be square matrix) | -//| As the determinant is equal to the product of squares of diagonal| -//| elements, it?s not necessary to specify which triangle - lower | -//| or upper - the matrix is stored in. | -//| Result: | -//| matrix determinant. | -//+------------------------------------------------------------------+ -static double CAlglib::SPDMatrixCholeskyDet(CMatrixDouble &a,const int n) - { -//--- return result - return(CMatDet::SPDMatrixCholeskyDet(a,n)); - } -//+------------------------------------------------------------------+ -//| Determinant calculation of the matrix given by the Cholesky | -//| decomposition. | -//| Input parameters: | -//| A - Cholesky decomposition, | -//| output of SMatrixCholesky subroutine. | -//| N - (optional) size of matrix A: | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, automatically determined from | -//| matrix size (A must be square matrix) | -//| As the determinant is equal to the product of squares of diagonal| -//| elements, it?s not necessary to specify which triangle - lower | -//| or upper - the matrix is stored in. | -//| Result: | -//| matrix determinant. | -//+------------------------------------------------------------------+ -static double CAlglib::SPDMatrixCholeskyDet(CMatrixDouble &a) - { -//--- create a variable - int n; -//--- check - if((CAp::Rows(a)!=CAp::Cols(a))) - { - Print(__FUNCTION__+": looks like one of arguments has wrong size"); - CAp::exception_happened=true; - return(EMPTY_VALUE); - } -//--- initialization - n=CAp::Rows(a); -//--- return result - return(CMatDet::SPDMatrixCholeskyDet(a,n)); - } -//+------------------------------------------------------------------+ -//| Determinant calculation of the symmetric positive definite | -//| matrix. | -//| Input parameters: | -//| A - matrix. Array with elements [0..N-1, 0..N-1]. | -//| N - (optional) size of matrix A: | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, automatically determined from | -//| matrix size (A must be square matrix) | -//| IsUpper - (optional) storage type: | -//| * if True, symmetric matrix A is given by its | -//| upper triangle, and the lower triangle isn?t | -//| used/changed by function | -//| * if False, symmetric matrix A is given by its | -//| lower triangle, and the upper triangle isn?t | -//| used/changed by function | -//| * if not given, both lower and upper triangles | -//| must be filled. | -//| Result: | -//| determinant of matrix A. | -//| If matrix A is not positive definite, exception is thrown. | -//+------------------------------------------------------------------+ -static double CAlglib::SPDMatrixDet(CMatrixDouble &a,const int n, - const bool isupper) - { -//--- return result - return(CMatDet::SPDMatrixDet(a,n,isupper)); - } -//+------------------------------------------------------------------+ -//| Determinant calculation of the symmetric positive definite | -//| matrix. | -//| Input parameters: | -//| A - matrix. Array with elements [0..N-1, 0..N-1]. | -//| N - (optional) size of matrix A: | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, automatically determined from | -//| matrix size (A must be square matrix) | -//| IsUpper - (optional) storage type: | -//| * if True, symmetric matrix A is given by its | -//| upper triangle, and the lower triangle isn?t | -//| used/changed by function | -//| * if False, symmetric matrix A is given by its | -//| lower triangle, and the upper triangle isn?t | -//| used/changed by function | -//| * if not given, both lower and upper triangles | -//| must be filled. | -//| Result: | -//| determinant of matrix A. | -//| If matrix A is not positive definite, exception is thrown. | -//+------------------------------------------------------------------+ -static double CAlglib::SPDMatrixDet(CMatrixDouble &a) - { -//--- create a variable - int n; - bool isupper; -//--- check - if((CAp::Rows(a)!=CAp::Cols(a))) - { - Print(__FUNCTION__+": looks like one of arguments has wrong size"); - CAp::exception_happened=true; - return(EMPTY_VALUE); - } -//--- check - if(!CAp::IsSymmetric(a)) - { - Print(__FUNCTION__+": 'a' parameter is not symmetric matrix"); - CAp::exception_happened=true; - return(EMPTY_VALUE); - } -//--- initialization - n=CAp::Rows(a); - isupper=false; -//--- return result - return(CMatDet::SPDMatrixDet(a,n,isupper)); - } -//+------------------------------------------------------------------+ -//| Algorithm for solving the following generalized symmetric | -//| positive-definite eigenproblem: | -//| A*x = lambda*B*x (1) or | -//| A*B*x = lambda*x (2) or | -//| B*A*x = lambda*x (3). | -//| where A is a symmetric matrix, B - symmetric positive-definite | -//| matrix. The problem is solved by reducing it to an ordinary | -//| symmetric eigenvalue problem. | -//| Input parameters: | -//| A - symmetric matrix which is given by its upper | -//| or lower triangular part. | -//| Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| N - size of matrices A and B. | -//| IsUpperA - storage format of matrix A. | -//| B - symmetric positive-definite matrix which is | -//| given by its upper or lower triangular part. | -//| Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| IsUpperB - storage format of matrix B. | -//| ZNeeded - if ZNeeded is equal to: | -//| * 0, the eigenvectors are not returned; | -//| * 1, the eigenvectors are returned. | -//| ProblemType - if ProblemType is equal to: | -//| * 1, the following problem is solved: | -//| A*x = lambda*B*x; | -//| * 2, the following problem is solved: | -//| A*B*x = lambda*x; | -//| * 3, the following problem is solved: | -//| B*A*x = lambda*x. | -//| Output parameters: | -//| D - eigenvalues in ascending order. | -//| Array whose index ranges within [0..N-1]. | -//| Z - if ZNeeded is equal to: | -//| * 0, Z hasn?t changed; | -//| * 1, Z contains eigenvectors. | -//| Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| The eigenvectors are stored in matrix | -//| columns. It should be noted that the | -//| eigenvectors in such problems do not form an | -//| orthogonal system. | -//| Result: | -//| True, if the problem was solved successfully. | -//| False, if the error occurred during the Cholesky | -//| decomposition of matrix B (the matrix isn?t | -//| positive-definite) or during the work of the iterative | -//| algorithm for solving the symmetric eigenproblem. | -//| See also the GeneralizedSymmetricDefiniteEVDReduce subroutine. | -//+------------------------------------------------------------------+ -static bool CAlglib::SMatrixGEVD(CMatrixDouble &a,const int n,const bool isuppera, - CMatrixDouble &b,const bool isupperb, - const int zneeded,const int problemtype, - double &d[],CMatrixDouble &z) - { -//--- return result - return(CSpdGEVD::SMatrixGEVD(a,n,isuppera,b,isupperb,zneeded,problemtype,d,z)); - } -//+------------------------------------------------------------------+ -//| Algorithm for reduction of the following generalized symmetric | -//| positive- definite eigenvalue problem: | -//| A*x = lambda*B*x (1) or | -//| A*B*x = lambda*x (2) or | -//| B*A*x = lambda*x (3) | -//| to the symmetric eigenvalues problem C*y = lambda*y (eigenvalues | -//| of this and the given problems are the same, and the eigenvectors| -//| of the given problem could be obtained by multiplying the | -//| obtained eigenvectors by the transformation matrix x = R*y). | -//| Here A is a symmetric matrix, B - symmetric positive-definite | -//| matrix. | -//| Input parameters: | -//| A - symmetric matrix which is given by its upper | -//| or lower triangular part. | -//| Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| N - size of matrices A and B. | -//| IsUpperA - storage format of matrix A. | -//| B - symmetric positive-definite matrix which is | -//| given by its upper or lower triangular part. | -//| Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| IsUpperB - storage format of matrix B. | -//| ProblemType - if ProblemType is equal to: | -//| * 1, the following problem is solved: | -//| A*x = lambda*B*x; | -//| * 2, the following problem is solved: | -//| A*B*x = lambda*x; | -//| * 3, the following problem is solved: | -//| B*A*x = lambda*x. | -//| Output parameters: | -//| A - symmetric matrix which is given by its upper | -//| or lower triangle depending on IsUpperA. | -//| Contains matrix C. Array whose indexes range | -//| within [0..N-1, 0..N-1]. | -//| R - upper triangular or low triangular | -//| transformation matrix which is used to obtain| -//| the eigenvectors of a given problem as the | -//| product of eigenvectors of C (from the right)| -//| and matrix R (from the left). If the matrix | -//| is upper triangular, the elements below the | -//| main diagonal are equal to 0 (and vice versa)| -//| Thus, we can perform the multiplication | -//| without taking into account the internal | -//| structure (which is an easier though less | -//| effective way). Array whose indexes range | -//| within [0..N-1, 0..N-1]. | -//| IsUpperR - type of matrix R (upper or lower triangular).| -//| Result: | -//| True, if the problem was reduced successfully. | -//| False, if the error occurred during the Cholesky | -//| decomposition of matrix B (the matrix is not | -//| positive-definite). | -//+------------------------------------------------------------------+ -static bool CAlglib::SMatrixGEVDReduce(CMatrixDouble &a,const int n, - const bool isuppera,CMatrixDouble &b, - const bool isupperb,const int problemtype, - CMatrixDouble &r,bool &isupperr) - { -//--- initialization - isupperr=false; -//--- return result - return(CSpdGEVD::SMatrixGEVDReduce(a,n,isuppera,b,isupperb,problemtype,r,isupperr)); - } -//+------------------------------------------------------------------+ -//| Inverse matrix update by the Sherman-Morrison formula | -//| The algorithm updates matrix A^-1 when adding a number to an | -//| element of matrix A. | -//| Input parameters: | -//| InvA - inverse of matrix A. | -//| Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| UpdRow - row where the element to be updated is stored. | -//| UpdColumn - column where the element to be updated is stored.| -//| UpdVal - a number to be added to the element. | -//| Output parameters: | -//| InvA - inverse of modified matrix A. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixInvUpdateSimple(CMatrixDouble &inva,const int n, - const int updrow,const int updcolumn, - const double updval) - { -//--- get result - CInverseUpdate::RMatrixInvUpdateSimple(inva,n,updrow,updcolumn,updval); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Inverse matrix update by the Sherman-Morrison formula | -//| The algorithm updates matrix A^-1 when adding a vector to a row | -//| of matrix A. | -//| Input parameters: | -//| InvA - inverse of matrix A. | -//| Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| UpdRow - the row of A whose vector V was added. | -//| 0 <= Row <= N-1 | -//| V - the vector to be added to a row. | -//| Array whose index ranges within [0..N-1]. | -//| Output parameters: | -//| InvA - inverse of modified matrix A. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixInvUpdateRow(CMatrixDouble &inva,const int n, - const int updrow,double &v[]) - { -//--- get result - CInverseUpdate::RMatrixInvUpdateRow(inva,n,updrow,v); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Inverse matrix update by the Sherman-Morrison formula | -//| The algorithm updates matrix A^-1 when adding a vector to a | -//| column of matrix A. | -//| Input parameters: | -//| InvA - inverse of matrix A. | -//| Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| UpdColumn - the column of A whose vector U was added. | -//| 0 <= UpdColumn <= N-1 | -//| U - the vector to be added to a column. | -//| Array whose index ranges within [0..N-1]. | -//| Output parameters: | -//| InvA - inverse of modified matrix A. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixInvUpdateColumn(CMatrixDouble &inva,const int n, - const int updcolumn,double &u[]) - { -//--- get result - CInverseUpdate::RMatrixInvUpdateColumn(inva,n,updcolumn,u); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Inverse matrix update by the Sherman-Morrison formula | -//| The algorithm computes the inverse of matrix A+u*v? by using the | -//| given matrix A^-1 and the vectors u and v. | -//| Input parameters: | -//| InvA - inverse of matrix A. | -//| Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| U - the vector modifying the matrix. | -//| Array whose index ranges within [0..N-1]. | -//| V - the vector modifying the matrix. | -//| Array whose index ranges within [0..N-1]. | -//| Output parameters: | -//| InvA - inverse of matrix A + u*v'. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixInvUpdateUV(CMatrixDouble &inva,const int n, - double &u[],double &v[]) - { -//--- get result - CInverseUpdate::RMatrixInvUpdateUV(inva,n,u,v); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Subroutine performing the Schur decomposition of a general matrix| -//| by using the QR algorithm with multiple shifts. | -//| The source matrix A is represented as S'*A*S = T, where S is an | -//| orthogonal matrix (Schur vectors), T - upper quasi-triangular | -//| matrix (with blocks of sizes 1x1 and 2x2 on the main diagonal). | -//| Input parameters: | -//| A - matrix to be decomposed. | -//| Array whose indexes range within [0..N-1, 0..N-1]. | -//| N - size of A, N>=0. | -//| Output parameters: | -//| A - contains matrix T. | -//| Array whose indexes range within [0..N-1, 0..N-1]. | -//| S - contains Schur vectors. | -//| Array whose indexes range within [0..N-1, 0..N-1]. | -//| Note 1: | -//| The block structure of matrix T can be easily recognized: | -//| since all the elements below the blocks are zeros, the | -//| elements a[i+1,i] which are equal to 0 show the block border.| -//| Note 2: | -//| The algorithm performance depends on the value of the | -//| internal parameter NS of the InternalSchurDecomposition | -//| subroutine which defines the number of shifts in the QR | -//| algorithm (similarly to the block width in block-matrix | -//| algorithms in linear algebra). If you require maximum | -//| performance on your machine, it is recommended to adjust | -//| this parameter manually. | -//| Result: | -//| True, | -//| if the algorithm has converged and parameters A and S | -//| contain the result. | -//| False, | -//| if the algorithm has not converged. | -//| Algorithm implemented on the basis of the DHSEQR subroutine | -//| (LAPACK 3.0 library). | -//+------------------------------------------------------------------+ -static bool CAlglib::RMatrixSchur(CMatrixDouble &a,const int n,CMatrixDouble &s) - { -//--- return result - return(CSchur::RMatrixSchur(a,n,s)); - } -//+------------------------------------------------------------------+ -//| NONLINEAR CONJUGATE GRADIENT METHOD | -//| DESCRIPTION: | -//| The subroutine minimizes function F(x) of N arguments by using | -//| one of the nonlinear conjugate gradient methods. | -//| These CG methods are globally convergent (even on non-convex | -//| functions) as long as grad(f) is Lipschitz continuous in a some | -//| neighborhood of the L = { x : f(x)<=f(x0) }. | -//| REQUIREMENTS: | -//| Algorithm will request following information during its | -//| operation: | -//| * function value F and its gradient G (simultaneously) at given | -//| point X | -//| USAGE: | -//| 1. User initializes algorithm state with MinCGCreate() call | -//| 2. User tunes solver parameters with MinCGSetCond(), | -//| MinCGSetStpMax() and other functions | -//| 3. User calls MinCGOptimize() function which takes algorithm | -//| state and pointer (delegate, etc.) to callback function which | -//| calculates F/G. | -//| 4. User calls MinCGResults() to get solution | -//| 5. Optionally, user may call MinCGRestartFrom() to solve another | -//| problem with same N but another starting point and/or another | -//| function. MinCGRestartFrom() allows to reuse already | -//| initialized structure. | -//| INPUT PARAMETERS: | -//| N - problem dimension, N>0: | -//| * if given, only leading N elements of X are used| -//| * if not given, automatically determined from | -//| size of X | -//| X - starting point, array[0..N-1]. | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//+------------------------------------------------------------------+ -static void CAlglib::MinCGCreate(const int n,double &x[],CMinCGStateShell &state) - { -//--- function call - CMinCG::MinCGCreate(n,x,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| NONLINEAR CONJUGATE GRADIENT METHOD | -//| DESCRIPTION: | -//| The subroutine minimizes function F(x) of N arguments by using | -//| one of the nonlinear conjugate gradient methods. | -//| These CG methods are globally convergent (even on non-convex | -//| functions) as long as grad(f) is Lipschitz continuous in a some | -//| neighborhood of the L = { x : f(x)<=f(x0) }. | -//| REQUIREMENTS: | -//| Algorithm will request following information during its | -//| operation: | -//| * function value F and its gradient G (simultaneously) at given | -//| point X | -//| USAGE: | -//| 1. User initializes algorithm state with MinCGCreate() call | -//| 2. User tunes solver parameters with MinCGSetCond(), | -//| MinCGSetStpMax() and other functions | -//| 3. User calls MinCGOptimize() function which takes algorithm | -//| state and pointer (delegate, etc.) to callback function which | -//| calculates F/G. | -//| 4. User calls MinCGResults() to get solution | -//| 5. Optionally, user may call MinCGRestartFrom() to solve another | -//| problem with same N but another starting point and/or another | -//| function. MinCGRestartFrom() allows to reuse already | -//| initialized structure. | -//| INPUT PARAMETERS: | -//| N - problem dimension, N>0: | -//| * if given, only leading N elements of X are used| -//| * if not given, automatically determined from | -//| size of X | -//| X - starting point, array[0..N-1]. | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//+------------------------------------------------------------------+ -static void CAlglib::MinCGCreate(double &x[],CMinCGStateShell &state) - { -//--- create a variable - int n; -//--- initialization - n=CAp::Len(x); -//--- function call - CMinCG::MinCGCreate(n,x,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| The subroutine is finite difference variant of MinCGCreate(). | -//| It uses finite differences in order to differentiate target | -//| function. | -//| Description below contains information which is specific to this | -//| function only. We recommend to read comments on MinCGCreate() in | -//| order to get more information about creation of CG optimizer. | -//| INPUT PARAMETERS: | -//| N - problem dimension, N>0: | -//| * if given, only leading N elements of X are | -//| used | -//| * if not given, automatically determined from | -//| size of X | -//| X - starting point, array[0..N-1]. | -//| DiffStep- differentiation step, >0 | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTES: | -//| 1. algorithm uses 4-point central formula for differentiation. | -//| 2. differentiation step along I-th axis is equal to | -//| DiffStep*S[I] where S[] is scaling vector which can be set by | -//| MinCGSetScale() call. | -//| 3. we recommend you to use moderate values of differentiation | -//| step. Too large step will result in too large truncation | -//| errors, while too small step will result in too large | -//| numerical errors. 1.0E-6 can be good value to start with. | -//| 4. Numerical differentiation is very inefficient - one gradient | -//| calculation needs 4*N function evaluations. This function will| -//| work for any N - either small (1...10), moderate (10...100) or| -//| large (100...). However, performance penalty will be too | -//| severe for any N's except for small ones. | -//| We should also say that code which relies on numerical | -//| differentiation is less robust and precise. L-BFGS needs | -//| exact gradient values. Imprecise gradient may slow down | -//| convergence, especially on highly nonlinear problems. | -//| Thus we recommend to use this function for fast prototyping | -//| on small- dimensional problems only, and to implement | -//| analytical gradient as soon as possible. | -//+------------------------------------------------------------------+ -static void CAlglib::MinCGCreateF(const int n,double &x[],double diffstep, - CMinCGStateShell &state) - { -//--- function call - CMinCG::MinCGCreateF(n,x,diffstep,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| The subroutine is finite difference variant of MinCGCreate(). | -//| It uses finite differences in order to differentiate target | -//| function. | -//| Description below contains information which is specific to this | -//| function only. We recommend to read comments on MinCGCreate() in | -//| order to get more information about creation of CG optimizer. | -//| INPUT PARAMETERS: | -//| N - problem dimension, N>0: | -//| * if given, only leading N elements of X are | -//| used | -//| * if not given, automatically determined from | -//| size of X | -//| X - starting point, array[0..N-1]. | -//| DiffStep- differentiation step, >0 | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTES: | -//| 1. algorithm uses 4-point central formula for differentiation. | -//| 2. differentiation step along I-th axis is equal to | -//| DiffStep*S[I] where S[] is scaling vector which can be set by | -//| MinCGSetScale() call. | -//| 3. we recommend you to use moderate values of differentiation | -//| step. Too large step will result in too large truncation | -//| errors, while too small step will result in too large | -//| numerical errors. 1.0E-6 can be good value to start with. | -//| 4. Numerical differentiation is very inefficient - one gradient | -//| calculation needs 4*N function evaluations. This function will| -//| work for any N - either small (1...10), moderate (10...100) or| -//| large (100...). However, performance penalty will be too | -//| severe for any N's except for small ones. | -//| We should also say that code which relies on numerical | -//| differentiation is less robust and precise. L-BFGS needs | -//| exact gradient values. Imprecise gradient may slow down | -//| convergence, especially on highly nonlinear problems. | -//| Thus we recommend to use this function for fast prototyping | -//| on small- dimensional problems only, and to implement | -//| analytical gradient as soon as possible. | -//+------------------------------------------------------------------+ -static void CAlglib::MinCGCreateF(double &x[],double diffstep, - CMinCGStateShell &state) - { -//--- create a variable - int n; -//--- initialization - n=CAp::Len(x); -//--- function call - CMinCG::MinCGCreateF(n,x,diffstep,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets stopping conditions for CG optimization | -//| algorithm. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| EpsG - >=0 | -//| The subroutine finishes its work if the condition| -//| |v|=0 | -//| The subroutine finishes its work if on k+1-th | -//| iteration the condition |F(k+1)-F(k)| <= | -//| <= EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. | -//| EpsX - >=0 | -//| The subroutine finishes its work if on k+1-th | -//| iteration the condition |v|<=EpsX is fulfilled, | -//| where: | -//| * |.| means Euclidian norm | -//| * v - scaled step vector, v[i]=dx[i]/s[i] | -//| * dx - ste pvector, dx=X(k+1)-X(k) | -//| * s - scaling coefficients set by MinCGSetScale()| -//| MaxIts - maximum number of iterations. If MaxIts=0, the | -//| number of iterations is unlimited. | -//| Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will| -//| lead to automatic stopping criterion selection (small EpsX). | -//+------------------------------------------------------------------+ -static void CAlglib::MinCGSetCond(CMinCGStateShell &state,double epsg, - double epsf,double epsx,int maxits) - { -//--- function call - CMinCG::MinCGSetCond(state.GetInnerObj(),epsg,epsf,epsx,maxits); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets scaling coefficients for CG optimizer. | -//| ALGLIB optimizers use scaling matrices to test stopping | -//| conditions (step size and gradient are scaled before comparison | -//| with tolerances). Scale of the I-th variable is a translation | -//| invariant measure of: | -//| a) "how large" the variable is | -//| b) how large the step should be to make significant changes in | -//| the function | -//| Scaling is also used by finite difference variant of CG | -//| optimizer - step along I-th axis is equal to DiffStep*S[I]. | -//| In most optimizers (and in the CG too) scaling is NOT a form of | -//| preconditioning. It just affects stopping conditions. You should | -//| set preconditioner by separate call to one of the | -//| MinCGSetPrec...() functions. | -//| There is special preconditioning mode, however, which uses | -//| scaling coefficients to form diagonal preconditioning matrix. | -//| You can turn this mode on, if you want. But you should understand| -//| that scaling is not the same thing as preconditioning - these are| -//| two different, although related forms of tuning solver. | -//| INPUT PARAMETERS: | -//| State - structure stores algorithm state | -//| S - array[N], non-zero scaling coefficients | -//| S[i] may be negative, sign doesn't matter. | -//+------------------------------------------------------------------+ -static void CAlglib::MinCGSetScale(CMinCGStateShell &state,double &s[]) - { -//--- function call - CMinCG::MinCGSetScale(state.GetInnerObj(),s); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function turns on/off reporting. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NeedXRep- whether iteration reports are needed or not | -//| If NeedXRep is True, algorithm will call rep() callback function | -//| if it is provided to MinCGOptimize(). | -//+------------------------------------------------------------------+ -static void CAlglib::MinCGSetXRep(CMinCGStateShell &state,bool needxrep) - { -//--- function call - CMinCG::MinCGSetXRep(state.GetInnerObj(),needxrep); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets CG algorithm. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| CGType - algorithm type: | -//| * -1 automatic selection of the best | -//| algorithm | -//| * 0 DY (Dai and Yuan) algorithm | -//| * 1 Hybrid DY-HS algorithm | -//+------------------------------------------------------------------+ -static void CAlglib::MinCGSetCGType(CMinCGStateShell &state,int cgtype) - { -//--- function call - CMinCG::MinCGSetCGType(state.GetInnerObj(),cgtype); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets maximum step length | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| StpMax - maximum step length, >=0. Set StpMax to 0.0, if | -//| you don't want to limit step length. | -//| Use this subroutine when you optimize target function which | -//| contains exp() or other fast growing functions, and optimization | -//| algorithm makes too large steps which leads to overflow. This | -//| function allows us to reject steps that are too large (and | -//| therefore expose us to the possible overflow) without actually | -//| calculating function value at the x+stp*d. | -//+------------------------------------------------------------------+ -static void CAlglib::MinCGSetStpMax(CMinCGStateShell &state,double stpmax) - { -//--- function call - CMinCG::MinCGSetStpMax(state.GetInnerObj(),stpmax); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function allows to suggest initial step length to the CG | -//| algorithm. | -//| Suggested step length is used as starting point for the line | -//| search. It can be useful when you have badly scaled problem, i.e.| -//| when ||grad|| (which is used as initial estimate for the first | -//| step) is many orders of magnitude different from the desired | -//| step. | -//| Line search may fail on such problems without good estimate of | -//| initial step length. Imagine, for example, problem with | -//| ||grad||=10^50 and desired step equal to 0.1 Line search | -//| function will use 10^50 as initial step, then it will decrease | -//| step length by 2 (up to 20 attempts) and will get 10^44, which is| -//| still too large. | -//| This function allows us to tell than line search should be | -//| started from some moderate step length, like 1.0, so algorithm | -//| will be able to detect desired step length in a several searches.| -//| Default behavior (when no step is suggested) is to use | -//| preconditioner, if it is available, to generate initial estimate | -//| of step length. | -//| This function influences only first iteration of algorithm. It | -//| should be called between MinCGCreate/MinCGRestartFrom() call and | -//| MinCGOptimize call. Suggested step is ignored if you have | -//| preconditioner. | -//| INPUT PARAMETERS: | -//| State - structure used to store algorithm state. | -//| Stp - initial estimate of the step length. | -//| Can be zero (no estimate). | -//+------------------------------------------------------------------+ -static void CAlglib::MinCGSuggestStep(CMinCGStateShell &state,double stp) - { -//--- function call - CMinCG::MinCGSuggestStep(state.GetInnerObj(),stp); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Modification of the preconditioner: preconditioning is turned | -//| off. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTE: you can change preconditioner "on the fly", during | -//| algorithm iterations. | -//+------------------------------------------------------------------+ -static void CAlglib::MinCGSetPrecDefault(CMinCGStateShell &state) - { -//--- function call - CMinCG::MinCGSetPrecDefault(state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Modification of the preconditioner: diagonal of approximate | -//| Hessian is used. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| D - diagonal of the approximate Hessian, | -//| array[0..N-1], (if larger, only leading N | -//| elements are used). | -//| NOTE: you can change preconditioner "on the fly", during | -//| algorithm iterations. | -//| NOTE 2: D[i] should be positive. Exception will be thrown | -//| otherwise. | -//| NOTE 3: you should pass diagonal of approximate Hessian - NOT | -//| ITS INVERSE. | -//+------------------------------------------------------------------+ -static void CAlglib::MinCGSetPrecDiag(CMinCGStateShell &state,double &d[]) - { -//--- function call - CMinCG::MinCGSetPrecDiag(state.GetInnerObj(),d); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Modification of the preconditioner: scale-based diagonal | -//| preconditioning. | -//| This preconditioning mode can be useful when you don't have | -//| approximate diagonal of Hessian, but you know that your variables| -//| are badly scaled (for example, one variable is in [1,10], and | -//| another in [1000,100000]), and most part of the ill-conditioning | -//| comes from different scales of vars. | -//| In this case simple scale-based preconditioner, | -//| with H[i] = 1/(s[i]^2), can greatly improve convergence. | -//| IMPRTANT: you should set scale of your variables with | -//| MinCGSetScale() call (before or after MinCGSetPrecScale() call). | -//| Without knowledge of the scale of your variables scale-based | -//| preconditioner will be just unit matrix. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTE: you can change preconditioner "on the fly", during | -//| algorithm iterations. | -//+------------------------------------------------------------------+ -static void CAlglib::MinCGSetPrecScale(CMinCGStateShell &state) - { -//--- function call - CMinCG::MinCGSetPrecScale(state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function provides reverse communication interface | -//| Reverse communication interface is not documented or recommended | -//| to use. | -//| See below for functions which provide better documented API | -//+------------------------------------------------------------------+ -static bool CAlglib::MinCGIteration(CMinCGStateShell &state) - { -//--- return result - return(CMinCG::MinCGIteration(state.GetInnerObj())); - } -//+------------------------------------------------------------------+ -//| This family of functions is used to launcn iterations of | -//| nonlinear optimizer | -//| These functions accept following parameters: | -//| func - callback which calculates function (or merit | -//| function) value func at given point x | -//| grad - callback which calculates function (or merit | -//| function) value func and gradient grad at given | -//| point x | -//| rep - optional callback which is called after each | -//| iteration can be null | -//| obj - optional object which is passed to | -//| func/grad/hess/jac/rep can be null | -//| NOTES: | -//| 1. This function has two different implementations: one which | -//| uses exact (analytical) user-supplied gradient, and one which| -//| uses function value only and numerically differentiates | -//| function in order to obtain gradient. | -//| Depending on the specific function used to create optimizer | -//| object (either MinCGCreate() for analytical gradient or | -//| MinCGCreateF() for numerical differentiation) you should | -//| choose appropriate variant of MinCGOptimize() - one which | -//| accepts function AND gradient or one which accepts function | -//| ONLY. | -//| Be careful to choose variant of MinCGOptimize() which | -//| corresponds to your optimization scheme! Table below lists | -//| different combinations of callback (function/gradient) passed | -//| to MinCGOptimize() and specific function used to create | -//| optimizer. | -//| | USER PASSED TO MinCGOptimize() | -//| CREATED WITH | function only | function and gradient | -//| ------------------------------------------------------------ | -//| MinCGCreateF() | work FAIL | -//| MinCGCreate() | FAIL work | -//| Here "FAIL" denotes inappropriate combinations of optimizer | -//| creation function and MinCGOptimize() version. Attemps to use | -//| such combination (for example, to create optimizer with | -//| MinCGCreateF() and to pass gradient information to | -//| MinCGOptimize()) will lead to exception being thrown. Either | -//| you did not pass gradient when it WAS needed or you passed | -//| gradient when it was NOT needed. | -//+------------------------------------------------------------------+ -static void CAlglib::MinCGOptimize(CMinCGStateShell &state,CNDimensional_Func &func, - CNDimensional_Rep &rep,bool rep_status,CObject &obj) - { -//--- cycle - while(CAlglib::MinCGIteration(state)) - { - //--- check - if(state.GetNeedF()) - { - func.Func(state.GetInnerObj().m_x,state.GetInnerObj().m_f,obj); - //--- next iteration - continue; - } - //--- check - if(state.GetInnerObj().m_xupdated) - { - //--- check - if(rep_status) - rep.Rep(state.GetInnerObj().m_x,state.GetInnerObj().m_f,obj); - //--- next iteration - continue; - } - Print("ALGLIB: error in 'mincgoptimize' (some derivatives were not provided?)"); - CAp::exception_happened=true; - return; - } - } -//+------------------------------------------------------------------+ -//| This family of functions is used to launcn iterations of | -//| nonlinear optimizer | -//| These functions accept following parameters: | -//| func - callback which calculates function (or merit | -//| function) value func at given point x | -//| grad - callback which calculates function (or merit | -//| function) value func and gradient grad at given | -//| point x | -//| rep - optional callback which is called after each | -//| iteration can be null | -//| obj - optional object which is passed to | -//| func/grad/hess/jac/rep can be null | -//| NOTES: | -//| 1. This function has two different implementations: one which | -//| uses exact (analytical) user-supplied gradient, and one which| -//| uses function value only and numerically differentiates | -//| function in order to obtain gradient. | -//| Depending on the specific function used to create optimizer | -//| object (either MinCGCreate() for analytical gradient or | -//| MinCGCreateF() for numerical differentiation) you should | -//| choose appropriate variant of MinCGOptimize() - one which | -//| accepts function AND gradient or one which accepts function | -//| ONLY. | -//| Be careful to choose variant of MinCGOptimize() which | -//| corresponds to your optimization scheme! Table below lists | -//| different combinations of callback (function/gradient) passed | -//| to MinCGOptimize() and specific function used to create | -//| optimizer. | -//| | USER PASSED TO MinCGOptimize() | -//| CREATED WITH | function only | function and gradient | -//| ------------------------------------------------------------ | -//| MinCGCreateF() | work FAIL | -//| MinCGCreate() | FAIL work | -//| Here "FAIL" denotes inappropriate combinations of optimizer | -//| creation function and MinCGOptimize() version. Attemps to use | -//| such combination (for example, to create optimizer with | -//| MinCGCreateF() and to pass gradient information to | -//| MinCGOptimize()) will lead to exception being thrown. Either | -//| you did not pass gradient when it WAS needed or you passed | -//| gradient when it was NOT needed. | -//+------------------------------------------------------------------+ -static void CAlglib::MinCGOptimize(CMinCGStateShell &state,CNDimensional_Grad &grad, - CNDimensional_Rep &rep,bool rep_status,CObject &obj) - { -//--- cycle - while(CAlglib::MinCGIteration(state)) - { - //--- check - if(state.GetNeedFG()) - { - grad.Grad(state.GetInnerObj().m_x,state.GetInnerObj().m_f,state.GetInnerObj().m_g,obj); - //--- next iteration - continue; - } - //--- check - if(state.GetInnerObj().m_xupdated) - { - //--- check - if(rep_status) - rep.Rep(state.GetInnerObj().m_x,state.GetInnerObj().m_f,obj); - //--- next iteration - continue; - } - Print("ALGLIB: error in 'mincgoptimize' (some derivatives were not provided?)"); - CAp::exception_happened=true; - return; - } - } -//+------------------------------------------------------------------+ -//| Conjugate gradient results | -//| INPUT PARAMETERS: | -//| State - algorithm state | -//| OUTPUT PARAMETERS: | -//| X - array[0..N-1], solution | -//| Rep - optimization report: | -//| * Rep.TerminationType completetion code: | -//| * 1 relative function improvement is no | -//| more than EpsF. | -//| * 2 relative step is no more than EpsX. | -//| * 4 gradient norm is no more than EpsG | -//| * 5 MaxIts steps was taken | -//| * 7 stopping conditions are too | -//| stringent, further improvement is | -//| impossible, we return best X found | -//| so far | -//| * 8 terminated by user | -//| * Rep.IterationsCount contains iterations count | -//| * NFEV countains number of function calculations | -//+------------------------------------------------------------------+ -static void CAlglib::MinCGResults(CMinCGStateShell &state,double &x[], - CMinCGReportShell &rep) - { -//--- function call - CMinCG::MinCGResults(state.GetInnerObj(),x,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Conjugate gradient results | -//| Buffered implementation of MinCGResults(), which uses | -//| pre-allocated buffer to store X[]. If buffer size is too small, | -//| it resizes buffer.It is intended to be used in the inner cycles | -//| of performance critical algorithms where array reallocation | -//| penalty is too large to be ignored. | -//+------------------------------------------------------------------+ -static void CAlglib::MinCGResultsBuf(CMinCGStateShell &state,double &x[], - CMinCGReportShell &rep) - { -//--- function call - CMinCG::MinCGResultsBuf(state.GetInnerObj(),x,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This subroutine restarts CG algorithm from new point. All | -//| optimization parameters are left unchanged. | -//| This function allows to solve multiple optimization problems | -//| (which must have same number of dimensions) without object | -//| reallocation penalty. | -//| INPUT PARAMETERS: | -//| State - structure used to store algorithm state. | -//| X - new starting point. | -//+------------------------------------------------------------------+ -static void CAlglib::MinCGRestartFrom(CMinCGStateShell &state,double &x[]) - { -//--- function call - CMinCG::MinCGRestartFrom(state.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| BOUND CONSTRAINED OPTIMIZATION | -//| WITH ADDITIONAL LINEAR EQUALITY AND INEQUALITY CONSTRAINTS| -//| DESCRIPTION: | -//| The subroutine minimizes function F(x) of N arguments subject to | -//| any combination of: | -//| * bound constraints | -//| * linear inequality constraints | -//| * linear equality constraints | -//| REQUIREMENTS: | -//| * user must provide function value and gradient | -//| * starting point X0 must be feasible or | -//| not too far away from the feasible set | -//| * grad(f) must be Lipschitz continuous on a level set: | -//| L = { x : f(x)<=f(x0) } | -//| * function must be defined everywhere on the feasible set F | -//| USAGE: | -//| Constrained optimization if far more complex than the | -//| unconstrained one. Here we give very brief outline of the BLEIC | -//| optimizer. We strongly recommend you to read examples in the | -//| ALGLIB Reference Manual and to read ALGLIB User Guide on | -//| optimization, which is available at | -//| http://www.alglib.net/optimization/ | -//| 1. User initializes algorithm state with MinBLEICCreate() call | -//| 2. USer adds boundary and/or linear constraints by calling | -//| MinBLEICSetBC() and MinBLEICSetLC() functions. | -//| 3. User sets stopping conditions for underlying unconstrained | -//| solver with MinBLEICSetInnerCond() call. | -//| This function controls accuracy of underlying optimization | -//| algorithm. | -//| 4. User sets stopping conditions for outer iteration by calling | -//| MinBLEICSetOuterCond() function. | -//| This function controls handling of boundary and inequality | -//| constraints. | -//| 5. Additionally, user may set limit on number of internal | -//| iterations by MinBLEICSetMaxIts() call. | -//| This function allows to prevent algorithm from looping | -//| forever. | -//| 6. User calls MinBLEICOptimize() function which takes algorithm | -//| state and pointer (delegate, etc.) to callback function | -//| which calculates F/G. | -//| 7. User calls MinBLEICResults() to get solution | -//| 8. Optionally user may call MinBLEICRestartFrom() to solve | -//| another problem with same N but another starting point. | -//| MinBLEICRestartFrom() allows to reuse already initialized | -//| structure. | -//| INPUT PARAMETERS: | -//| N - problem dimension, N>0: | -//| * if given, only leading N elements of X are | -//| used | -//| * if not given, automatically determined from | -//| size ofX | -//| X - starting point, array[N]: | -//| * it is better to set X to a feasible point | -//| * but X can be infeasible, in which case | -//| algorithm will try to find feasible point | -//| first, using X as initial approximation. | -//| OUTPUT PARAMETERS: | -//| State - structure stores algorithm state | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICCreate(const int n,double &x[],CMinBLEICStateShell &state) - { -//--- function call - CMinBLEIC::MinBLEICCreate(n,x,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| BOUND CONSTRAINED OPTIMIZATION | -//| WITH ADDITIONAL LINEAR EQUALITY AND INEQUALITY CONSTRAINTS| -//| DESCRIPTION: | -//| The subroutine minimizes function F(x) of N arguments subject to | -//| any combination of: | -//| * bound constraints | -//| * linear inequality constraints | -//| * linear equality constraints | -//| REQUIREMENTS: | -//| * user must provide function value and gradient | -//| * starting point X0 must be feasible or | -//| not too far away from the feasible set | -//| * grad(f) must be Lipschitz continuous on a level set: | -//| L = { x : f(x)<=f(x0) } | -//| * function must be defined everywhere on the feasible set F | -//| USAGE: | -//| Constrained optimization if far more complex than the | -//| unconstrained one. Here we give very brief outline of the BLEIC | -//| optimizer. We strongly recommend you to read examples in the | -//| ALGLIB Reference Manual and to read ALGLIB User Guide on | -//| optimization, which is available at | -//| http://www.alglib.net/optimization/ | -//| 1. User initializes algorithm state with MinBLEICCreate() call | -//| 2. USer adds boundary and/or linear constraints by calling | -//| MinBLEICSetBC() and MinBLEICSetLC() functions. | -//| 3. User sets stopping conditions for underlying unconstrained | -//| solver with MinBLEICSetInnerCond() call. | -//| This function controls accuracy of underlying optimization | -//| algorithm. | -//| 4. User sets stopping conditions for outer iteration by calling | -//| MinBLEICSetOuterCond() function. | -//| This function controls handling of boundary and inequality | -//| constraints. | -//| 5. Additionally, user may set limit on number of internal | -//| iterations by MinBLEICSetMaxIts() call. | -//| This function allows to prevent algorithm from looping | -//| forever. | -//| 6. User calls MinBLEICOptimize() function which takes algorithm | -//| state and pointer (delegate, etc.) to callback function | -//| which calculates F/G. | -//| 7. User calls MinBLEICResults() to get solution | -//| 8. Optionally user may call MinBLEICRestartFrom() to solve | -//| another problem with same N but another starting point. | -//| MinBLEICRestartFrom() allows to reuse already initialized | -//| structure. | -//| INPUT PARAMETERS: | -//| N - problem dimension, N>0: | -//| * if given, only leading N elements of X are | -//| used | -//| * if not given, automatically determined from | -//| size ofX | -//| X - starting point, array[N]: | -//| * it is better to set X to a feasible point | -//| * but X can be infeasible, in which case | -//| algorithm will try to find feasible point | -//| first, using X as initial approximation. | -//| OUTPUT PARAMETERS: | -//| State - structure stores algorithm state | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICCreate(double &x[],CMinBLEICStateShell &state) - { -//--- create a variable - int n; -//--- initialization - n=CAp::Len(x); -//--- function call - CMinBLEIC::MinBLEICCreate(n,x,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| The subroutine is finite difference variant of MinBLEICCreate(). | -//| It uses finite differences in order to differentiate target | -//| function. | -//| Description below contains information which is specific to this | -//| function only. We recommend to read comments on MinBLEICCreate() | -//| in order to get more information about creation of BLEIC | -//| optimizer. | -//| INPUT PARAMETERS: | -//| N - problem dimension, N>0: | -//| * if given, only leading N elements of X are used| -//| * if not given, automatically determined from | -//| size of X | -//| X - starting point, array[0..N-1]. | -//| DiffStep- differentiation step, >0 | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTES: | -//| 1. algorithm uses 4-point central formula for differentiation. | -//| 2. differentiation step along I-th axis is equal to DiffStep*S[I]| -//| where S[] is scaling vector which can be set by | -//| MinBLEICSetScale() call. | -//| 3. we recommend you to use moderate values of differentiation | -//| step. Too large step will result in too large truncation | -//| errors, while too small step will result in too large | -//| numerical errors. 1.0E-6 can be good value to start with. | -//| 4. Numerical differentiation is very inefficient - one gradient | -//| calculation needs 4*N function evaluations. This function will| -//| work for any N - either small (1...10), moderate (10...100) or| -//| large (100...). However, performance penalty will be too | -//| severe for any N's except for small ones. | -//| We should also say that code which relies on numerical | -//| differentiation is less robust and precise. CG needs exact | -//| gradient values. Imprecise gradient may slow down convergence,| -//| especially on highly nonlinear problems. | -//| Thus we recommend to use this function for fast prototyping on| -//| small - dimensional problems only, and to implement analytical| -//| gradient as soon as possible. | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICCreateF(const int n,double &x[],double diffstep, - CMinBLEICStateShell &state) - { -//--- function call - CMinBLEIC::MinBLEICCreateF(n,x,diffstep,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| The subroutine is finite difference variant of MinBLEICCreate(). | -//| It uses finite differences in order to differentiate target | -//| function. | -//| Description below contains information which is specific to this | -//| function only. We recommend to read comments on MinBLEICCreate() | -//| in order to get more information about creation of BLEIC | -//| optimizer. | -//| INPUT PARAMETERS: | -//| N - problem dimension, N>0: | -//| * if given, only leading N elements of X are used| -//| * if not given, automatically determined from | -//| size of X | -//| X - starting point, array[0..N-1]. | -//| DiffStep- differentiation step, >0 | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTES: | -//| 1. algorithm uses 4-point central formula for differentiation. | -//| 2. differentiation step along I-th axis is equal to DiffStep*S[I]| -//| where S[] is scaling vector which can be set by | -//| MinBLEICSetScale() call. | -//| 3. we recommend you to use moderate values of differentiation | -//| step. Too large step will result in too large truncation | -//| errors, while too small step will result in too large | -//| numerical errors. 1.0E-6 can be good value to start with. | -//| 4. Numerical differentiation is very inefficient - one gradient | -//| calculation needs 4*N function evaluations. This function will| -//| work for any N - either small (1...10), moderate (10...100) or| -//| large (100...). However, performance penalty will be too | -//| severe for any N's except for small ones. | -//| We should also say that code which relies on numerical | -//| differentiation is less robust and precise. CG needs exact | -//| gradient values. Imprecise gradient may slow down convergence,| -//| especially on highly nonlinear problems. | -//| Thus we recommend to use this function for fast prototyping on| -//| small - dimensional problems only, and to implement analytical| -//| gradient as soon as possible. | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICCreateF(double &x[],double diffstep, - CMinBLEICStateShell &state) - { -//--- create a variable - int n; -//--- initialization - n=CAp::Len(x); -//--- function call - CMinBLEIC::MinBLEICCreateF(n,x,diffstep,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets boundary constraints for BLEIC optimizer. | -//| Boundary constraints are inactive by default (after initial | -//| creation). They are preserved after algorithm restart with | -//| MinBLEICRestartFrom(). | -//| INPUT PARAMETERS: | -//| State - structure stores algorithm state | -//| BndL - lower bounds, array[N]. | -//| If some (all) variables are unbounded, you may | -//| specify very small number or -INF. | -//| BndU - upper bounds, array[N]. | -//| If some (all) variables are unbounded, you may | -//| specify very large number or +INF. | -//| NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case | -//| I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. | -//| NOTE 2: this solver has following useful properties: | -//| * bound constraints are always satisfied exactly | -//| * function is evaluated only INSIDE area specified by bound | -//| constraints, even when numerical differentiation is used | -//| (algorithm adjusts nodes according to boundary constraints) | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICSetBC(CMinBLEICStateShell &state,double &bndl[], - double &bndu[]) - { -//--- function call - CMinBLEIC::MinBLEICSetBC(state.GetInnerObj(),bndl,bndu); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets linear constraints for BLEIC optimizer. | -//| Linear constraints are inactive by default (after initial | -//| creation). They are preserved after algorithm restart with | -//| MinBLEICRestartFrom(). | -//| INPUT PARAMETERS: | -//| State - structure previously allocated with | -//| MinBLEICCreate call. | -//| C - linear constraints, array[K,N+1]. | -//| Each row of C represents one constraint, either | -//| equality or inequality (see below): | -//| * first N elements correspond to coefficients, | -//| * last element corresponds to the right part. | -//| All elements of C (including right part) must be | -//| finite. | -//| CT - type of constraints, array[K]: | -//| * if CT[i]>0, then I-th constraint is | -//| C[i,*]*x >= C[i,n+1] | -//| * if CT[i]=0, then I-th constraint is | -//| C[i,*]*x = C[i,n+1] | -//| * if CT[i]<0, then I-th constraint is | -//| C[i,*]*x <= C[i,n+1] | -//| K - number of equality/inequality constraints, K>=0: | -//| * if given, only leading K elements of C/CT are | -//| used | -//| * if not given, automatically determined from | -//| sizes of C/CT | -//| NOTE 1: linear (non-bound) constraints are satisfied only | -//| approximately: | -//| * there always exists some minor violation (about Epsilon in | -//| magnitude) due to rounding errors | -//| * numerical differentiation, if used, may lead to function | -//| evaluations outside of the feasible area, because algorithm | -//| does NOT change numerical differentiation formula according to | -//| linear constraints. | -//| If you want constraints to be satisfied exactly, try to | -//| reformulate your problem in such manner that all constraints will| -//| become boundary ones (this kind of constraints is always | -//| satisfied exactly, both in the final solution and in all | -//| intermediate points). | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICSetLC(CMinBLEICStateShell &state,CMatrixDouble &c, - int &ct[],const int k) - { -//--- function call - CMinBLEIC::MinBLEICSetLC(state.GetInnerObj(),c,ct,k); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets linear constraints for BLEIC optimizer. | -//| Linear constraints are inactive by default (after initial | -//| creation). They are preserved after algorithm restart with | -//| MinBLEICRestartFrom(). | -//| INPUT PARAMETERS: | -//| State - structure previously allocated with | -//| MinBLEICCreate call. | -//| C - linear constraints, array[K,N+1]. | -//| Each row of C represents one constraint, either | -//| equality or inequality (see below): | -//| * first N elements correspond to coefficients, | -//| * last element corresponds to the right part. | -//| All elements of C (including right part) must be | -//| finite. | -//| CT - type of constraints, array[K]: | -//| * if CT[i]>0, then I-th constraint is | -//| C[i,*]*x >= C[i,n+1] | -//| * if CT[i]=0, then I-th constraint is | -//| C[i,*]*x = C[i,n+1] | -//| * if CT[i]<0, then I-th constraint is | -//| C[i,*]*x <= C[i,n+1] | -//| K - number of equality/inequality constraints, K>=0: | -//| * if given, only leading K elements of C/CT are | -//| used | -//| * if not given, automatically determined from | -//| sizes of C/CT | -//| NOTE 1: linear (non-bound) constraints are satisfied only | -//| approximately: | -//| * there always exists some minor violation (about Epsilon in | -//| magnitude) due to rounding errors | -//| * numerical differentiation, if used, may lead to function | -//| evaluations outside of the feasible area, because algorithm | -//| does NOT change numerical differentiation formula according to | -//| linear constraints. | -//| If you want constraints to be satisfied exactly, try to | -//| reformulate your problem in such manner that all constraints will| -//| become boundary ones (this kind of constraints is always | -//| satisfied exactly, both in the final solution and in all | -//| intermediate points). | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICSetLC(CMinBLEICStateShell &state,CMatrixDouble &c, - int &ct[]) - { -//--- create a variable - int k; -//--- check - if(CAp::Rows(c)!=CAp::Len(ct)) - { - Print(__FUNCTION__+": looks like one of arguments has wrong size"); - CAp::exception_happened=true; - return; - } -//--- initialization - k=CAp::Rows(c); -//--- function call - CMinBLEIC::MinBLEICSetLC(state.GetInnerObj(),c,ct,k); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets stopping conditions for the underlying | -//| nonlinear CG optimizer. It controls overall accuracy of solution.| -//| These conditions should be strict enough in order for algorithm | -//| to converge. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| EpsG - >=0 | -//| The subroutine finishes its work if the condition| -//| |v|=0 | -//| The subroutine finishes its work if on k+1-th | -//| iteration the condition |F(k+1)-F(k)| <= | -//| <= EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. | -//| EpsX - >=0 | -//| The subroutine finishes its work if on k+1-th | -//| iteration the condition |v|<=EpsX is fulfilled, | -//| where: | -//| * |.| means Euclidian norm | -//| * v - scaled step vector, v[i]=dx[i]/s[i] | -//| * dx - ste pvector, dx=X(k+1)-X(k) | -//| * s - scaling coefficients set by | -//| MinBLEICSetScale() | -//| Passing EpsG=0, EpsF=0 and EpsX=0 (simultaneously) will lead to | -//| automatic stopping criterion selection. | -//| These conditions are used to terminate inner iterations. However,| -//| you need to tune termination conditions for outer iterations too.| -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICSetInnerCond(CMinBLEICStateShell &state, - const double epsg, - const double epsf, - const double epsx) - { -//--- function call - CMinBLEIC::MinBLEICSetInnerCond(state.GetInnerObj(),epsg,epsf,epsx); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets stopping conditions for outer iteration of | -//| BLEIC algo. | -//| These conditions control accuracy of constraint handling and | -//| amount of infeasibility allowed in the solution. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| EpsX - >0, stopping condition on outer iteration step | -//| length | -//| EpsI - >0, stopping condition on infeasibility | -//| Both EpsX and EpsI must be non-zero. | -//| MEANING OF EpsX | -//| EpsX is a stopping condition for outer iterations. Algorithm will| -//| stop when solution of the current modified subproblem will be | -//| within EpsX (using 2-norm) of the previous solution. | -//| MEANING OF EpsI | -//| EpsI controls feasibility properties - algorithm won't stop until| -//| all inequality constraints will be satisfied with error (distance| -//| from current point to the feasible area) at most EpsI. | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICSetOuterCond(CMinBLEICStateShell &state, - const double epsx,const double epsi) - { -//--- function call - CMinBLEIC::MinBLEICSetOuterCond(state.GetInnerObj(),epsx,epsi); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets scaling coefficients for BLEIC optimizer. | -//| ALGLIB optimizers use scaling matrices to test stopping | -//| conditions (step size and gradient are scaled before comparison | -//| with tolerances). Scale of the I-th variable is a translation | -//| invariant measure of: | -//| a) "how large" the variable is | -//| b) how large the step should be to make significant changes in | -//| the function | -//| Scaling is also used by finite difference variant of the | -//| optimizer - step along I-th axis is equal to DiffStep*S[I]. | -//| In most optimizers (and in the BLEIC too) scaling is NOT a form | -//| of preconditioning. It just affects stopping conditions. You | -//| should set preconditioner by separate call to one of the | -//| MinBLEICSetPrec...() functions. | -//| There is a special preconditioning mode, however, which uses | -//| scaling coefficients to form diagonal preconditioning matrix. | -//| You can turn this mode on, if you want. But you should understand| -//| that scaling is not the same thing as preconditioning - these are| -//| two different, although related forms of tuning solver. | -//| INPUT PARAMETERS: | -//| State - structure stores algorithm state | -//| S - array[N], non-zero scaling coefficients | -//| S[i] may be negative, sign doesn't matter. | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICSetScale(CMinBLEICStateShell &state,double &s[]) - { -//--- function call - CMinBLEIC::MinBLEICSetScale(state.GetInnerObj(),s); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Modification of the preconditioner: preconditioning is turned | -//| off. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICSetPrecDefault(CMinBLEICStateShell &state) - { -//--- function call - CMinBLEIC::MinBLEICSetPrecDefault(state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Modification of the preconditioner: diagonal of approximate | -//| Hessian is used. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| D - diagonal of the approximate Hessian, | -//| array[0..N-1], (if larger, only leading N | -//| elements are used). | -//| NOTE 1: D[i] should be positive. Exception will be thrown | -//| otherwise. | -//| NOTE 2: you should pass diagonal of approximate Hessian - NOT | -//| ITS INVERSE. | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICSetPrecDiag(CMinBLEICStateShell &state, - double &d[]) - { -//--- function call - CMinBLEIC::MinBLEICSetPrecDiag(state.GetInnerObj(),d); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Modification of the preconditioner: scale-based diagonal | -//| preconditioning. | -//| This preconditioning mode can be useful when you don't have | -//| approximate diagonal of Hessian, but you know that your variables| -//| are badly scaled (for example, one variable is in [1,10], and | -//| another in [1000,100000]), and most part of the ill-conditioning | -//| comes from different scales of vars. | -//| In this case simple scale-based preconditioner, with H[i] = | -//| = 1/(s[i]^2), can greatly improve convergence. | -//| IMPRTANT: you should set scale of your variables with | -//| MinBLEICSetScale() call (before or after MinBLEICSetPrecScale() | -//| call). Without knowledge of the scale of your variables | -//| scale-based preconditioner will be just unit matrix. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICSetPrecScale(CMinBLEICStateShell &state) - { -//--- function call - CMinBLEIC::MinBLEICSetPrecScale(state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function allows to stop algorithm after specified number of | -//| inner iterations. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| MaxIts - maximum number of inner iterations. | -//| If MaxIts=0, the number of iterations is | -//| unlimited. | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICSetMaxIts(CMinBLEICStateShell &state, - const int maxits) - { -//--- function call - CMinBLEIC::MinBLEICSetMaxIts(state.GetInnerObj(),maxits); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function turns on/off reporting. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NeedXRep- whether iteration reports are needed or not | -//| If NeedXRep is True, algorithm will call rep() callback function | -//| if it is provided to MinBLEICOptimize(). | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICSetXRep(CMinBLEICStateShell &state,bool needxrep) - { -//--- function call - CMinBLEIC::MinBLEICSetXRep(state.GetInnerObj(),needxrep); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets maximum step length | -//| IMPORTANT: this feature is hard to combine with preconditioning. | -//| You can't set upper limit on step length, when you solve | -//| optimization problem with linear (non-boundary) constraints AND | -//| preconditioner turned on. | -//| When non-boundary constraints are present, you have to either a) | -//| use preconditioner, or b) use upper limit on step length. YOU | -//| CAN'T USE BOTH! In this case algorithm will terminate with | -//| appropriate error code. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| StpMax - maximum step length, >=0. Set StpMax to 0.0, if | -//| you don't want to limit step length. | -//| Use this subroutine when you optimize target function which | -//| contains exp() or other fast growing functions, and optimization | -//| algorithm makes too large steps which lead to overflow. This | -//| function allows us to reject steps that are too large (and | -//| therefore expose us to the possible overflow) without actually | -//| calculating function value at the x+stp*d. | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICSetStpMax(CMinBLEICStateShell &state,double stpmax) - { -//--- function call - CMinBLEIC::MinBLEICSetStpMax(state.GetInnerObj(),stpmax); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function provides reverse communication interface | -//| Reverse communication interface is not documented or recommended | -//| to use. | -//| See below for functions which provide better documented API | -//+------------------------------------------------------------------+ -static bool CAlglib::MinBLEICIteration(CMinBLEICStateShell &state) - { -//--- return result - return(CMinBLEIC::MinBLEICIteration(state.GetInnerObj())); - } -//+------------------------------------------------------------------+ -//| This family of functions is used to launcn iterations of | -//| nonlinear optimizer | -//| These functions accept following parameters: | -//| func - callback which calculates function (or merit | -//| function) value func at given point x | -//| grad - callback which calculates function (or merit | -//| function) value func and gradient grad at given | -//| point x | -//| rep - optional callback which is called after each | -//| iteration can be null | -//| obj - optional object which is passed to | -//| func/grad/hess/jac/rep can be null | -//| NOTES: | -//| 1. This function has two different implementations: one which | -//| uses exact (analytical) user-supplied gradient, and one which | -//| uses function value only and numerically differentiates | -//| function in order to obtain gradient. | -//| Depending on the specific function used to create optimizer | -//| object (either MinBLEICCreate() for analytical gradient or | -//| MinBLEICCreateF() for numerical differentiation) you should | -//| choose appropriate variant of MinBLEICOptimize() - one which | -//| accepts function AND gradient or one which accepts function | -//| ONLY. | -//| Be careful to choose variant of MinBLEICOptimize() which | -//| corresponds to your optimization scheme! Table below lists | -//| different combinations of callback (function/gradient) passed | -//| to MinBLEICOptimize() and specific function used to create | -//| optimizer. | -//| | USER PASSED TO MinBLEICOptimize() | -//| CREATED WITH | function only | function and gradient | -//| ------------------------------------------------------------ | -//| MinBLEICCreateF() | work FAIL | -//| MinBLEICCreate() | FAIL work | -//| Here "FAIL" denotes inappropriate combinations of optimizer | -//| creation function and MinBLEICOptimize() version. Attemps to | -//| use such combination (for example, to create optimizer with | -//| MinBLEICCreateF() and to pass gradient information to | -//| MinCGOptimize()) will lead to exception being thrown. Either | -//| you did not pass gradient when it WAS needed or you passed | -//| gradient when it was NOT needed. | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICOptimize(CMinBLEICStateShell &state,CNDimensional_Func &func, - CNDimensional_Rep &rep,bool rep_status,CObject &obj) - { -//--- cycle - while(CAlglib::MinBLEICIteration(state)) - { - //--- check - if(state.GetNeedF()) - { - func.Func(state.GetInnerObj().m_x,state.GetInnerObj().m_f,obj); - //--- next iteration - continue; - } - //--- check - if(state.GetInnerObj().m_xupdated) - { - //--- check - if(rep_status) - rep.Rep(state.GetInnerObj().m_x,state.GetInnerObj().m_f,obj); - //--- next iteration - continue; - } - Print("ALGLIB: error in 'minbleicoptimize' (some derivatives were not provided?)"); - CAp::exception_happened=true; - return; - } - } -//+------------------------------------------------------------------+ -//| This family of functions is used to launcn iterations of | -//| nonlinear optimizer | -//| These functions accept following parameters: | -//| func - callback which calculates function (or merit | -//| function) value func at given point x | -//| grad - callback which calculates function (or merit | -//| function) value func and gradient grad at given | -//| point x | -//| rep - optional callback which is called after each | -//| iteration can be null | -//| obj - optional object which is passed to | -//| func/grad/hess/jac/rep can be null | -//| NOTES: | -//| 1. This function has two different implementations: one which | -//| uses exact (analytical) user-supplied gradient, and one which | -//| uses function value only and numerically differentiates | -//| function in order to obtain gradient. | -//| Depending on the specific function used to create optimizer | -//| object (either MinBLEICCreate() for analytical gradient or | -//| MinBLEICCreateF() for numerical differentiation) you should | -//| choose appropriate variant of MinBLEICOptimize() - one which | -//| accepts function AND gradient or one which accepts function | -//| ONLY. | -//| Be careful to choose variant of MinBLEICOptimize() which | -//| corresponds to your optimization scheme! Table below lists | -//| different combinations of callback (function/gradient) passed | -//| to MinBLEICOptimize() and specific function used to create | -//| optimizer. | -//| | USER PASSED TO MinBLEICOptimize() | -//| CREATED WITH | function only | function and gradient | -//| ------------------------------------------------------------ | -//| MinBLEICCreateF() | work FAIL | -//| MinBLEICCreate() | FAIL work | -//| Here "FAIL" denotes inappropriate combinations of optimizer | -//| creation function and MinBLEICOptimize() version. Attemps to | -//| use such combination (for example, to create optimizer with | -//| MinBLEICCreateF() and to pass gradient information to | -//| MinCGOptimize()) will lead to exception being thrown. Either | -//| you did not pass gradient when it WAS needed or you passed | -//| gradient when it was NOT needed. | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICOptimize(CMinBLEICStateShell &state,CNDimensional_Grad &grad, - CNDimensional_Rep &rep,bool rep_status,CObject &obj) - { -//--- cycle - while(CAlglib::MinBLEICIteration(state)) - { - //--- check - if(state.GetNeedFG()) - { - grad.Grad(state.GetInnerObj().m_x,state.GetInnerObj().m_f,state.GetInnerObj().m_g,obj); - //--- next iteration - continue; - } - //--- check - if(state.GetInnerObj().m_xupdated) - { - //--- check - if(rep_status) - rep.Rep(state.GetInnerObj().m_x,state.GetInnerObj().m_f,obj); - //--- next iteration - continue; - } - Print("ALGLIB: error in 'minbleicoptimize' (some derivatives were not provided?)"); - CAp::exception_happened=true; - return; - } - } -//+------------------------------------------------------------------+ -//| BLEIC results | -//| INPUT PARAMETERS: | -//| State - algorithm state | -//| OUTPUT PARAMETERS: | -//| X - array[0..N-1], solution | -//| Rep - optimization report. You should check Rep. | -//| TerminationType in order to distinguish | -//| successful termination from unsuccessful one. | -//| More information about fields of this structure | -//| can be found in the comments on MinBLEICReport | -//| datatype. | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICResults(CMinBLEICStateShell &state,double &x[], - CMinBLEICReportShell &rep) - { -//--- function call - CMinBLEIC::MinBLEICResults(state.GetInnerObj(),x,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| BLEIC results | -//| Buffered implementation of MinBLEICResults() which uses | -//| pre-allocated buffer to store X[]. If buffer size is too small, | -//| it resizes buffer. It is intended to be used in the inner cycles | -//| of performance critical algorithms where array reallocation | -//| penalty is too large to be ignored. | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICResultsBuf(CMinBLEICStateShell &state,double &x[], - CMinBLEICReportShell &rep) - { -//--- function call - CMinBLEIC::MinBLEICResultsBuf(state.GetInnerObj(),x,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This subroutine restarts algorithm from new point. | -//| All optimization parameters (including constraints) are left | -//| unchanged. | -//| This function allows to solve multiple optimization problems | -//| (which must have same number of dimensions) without object | -//| reallocation penalty. | -//| INPUT PARAMETERS: | -//| State - structure previously allocated with | -//| MinBLEICCreate call. | -//| X - new starting point. | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICRestartFrom(CMinBLEICStateShell &state, - double &x[]) - { -//--- function call - CMinBLEIC::MinBLEICRestartFrom(state.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION | -//| DESCRIPTION: | -//| The subroutine minimizes function F(x) of N arguments by using a | -//| quasi - Newton method (LBFGS scheme) which is optimized to use a | -//| minimum amount of memory. | -//| The subroutine generates the approximation of an inverse Hessian | -//| matrix by using information about the last M steps of the | -//| algorithm (instead of N). It lessens a required amount of memory | -//| from a value of order N^2 to a value of order 2*N*M. | -//| REQUIREMENTS: | -//| Algorithm will request following information during its | -//| operation: | -//| * function value F and its gradient G (simultaneously) at given | -//| point X | -//| USAGE: | -//| 1. User initializes algorithm state with MinLBFGSCreate() call | -//| 2. User tunes solver parameters with MinLBFGSSetCond() | -//| MinLBFGSSetStpMax() and other functions | -//| 3. User calls MinLBFGSOptimize() function which takes algorithm | -//| state and pointer (delegate, etc.) to callback function which | -//| calculates F/G. | -//| 4. User calls MinLBFGSResults() to get solution | -//| 5. Optionally user may call MinLBFGSRestartFrom() to solve | -//| another problem with same N/M but another starting point | -//| and/or another function. MinLBFGSRestartFrom() allows to reuse| -//| already initialized structure. | -//| INPUT PARAMETERS: | -//| N - problem dimension. N>0 | -//| M - number of corrections in the BFGS scheme of | -//| Hessian approximation update. Recommended value: | -//| 3<=M<=7. The smaller value causes worse | -//| convergence, the bigger will not cause a | -//| considerably better convergence, but will cause | -//| a fall in the performance. M<=N. | -//| X - initial solution approximation, array[0..N-1]. | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTES: | -//| 1. you may tune stopping conditions with MinLBFGSSetCond() | -//| function | -//| 2. if target function contains exp() or other fast growing | -//| functions, and optimization algorithm makes too large steps | -//| which leads to overflow, use MinLBFGSSetStpMax() function to | -//| bound algorithm's steps. However, L-BFGS rarely needs such a | -//| tuning. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLBFGSCreate(const int n,const int m,double &x[], - CMinLBFGSStateShell &state) - { -//--- function call - CMinLBFGS::MinLBFGSCreate(n,m,x,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION | -//| DESCRIPTION: | -//| The subroutine minimizes function F(x) of N arguments by using a | -//| quasi - Newton method (LBFGS scheme) which is optimized to use a | -//| minimum amount of memory. | -//| The subroutine generates the approximation of an inverse Hessian | -//| matrix by using information about the last M steps of the | -//| algorithm (instead of N). It lessens a required amount of memory | -//| from a value of order N^2 to a value of order 2*N*M. | -//| REQUIREMENTS: | -//| Algorithm will request following information during its | -//| operation: | -//| * function value F and its gradient G (simultaneously) at given | -//| point X | -//| USAGE: | -//| 1. User initializes algorithm state with MinLBFGSCreate() call | -//| 2. User tunes solver parameters with MinLBFGSSetCond() | -//| MinLBFGSSetStpMax() and other functions | -//| 3. User calls MinLBFGSOptimize() function which takes algorithm | -//| state and pointer (delegate, etc.) to callback function which | -//| calculates F/G. | -//| 4. User calls MinLBFGSResults() to get solution | -//| 5. Optionally user may call MinLBFGSRestartFrom() to solve | -//| another problem with same N/M but another starting point | -//| and/or another function. MinLBFGSRestartFrom() allows to reuse| -//| already initialized structure. | -//| INPUT PARAMETERS: | -//| N - problem dimension. N>0 | -//| M - number of corrections in the BFGS scheme of | -//| Hessian approximation update. Recommended value: | -//| 3<=M<=7. The smaller value causes worse | -//| convergence, the bigger will not cause a | -//| considerably better convergence, but will cause | -//| a fall in the performance. M<=N. | -//| X - initial solution approximation, array[0..N-1]. | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTES: | -//| 1. you may tune stopping conditions with MinLBFGSSetCond() | -//| function | -//| 2. if target function contains exp() or other fast growing | -//| functions, and optimization algorithm makes too large steps | -//| which leads to overflow, use MinLBFGSSetStpMax() function to | -//| bound algorithm's steps. However, L-BFGS rarely needs such a | -//| tuning. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLBFGSCreate(const int m,double &x[],CMinLBFGSStateShell &state) - { -//--- create a variable - int n; -//--- initialization - n=CAp::Len(x); -//--- function call - CMinLBFGS::MinLBFGSCreate(n,m,x,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| The subroutine is finite difference variant of MinLBFGSCreate(). | -//| It uses finite differences in order to differentiate target | -//| function. | -//| Description below contains information which is specific to this | -//| function only. We recommend to read comments on MinLBFGSCreate() | -//| in order to get more information about creation of LBFGS | -//| optimizer. | -//| INPUT PARAMETERS: | -//| N - problem dimension, N>0: | -//| * if given, only leading N elements of X are used| -//| * if not given, automatically determined from | -//| size of X | -//| M - number of corrections in the BFGS scheme of | -//| Hessian approximation update. Recommended value: | -//| 3<=M<=7. The smaller value causes worse | -//| convergence, the bigger will not cause a | -//| considerably better convergence, but will cause a| -//| fall in the performance. M<=N. | -//| X - starting point, array[0..N-1]. | -//| DiffStep- differentiation step, >0 | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTES: | -//| 1. algorithm uses 4-point central formula for differentiation. | -//| 2. differentiation step along I-th axis is equal to DiffStep*S[I]| -//| where S[] is scaling vector which can be set by | -//| MinLBFGSSetScale() call. | -//| 3. we recommend you to use moderate values of differentiation | -//| step. Too large step will result in too large truncation | -//| errors, while too small step will result in too large | -//| numerical errors. 1.0E-6 can be good value to start with. | -//| 4. Numerical differentiation is very inefficient - one gradient | -//| calculation needs 4*N function evaluations. This function will| -//| work for any N - either small (1...10), moderate (10...100) or| -//| large (100...). However, performance penalty will be too | -//| severe for any N's except for small ones. | -//| We should also say that code which relies on numerical | -//| differentiation is less robust and precise. LBFGS needs exact | -//| gradient values. Imprecise gradient may slow down convergence,| -//| especially on highly nonlinear problems. | -//| Thus we recommend to use this function for fast prototyping on| -//| small- dimensional problems only, and to implement analytical | -//| gradient as soon as possible. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLBFGSCreateF(const int n,const int m,double &x[], - const double diffstep,CMinLBFGSStateShell &state) - { -//--- function call - CMinLBFGS::MinLBFGSCreateF(n,m,x,diffstep,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| The subroutine is finite difference variant of MinLBFGSCreate(). | -//| It uses finite differences in order to differentiate target | -//| function. | -//| Description below contains information which is specific to this | -//| function only. We recommend to read comments on MinLBFGSCreate() | -//| in order to get more information about creation of LBFGS | -//| optimizer. | -//| INPUT PARAMETERS: | -//| N - problem dimension, N>0: | -//| * if given, only leading N elements of X are used| -//| * if not given, automatically determined from | -//| size of X | -//| M - number of corrections in the BFGS scheme of | -//| Hessian approximation update. Recommended value: | -//| 3<=M<=7. The smaller value causes worse | -//| convergence, the bigger will not cause a | -//| considerably better convergence, but will cause a| -//| fall in the performance. M<=N. | -//| X - starting point, array[0..N-1]. | -//| DiffStep- differentiation step, >0 | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTES: | -//| 1. algorithm uses 4-point central formula for differentiation. | -//| 2. differentiation step along I-th axis is equal to DiffStep*S[I]| -//| where S[] is scaling vector which can be set by | -//| MinLBFGSSetScale() call. | -//| 3. we recommend you to use moderate values of differentiation | -//| step. Too large step will result in too large truncation | -//| errors, while too small step will result in too large | -//| numerical errors. 1.0E-6 can be good value to start with. | -//| 4. Numerical differentiation is very inefficient - one gradient | -//| calculation needs 4*N function evaluations. This function will| -//| work for any N - either small (1...10), moderate (10...100) or| -//| large (100...). However, performance penalty will be too | -//| severe for any N's except for small ones. | -//| We should also say that code which relies on numerical | -//| differentiation is less robust and precise. LBFGS needs exact | -//| gradient values. Imprecise gradient may slow down convergence,| -//| especially on highly nonlinear problems. | -//| Thus we recommend to use this function for fast prototyping on| -//| small- dimensional problems only, and to implement analytical | -//| gradient as soon as possible. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLBFGSCreateF(const int m,double &x[],const double diffstep, - CMinLBFGSStateShell &state) - { -//--- create a variable - int n; -//--- initialization - n=CAp::Len(x); -//--- function call - CMinLBFGS::MinLBFGSCreateF(n,m,x,diffstep,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets stopping conditions for L-BFGS optimization | -//| algorithm. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| EpsG - >=0 | -//| The subroutine finishes its work if the condition| -//| |v|=0 | -//| The subroutine finishes its work if on k+1-th | -//| iteration the condition |F(k+1)-F(k)| <= | -//| <= EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. | -//| EpsX - >=0 | -//| The subroutine finishes its work if on k+1-th | -//| iteration the condition |v|<=EpsX is fulfilled, | -//| where: | -//| * |.| means Euclidian norm | -//| * v - scaled step vector, v[i]=dx[i]/s[i] | -//| * dx - ste pvector, dx=X(k+1)-X(k) | -//| * s - scaling coefficients set by | -//| MinLBFGSSetScale() | -//| MaxIts - maximum number of iterations. If MaxIts=0, the | -//| number of iterations is unlimited. | -//| Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will| -//| lead to automatic stopping criterion selection (small EpsX). | -//+------------------------------------------------------------------+ -static void CAlglib::MinLBFGSSetCond(CMinLBFGSStateShell &state,const double epsg, - const double epsf,const double epsx, - const int maxits) - { -//--- function call - CMinLBFGS::MinLBFGSSetCond(state.GetInnerObj(),epsg,epsf,epsx,maxits); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function turns on/off reporting. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NeedXRep- whether iteration reports are needed or not | -//| If NeedXRep is True, algorithm will call rep() callback function | -//| if it is provided to MinLBFGSOptimize(). | -//+------------------------------------------------------------------+ -static void CAlglib::MinLBFGSSetXRep(CMinLBFGSStateShell &state,const bool needxrep) - { -//--- function call - CMinLBFGS::MinLBFGSSetXRep(state.GetInnerObj(),needxrep); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets maximum step length | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| StpMax - maximum step length, >=0. Set StpMax to 0.0 | -//| (default), if you don't want to limit step | -//| length. | -//| Use this subroutine when you optimize target function which | -//| contains exp() or other fast growing functions, and optimization | -//| algorithm makes too large steps which leads to overflow. This | -//| function allows us to reject steps that are too large (and | -//| therefore expose us to the possible overflow) without actually | -//| calculating function value at the x+stp*d. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLBFGSSetStpMax(CMinLBFGSStateShell &state,const double stpmax) - { -//--- function call - CMinLBFGS::MinLBFGSSetStpMax(state.GetInnerObj(),stpmax); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets scaling coefficients for LBFGS optimizer. | -//| ALGLIB optimizers use scaling matrices to test stopping | -//| conditions (step size and gradient are scaled before comparison | -//| with tolerances). Scale of the I-th variable is a translation | -//| invariant measure of: | -//| a) "how large" the variable is | -//| b) how large the step should be to make significant changes in | -//| the function | -//| Scaling is also used by finite difference variant of the | -//| optimizer - step along I-th axis is equal to DiffStep*S[I]. | -//| In most optimizers (and in the LBFGS too) scaling is NOT a form | -//| of preconditioning. It just affects stopping conditions. You | -//| should set preconditioner by separate call to one of the | -//| MinLBFGSSetPrec...() functions. | -//| There is special preconditioning mode, however, which uses | -//| scaling coefficients to form diagonal preconditioning matrix. | -//| You can turn this mode on, if you want. But you should | -//| understand that scaling is not the same thing as | -//| preconditioning - these are two different, although related | -//| forms of tuning solver. | -//| INPUT PARAMETERS: | -//| State - structure stores algorithm state | -//| S - array[N], non-zero scaling coefficients | -//| S[i] may be negative, sign doesn't matter. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLBFGSSetScale(CMinLBFGSStateShell &state,double &s[]) - { -//--- function call - CMinLBFGS::MinLBFGSSetScale(state.GetInnerObj(),s); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Modification of the preconditioner: default preconditioner | -//| (simple scaling, same for all elements of X) is used. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTE: you can change preconditioner "on the fly", during | -//| algorithm iterations. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLBFGSSetPrecDefault(CMinLBFGSStateShell &state) - { -//--- function call - CMinLBFGS::MinLBFGSSetPrecDefault(state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Modification of the preconditioner: Cholesky factorization of | -//| approximate Hessian is used. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| P - triangular preconditioner, Cholesky factorization| -//| of the approximate Hessian. array[0..N-1,0..N-1],| -//| (if larger, only leading N elements are used). | -//| IsUpper - whether upper or lower triangle of P is given | -//| (other triangle is not referenced) | -//| After call to this function preconditioner is changed to P (P is | -//| copied into the internal buffer). | -//| NOTE: you can change preconditioner "on the fly", during | -//| algorithm iterations. | -//| NOTE 2: P should be nonsingular. Exception will be thrown | -//| otherwise. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLBFGSSetPrecCholesky(CMinLBFGSStateShell &state, - CMatrixDouble &p,const bool isupper) - { -//--- function call - CMinLBFGS::MinLBFGSSetPrecCholesky(state.GetInnerObj(),p,isupper); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Modification of the preconditioner: diagonal of approximate | -//| Hessian is used. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| D - diagonal of the approximate Hessian, | -//| array[0..N-1], (if larger, only leading N | -//| elements are used). | -//| NOTE: you can change preconditioner "on the fly", during | -//| algorithm iterations. | -//| NOTE 2: D[i] should be positive. Exception will be thrown | -//| otherwise. | -//| NOTE 3: you should pass diagonal of approximate Hessian - NOT | -//| ITS INVERSE. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLBFGSSetPrecDiag(CMinLBFGSStateShell &state,double &d[]) - { -//--- function call - CMinLBFGS::MinLBFGSSetPrecDiag(state.GetInnerObj(),d); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Modification of the preconditioner: scale-based diagonal | -//| preconditioning. | -//| This preconditioning mode can be useful when you don't have | -//| approximate diagonal of Hessian, but you know that your variables| -//| are badly scaled (for example, one variable is in [1,10], and | -//| another in [1000,100000]), and most part of the ill-conditioning | -//| comes from different scales of vars. | -//| In this case simple scale-based preconditioner, with H[i] = | -//| = 1/(s[i]^2), can greatly improve convergence. | -//| IMPRTANT: you should set scale of your variables with | -//| MinLBFGSSetScale() call (before or after MinLBFGSSetPrecScale() | -//| call). Without knowledge of the scale of your variables | -//| scale-based preconditioner will be just unit matrix. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//+------------------------------------------------------------------+ -static void CAlglib::MinLBFGSSetPrecScale(CMinLBFGSStateShell &state) - { -//--- function call - CMinLBFGS::MinLBFGSSetPrecScale(state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function provides reverse communication interface | -//| Reverse communication interface is not documented or recommended | -//| to use. | -//| See below for functions which provide better documented API | -//+------------------------------------------------------------------+ -static bool CAlglib::MinLBFGSIteration(CMinLBFGSStateShell &state) - { -//--- return result - return(CMinLBFGS::MinLBFGSIteration(state.GetInnerObj())); - } -//+------------------------------------------------------------------+ -//| This family of functions is used to launcn iterations of | -//| nonlinear optimizer | -//| These functions accept following parameters: | -//| func - callback which calculates function (or merit | -//| function) value func at given point x | -//| grad - callback which calculates function (or merit | -//| function) value func and gradient grad at given | -//| point x | -//| rep - optional callback which is called after each | -//| iteration can be null | -//| obj - optional object which is passed to | -//| func/grad/hess/jac/rep can be null | -//| NOTES: | -//| 1. This function has two different implementations: one which | -//| uses exact (analytical) user-supplied gradient, and one which | -//| uses function value only and numerically differentiates | -//| function in order to obtain gradient. | -//| Depending on the specific function used to create optimizer | -//| object (either MinLBFGSCreate() for analytical gradient or | -//| MinLBFGSCreateF() for numerical differentiation) you should | -//| choose appropriate variant of MinLBFGSOptimize() - one which | -//| accepts function AND gradient or one which accepts function | -//| ONLY. | -//| Be careful to choose variant of MinLBFGSOptimize() which | -//| corresponds to your optimization scheme! Table below lists | -//| different combinations of callback (function/gradient) passed | -//| to MinLBFGSOptimize() and specific function used to create | -//| optimizer. | -//| | USER PASSED TO MinLBFGSOptimize() | -//| CREATED WITH | function only | function and gradient | -//| ------------------------------------------------------------ | -//| MinLBFGSCreateF() | work FAIL | -//| MinLBFGSCreate() | FAIL work | -//| Here "FAIL" denotes inappropriate combinations of optimizer | -//| creation function and MinLBFGSOptimize() version. Attemps to | -//| use such combination (for example, to create optimizer with | -//| MinLBFGSCreateF() and to pass gradient information to | -//| MinCGOptimize()) will lead to exception being thrown. Either | -//| you did not pass gradient when it WAS needed or you passed | -//| gradient when it was NOT needed. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLBFGSOptimize(CMinLBFGSStateShell &state,CNDimensional_Func &func, - CNDimensional_Rep &rep,bool rep_status,CObject &obj) - { -//--- cycle - while(CAlglib::MinLBFGSIteration(state)) - { - //--- check - if(state.GetNeedF()) - { - func.Func(state.GetInnerObj().m_x,state.GetInnerObj().m_f,obj); - //--- next iteration - continue; - } - //--- check - if(state.GetInnerObj().m_xupdated) - { - //--- check - if(rep_status) - rep.Rep(state.GetInnerObj().m_x,state.GetInnerObj().m_f,obj); - //--- next iteration - continue; - } - Print("ALGLIB: error in 'minlbfgsoptimize' (some derivatives were not provided?)"); - CAp::exception_happened=true; - return; - } - } -//+------------------------------------------------------------------+ -//| This family of functions is used to launcn iterations of | -//| nonlinear optimizer | -//| These functions accept following parameters: | -//| func - callback which calculates function (or merit | -//| function) value func at given point x | -//| grad - callback which calculates function (or merit | -//| function) value func and gradient grad at given | -//| point x | -//| rep - optional callback which is called after each | -//| iteration can be null | -//| obj - optional object which is passed to | -//| func/grad/hess/jac/rep can be null | -//| NOTES: | -//| 1. This function has two different implementations: one which | -//| uses exact (analytical) user-supplied gradient, and one which | -//| uses function value only and numerically differentiates | -//| function in order to obtain gradient. | -//| Depending on the specific function used to create optimizer | -//| object (either MinLBFGSCreate() for analytical gradient or | -//| MinLBFGSCreateF() for numerical differentiation) you should | -//| choose appropriate variant of MinLBFGSOptimize() - one which | -//| accepts function AND gradient or one which accepts function | -//| ONLY. | -//| Be careful to choose variant of MinLBFGSOptimize() which | -//| corresponds to your optimization scheme! Table below lists | -//| different combinations of callback (function/gradient) passed | -//| to MinLBFGSOptimize() and specific function used to create | -//| optimizer. | -//| | USER PASSED TO MinLBFGSOptimize() | -//| CREATED WITH | function only | function and gradient | -//| ------------------------------------------------------------ | -//| MinLBFGSCreateF() | work FAIL | -//| MinLBFGSCreate() | FAIL work | -//| Here "FAIL" denotes inappropriate combinations of optimizer | -//| creation function and MinLBFGSOptimize() version. Attemps to | -//| use such combination (for example, to create optimizer with | -//| MinLBFGSCreateF() and to pass gradient information to | -//| MinCGOptimize()) will lead to exception being thrown. Either | -//| you did not pass gradient when it WAS needed or you passed | -//| gradient when it was NOT needed. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLBFGSOptimize(CMinLBFGSStateShell &state,CNDimensional_Grad &grad, - CNDimensional_Rep &rep,bool rep_status,CObject &obj) - { -//--- cycle - while(CAlglib::MinLBFGSIteration(state)) - { - //--- check - if(state.GetNeedFG()) - { - grad.Grad(state.GetInnerObj().m_x,state.GetInnerObj().m_f,state.GetInnerObj().m_g,obj); - //--- next iteration - continue; - } - //--- check - if(state.GetInnerObj().m_xupdated) - { - //--- check - if(rep_status) - rep.Rep(state.GetInnerObj().m_x,state.GetInnerObj().m_f,obj); - //--- next iteration - continue; - } - Print("ALGLIB: error in 'minlbfgsoptimize' (some derivatives were not provided?)"); - CAp::exception_happened=true; - return; - } - } -//+------------------------------------------------------------------+ -//| L-BFGS algorithm results | -//| INPUT PARAMETERS: | -//| State - algorithm state | -//| OUTPUT PARAMETERS: | -//| X - array[0..N-1], solution | -//| Rep - optimization report: | -//| * Rep.TerminationType completetion code: | -//| * -2 rounding errors prevent further | -//| improvement. X contains best point | -//| found. | -//| * -1 incorrect parameters were specified | -//| * 1 relative function improvement is no | -//| more than EpsF. | -//| * 2 relative step is no more than EpsX. | -//| * 4 gradient norm is no more than EpsG | -//| * 5 MaxIts steps was taken | -//| * 7 stopping conditions are too | -//| stringent, further improvement is | -//| impossible | -//| * Rep.IterationsCount contains iterations count | -//| * NFEV countains number of function calculations | -//+------------------------------------------------------------------+ -static void CAlglib::MinLBFGSResults(CMinLBFGSStateShell &state,double &x[], - CMinLBFGSReportShell &rep) - { -//--- function call - CMinLBFGS::MinLBFGSResults(state.GetInnerObj(),x,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| L-BFGS algorithm results | -//| Buffered implementation of MinLBFGSResults which uses | -//| pre-allocated buffer to store X[]. If buffer size is too small, | -//| it resizes buffer. It is intended to be used in the inner cycles | -//| of performance critical algorithms where array reallocation | -//| penalty is too large to be ignored. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLBFGSresultsbuf(CMinLBFGSStateShell &state,double &x[], - CMinLBFGSReportShell &rep) - { -//--- function call - CMinLBFGS::MinLBFGSresultsbuf(state.GetInnerObj(),x,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This subroutine restarts LBFGS algorithm from new point. All | -//| optimization parameters are left unchanged. | -//| This function allows to solve multiple optimization problems | -//| (which must have same number of dimensions) without object | -//| reallocation penalty. | -//| INPUT PARAMETERS: | -//| State - structure used to store algorithm state | -//| X - new starting point. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLBFGSRestartFrom(CMinLBFGSStateShell &state,double &x[]) - { -//--- function call - CMinLBFGS::MinLBFGSRestartFrom(state.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| CONSTRAINED QUADRATIC PROGRAMMING | -//| The subroutine creates QP optimizer. After initial creation, it | -//| contains default optimization problem with zero quadratic and | -//| linear terms and no constraints. You should set quadratic/linear | -//| terms with calls to functions provided by MinQP subpackage. | -//| INPUT PARAMETERS: | -//| N - problem size | -//| OUTPUT PARAMETERS: | -//| State - optimizer with zero quadratic/linear terms | -//| and no constraints | -//+------------------------------------------------------------------+ -static void CAlglib::MinQPCreate(const int n,CMinQPStateShell &state) - { -//--- function call - CMinQP::MinQPCreate(n,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets linear term for QP solver. | -//| By default, linear term is zero. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| B - linear term, array[N]. | -//+------------------------------------------------------------------+ -static void CAlglib::MinQPSetLinearTerm(CMinQPStateShell &state,double &b[]) - { -//--- function call - CMinQP::MinQPSetLinearTerm(state.GetInnerObj(),b); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets quadratic term for QP solver. | -//| By default quadratic term is zero. | -//| IMPORTANT: this solver minimizes following function: | -//| f(x) = 0.5*x'*A*x + b'*x. | -//| Note that quadratic term has 0.5 before it. So if you want to | -//| minimize | -//| f(x) = x^2 + x | -//| you should rewrite your problem as follows: | -//| f(x) = 0.5*(2*x^2) + x | -//| and your matrix A will be equal to [[2.0]], not to [[1.0]] | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| A - matrix, array[N,N] | -//| IsUpper - (optional) storage type: | -//| * if True, symmetric matrix A is given by its | -//| upper triangle, and the lower triangle isn?t | -//| used | -//| * if False, symmetric matrix A is given by its | -//| lower triangle, and the upper triangle isn?t | -//| used | -//| * if not given, both lower and upper triangles | -//| must be filled. | -//+------------------------------------------------------------------+ -static void CAlglib::MinQPSetQuadraticTerm(CMinQPStateShell &state,CMatrixDouble &a, - const bool isupper) - { -//--- function call - CMinQP::MinQPSetQuadraticTerm(state.GetInnerObj(),a,isupper); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets quadratic term for QP solver. | -//| By default quadratic term is zero. | -//| IMPORTANT: this solver minimizes following function: | -//| f(x) = 0.5*x'*A*x + b'*x. | -//| Note that quadratic term has 0.5 before it. So if you want to | -//| minimize | -//| f(x) = x^2 + x | -//| you should rewrite your problem as follows: | -//| f(x) = 0.5*(2*x^2) + x | -//| and your matrix A will be equal to [[2.0]], not to [[1.0]] | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| A - matrix, array[N,N] | -//| IsUpper - (optional) storage type: | -//| * if True, symmetric matrix A is given by its | -//| upper triangle, and the lower triangle isn?t | -//| used | -//| * if False, symmetric matrix A is given by its | -//| lower triangle, and the upper triangle isn?t | -//| used | -//| * if not given, both lower and upper triangles | -//| must be filled. | -//+------------------------------------------------------------------+ -static void CAlglib::MinQPSetQuadraticTerm(CMinQPStateShell &state,CMatrixDouble &a) - { -//--- create a variable - bool isupper; -//--- check - if(!CAp::IsSymmetric(a)) - { - Print(__FUNCTION__+": 'a' parameter is not symmetric matrix"); - CAp::exception_happened=true; - return; - } -//--- initialization - isupper=false; -//--- function call - CMinQP::MinQPSetQuadraticTerm(state.GetInnerObj(),a,isupper); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets starting point for QP solver. It is useful to | -//| have good initial approximation to the solution, because it will | -//| increase speed of convergence and identification of active | -//| constraints. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| X - starting point, array[N]. | -//+------------------------------------------------------------------+ -static void CAlglib::MinQPSetStartingPoint(CMinQPStateShell &state,double &x[]) - { -//--- function call - CMinQP::MinQPSetStartingPoint(state.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets origin for QP solver. By default, following | -//| QP program is solved: | -//| min(0.5*x'*A*x+b'*x) | -//| This function allows to solve different problem: | -//| min(0.5*(x-x_origin)'*A*(x-x_origin)+b'*(x-x_origin)) | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| XOrigin - origin, array[N]. | -//+------------------------------------------------------------------+ -static void CAlglib::MinQPSetOrigin(CMinQPStateShell &state,double &xorigin[]) - { -//--- function call - CMinQP::MinQPSetOrigin(state.GetInnerObj(),xorigin); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function tells solver to use Cholesky-based algorithm. | -//| Cholesky-based algorithm can be used when: | -//| * problem is convex | -//| * there is no constraints or only boundary constraints are | -//| present | -//| This algorithm has O(N^3) complexity for unconstrained problem | -//| and is up to several times slower on bound constrained problems | -//| (these additional iterations are needed to identify active | -//| constraints). | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//+------------------------------------------------------------------+ -static void CAlglib::MinQPSetAlgoCholesky(CMinQPStateShell &state) - { -//--- function call - CMinQP::MinQPSetAlgoCholesky(state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets boundary constraints for QP solver | -//| Boundary constraints are inactive by default (after initial | -//| creation). After being set, they are preserved until explicitly | -//| turned off with another SetBC() call. | -//| INPUT PARAMETERS: | -//| State - structure stores algorithm state | -//| BndL - lower bounds, array[N]. | -//| If some (all) variables are unbounded, you may | -//| specify very small number or -INF (latter is | -//| recommended because it will allow solver to use | -//| better algorithm). | -//| BndU - upper bounds, array[N]. | -//| If some (all) variables are unbounded, you may | -//| specify very large number or +INF (latter is | -//| recommended because it will allow solver to use | -//| better algorithm). | -//| NOTE: it is possible to specify BndL[i]=BndU[i]. In this case | -//| I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. | -//+------------------------------------------------------------------+ -static void CAlglib::MinQPSetBC(CMinQPStateShell &state,double &bndl[], - double &bndu[]) - { -//--- function call - CMinQP::MinQPSetBC(state.GetInnerObj(),bndl,bndu); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function solves quadratic programming problem. | -//| You should call it after setting solver options with | -//| MinQPSet...() calls. | -//| INPUT PARAMETERS: | -//| State - algorithm state | -//| You should use MinQPResults() function to access results after | -//| calls to this function. | -//+------------------------------------------------------------------+ -static void CAlglib::MinQPOptimize(CMinQPStateShell &state) - { -//--- function call - CMinQP::MinQPOptimize(state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| QP solver results | -//| INPUT PARAMETERS: | -//| State - algorithm state | -//| OUTPUT PARAMETERS: | -//| X - array[0..N-1], solution | -//| Rep - optimization report. You should check Rep. | -//| TerminationType, which contains completion code, | -//| and you may check another fields which contain | -//| another information about algorithm functioning. | -//+------------------------------------------------------------------+ -static void CAlglib::MinQPResults(CMinQPStateShell &state,double &x[], - CMinQPReportShell &rep) - { -//--- function call - CMinQP::MinQPResults(state.GetInnerObj(),x,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| QP results | -//| Buffered implementation of MinQPResults() which uses | -//| pre-allocated buffer to store X[]. If buffer size is too small, | -//| it resizes buffer. It is intended to be used in the inner cycles | -//| of performance critical algorithms where array reallocation | -//| penalty is too large to be ignored. | -//+------------------------------------------------------------------+ -static void CAlglib::MinQPResultsBuf(CMinQPStateShell &state,double &x[], - CMinQPReportShell &rep) - { -//--- function call - CMinQP::MinQPResultsBuf(state.GetInnerObj(),x,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| IMPROVED LEVENBERG-MARQUARDT METHOD FOR | -//| NON-LINEAR LEAST SQUARES OPTIMIZATION | -//| DESCRIPTION: | -//| This function is used to find minimum of function which is | -//| represented as sum of squares: | -//| F(x) = f[0]^2(x[0],...,x[n-1]) + ... + | -//| + f[m-1]^2(x[0],...,x[n-1]) | -//| using value of function vector f[] and Jacobian of f[]. | -//| REQUIREMENTS: | -//| This algorithm will request following information during its | -//| operation: | -//| * function vector f[] at given point X | -//| * function vector f[] and Jacobian of f[] (simultaneously) at | -//| given point | -//| There are several overloaded versions of MinLMOptimize() | -//| function which correspond to different LM-like optimization | -//| algorithms provided by this unit. You should choose version which| -//| accepts fvec() and jac() callbacks. First one is used to | -//| calculate f[] at given point, second one calculates f[] and | -//| Jacobian df[i]/dx[j]. | -//| You can try to initialize MinLMState structure with VJ function | -//| and then use incorrect version of MinLMOptimize() (for example,| -//| version which works with general form function and does not | -//| provide Jacobian), but it will lead to exception being thrown | -//| after first attempt to calculate Jacobian. | -//| USAGE: | -//| 1. User initializes algorithm state with MinLMCreateVJ() call | -//| 2. User tunes solver parameters with MinLMSetCond(), | -//| MinLMSetStpMax() and other functions | -//| 3. User calls MinLMOptimize() function which takes algorithm | -//| state and callback functions. | -//| 4. User calls MinLMResults() to get solution | -//| 5. Optionally, user may call MinLMRestartFrom() to solve another | -//| problem with same N/M but another starting point and/or | -//| another function. MinLMRestartFrom() allows to reuse already | -//| initialized structure. | -//| INPUT PARAMETERS: | -//| N - dimension, N>1 | -//| * if given, only leading N elements of X are | -//| used | -//| * if not given, automatically determined from | -//| size of X | -//| M - number of functions f[i] | -//| X - initial solution, array[0..N-1] | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTES: | -//| 1. you may tune stopping conditions with MinLMSetCond() function | -//| 2. if target function contains exp() or other fast growing | -//| functions, and optimization algorithm makes too large steps | -//| which leads to overflow, use MinLMSetStpMax() function to | -//| bound algorithm's steps. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMCreateVJ(const int n,const int m,double &x[], - CMinLMStateShell &state) - { -//--- function call - CMinLM::MinLMCreateVJ(n,m,x,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| IMPROVED LEVENBERG-MARQUARDT METHOD FOR | -//| NON-LINEAR LEAST SQUARES OPTIMIZATION | -//| DESCRIPTION: | -//| This function is used to find minimum of function which is | -//| represented as sum of squares: | -//| F(x) = f[0]^2(x[0],...,x[n-1]) + ... + | -//| + f[m-1]^2(x[0],...,x[n-1]) | -//| using value of function vector f[] and Jacobian of f[]. | -//| REQUIREMENTS: | -//| This algorithm will request following information during its | -//| operation: | -//| * function vector f[] at given point X | -//| * function vector f[] and Jacobian of f[] (simultaneously) at | -//| given point | -//| There are several overloaded versions of MinLMOptimize() | -//| function which correspond to different LM-like optimization | -//| algorithms provided by this unit. You should choose version which| -//| accepts fvec() and jac() callbacks. First one is used to | -//| calculate f[] at given point, second one calculates f[] and | -//| Jacobian df[i]/dx[j]. | -//| You can try to initialize MinLMState structure with VJ function | -//| and then use incorrect version of MinLMOptimize() (for example,| -//| version which works with general form function and does not | -//| provide Jacobian), but it will lead to exception being thrown | -//| after first attempt to calculate Jacobian. | -//| USAGE: | -//| 1. User initializes algorithm state with MinLMCreateVJ() call | -//| 2. User tunes solver parameters with MinLMSetCond(), | -//| MinLMSetStpMax() and other functions | -//| 3. User calls MinLMOptimize() function which takes algorithm | -//| state and callback functions. | -//| 4. User calls MinLMResults() to get solution | -//| 5. Optionally, user may call MinLMRestartFrom() to solve another | -//| problem with same N/M but another starting point and/or | -//| another function. MinLMRestartFrom() allows to reuse already | -//| initialized structure. | -//| INPUT PARAMETERS: | -//| N - dimension, N>1 | -//| * if given, only leading N elements of X are | -//| used | -//| * if not given, automatically determined from | -//| size of X | -//| M - number of functions f[i] | -//| X - initial solution, array[0..N-1] | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTES: | -//| 1. you may tune stopping conditions with MinLMSetCond() function | -//| 2. if target function contains exp() or other fast growing | -//| functions, and optimization algorithm makes too large steps | -//| which leads to overflow, use MinLMSetStpMax() function to | -//| bound algorithm's steps. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMCreateVJ(const int m,double &x[],CMinLMStateShell &state) - { -//--- create a variable - int n; -//--- initialization - n=CAp::Len(x); -//--- function call - CMinLM::MinLMCreateVJ(n,m,x,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| IMPROVED LEVENBERG-MARQUARDT METHOD FOR | -//| NON-LINEAR LEAST SQUARES OPTIMIZATION | -//| DESCRIPTION: | -//| This function is used to find minimum of function which is | -//| represented as sum of squares: | -//| F(x) = f[0]^2(x[0],...,x[n-1]) + ... + | -//| + f[m-1]^2(x[0],...,x[n-1]) | -//| using value of function vector f[] only. Finite differences are | -//| used to calculate Jacobian. | -//| REQUIREMENTS: | -//| This algorithm will request following information during its | -//| operation: | -//| * function vector f[] at given point X | -//| There are several overloaded versions of MinLMOptimize() function| -//| which correspond to different LM-like optimization algorithms | -//| provided by this unit. You should choose version which accepts | -//| fvec() callback. | -//| You can try to initialize MinLMState structure with VJ function | -//| and then use incorrect version of MinLMOptimize() (for example, | -//| version which works with general form function and does not | -//| accept function vector), but it will lead to exception being | -//| thrown after first attempt to calculate Jacobian. | -//| USAGE: | -//| 1. User initializes algorithm state with MinLMCreateV() call | -//| 2. User tunes solver parameters with MinLMSetCond(), | -//| MinLMSetStpMax() and other functions | -//| 3. User calls MinLMOptimize() function which takes algorithm | -//| state and callback functions. | -//| 4. User calls MinLMResults() to get solution | -//| 5. Optionally, user may call MinLMRestartFrom() to solve another | -//| problem with same N/M but another starting point and/or | -//| another function. MinLMRestartFrom() allows to reuse already | -//| initialized structure. | -//| INPUT PARAMETERS: | -//| N - dimension, N>1 | -//| * if given, only leading N elements of X are | -//| used | -//| * if not given, automatically determined from | -//| size of X | -//| M - number of functions f[i] | -//| X - initial solution, array[0..N-1] | -//| DiffStep- differentiation step, >0 | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| See also MinLMIteration, MinLMResults. | -//| NOTES: | -//| 1. you may tune stopping conditions with MinLMSetCond() function | -//| 2. if target function contains exp() or other fast growing | -//| functions, and optimization algorithm makes too large steps | -//| which leads to overflow, use MinLMSetStpMax() function to | -//| bound algorithm's steps. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMCreateV(const int n,const int m,double &x[], - double diffstep,CMinLMStateShell &state) - { -//--- function call - CMinLM::MinLMCreateV(n,m,x,diffstep,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| IMPROVED LEVENBERG-MARQUARDT METHOD FOR | -//| NON-LINEAR LEAST SQUARES OPTIMIZATION | -//| DESCRIPTION: | -//| This function is used to find minimum of function which is | -//| represented as sum of squares: | -//| F(x) = f[0]^2(x[0],...,x[n-1]) + ... + | -//| + f[m-1]^2(x[0],...,x[n-1]) | -//| using value of function vector f[] only. Finite differences are | -//| used to calculate Jacobian. | -//| REQUIREMENTS: | -//| This algorithm will request following information during its | -//| operation: | -//| * function vector f[] at given point X | -//| There are several overloaded versions of MinLMOptimize() function| -//| which correspond to different LM-like optimization algorithms | -//| provided by this unit. You should choose version which accepts | -//| fvec() callback. | -//| You can try to initialize MinLMState structure with VJ function | -//| and then use incorrect version of MinLMOptimize() (for example, | -//| version which works with general form function and does not | -//| accept function vector), but it will lead to exception being | -//| thrown after first attempt to calculate Jacobian. | -//| USAGE: | -//| 1. User initializes algorithm state with MinLMCreateV() call | -//| 2. User tunes solver parameters with MinLMSetCond(), | -//| MinLMSetStpMax() and other functions | -//| 3. User calls MinLMOptimize() function which takes algorithm | -//| state and callback functions. | -//| 4. User calls MinLMResults() to get solution | -//| 5. Optionally, user may call MinLMRestartFrom() to solve another | -//| problem with same N/M but another starting point and/or | -//| another function. MinLMRestartFrom() allows to reuse already | -//| initialized structure. | -//| INPUT PARAMETERS: | -//| N - dimension, N>1 | -//| * if given, only leading N elements of X are | -//| used | -//| * if not given, automatically determined from | -//| size of X | -//| M - number of functions f[i] | -//| X - initial solution, array[0..N-1] | -//| DiffStep- differentiation step, >0 | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| See also MinLMIteration, MinLMResults. | -//| NOTES: | -//| 1. you may tune stopping conditions with MinLMSetCond() function | -//| 2. if target function contains exp() or other fast growing | -//| functions, and optimization algorithm makes too large steps | -//| which leads to overflow, use MinLMSetStpMax() function to | -//| bound algorithm's steps. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMCreateV(const int m,double &x[],const double diffstep, - CMinLMStateShell &state) - { -//--- create a variable - int n; -//--- initialization - n=CAp::Len(x); -//--- function call - CMinLM::MinLMCreateV(n,m,x,diffstep,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| LEVENBERG-MARQUARDT-LIKE METHOD FOR NON-LINEAR OPTIMIZATION | -//| DESCRIPTION: | -//| This function is used to find minimum of general form (not | -//| "sum-of-squares") function | -//| F = F(x[0], ..., x[n-1]) | -//| using its gradient and Hessian. Levenberg-Marquardt modification | -//| with L-BFGS pre-optimization and internal pre-conditioned L-BFGS | -//| optimization after each Levenberg-Marquardt step is used. | -//| REQUIREMENTS: | -//| This algorithm will request following information during its | -//| operation: | -//| * function value F at given point X | -//| * F and gradient G (simultaneously) at given point X | -//| * F, G and Hessian H (simultaneously) at given point X | -//| There are several overloaded versions of MinLMOptimize() | -//| function which correspond to different LM-like optimization | -//| algorithms provided by this unit. You should choose version which| -//| accepts func(), grad() and hess() function pointers. First | -//| pointer is used to calculate F at given point, second one | -//| calculates F(x) and grad F(x), third one calculates F(x), grad | -//| F(x), hess F(x). | -//| You can try to initialize MinLMState structure with FGH-function | -//| and then use incorrect version of MinLMOptimize() (for example, | -//| version which does not provide Hessian matrix), but it will lead | -//| to exception being thrown after first attempt to calculate | -//| Hessian. | -//| USAGE: | -//| 1. User initializes algorithm state with MinLMCreateFGH() call | -//| 2. User tunes solver parameters with MinLMSetCond(), | -//| MinLMSetStpMax() and other functions | -//| 3. User calls MinLMOptimize() function which takes algorithm | -//| state and pointers (delegates, etc.) to callback functions. | -//| 4. User calls MinLMResults() to get solution | -//| 5. Optionally, user may call MinLMRestartFrom() to solve another | -//| problem with same N but another starting point and/or another | -//| function. MinLMRestartFrom() allows to reuse already | -//| initialized structure. | -//| INPUT PARAMETERS: | -//| N - dimension, N>1 | -//| * if given, only leading N elements of X are | -//| used | -//| * if not given, automatically determined from | -//| size of X | -//| X - initial solution, array[0..N-1] | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTES: | -//| 1. you may tune stopping conditions with MinLMSetCond() function | -//| 2. if target function contains exp() or other fast growing | -//| functions, and optimization algorithm makes too large steps | -//| which leads to overflow, use MinLMSetStpMax() function to | -//| bound algorithm's steps. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMCreateFGH(const int n,double &x[],CMinLMStateShell &state) - { -//--- function call - CMinLM::MinLMCreateFGH(n,x,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| LEVENBERG-MARQUARDT-LIKE METHOD FOR NON-LINEAR OPTIMIZATION | -//| DESCRIPTION: | -//| This function is used to find minimum of general form (not | -//| "sum-of-squares") function | -//| F = F(x[0], ..., x[n-1]) | -//| using its gradient and Hessian. Levenberg-Marquardt modification | -//| with L-BFGS pre-optimization and internal pre-conditioned L-BFGS | -//| optimization after each Levenberg-Marquardt step is used. | -//| REQUIREMENTS: | -//| This algorithm will request following information during its | -//| operation: | -//| * function value F at given point X | -//| * F and gradient G (simultaneously) at given point X | -//| * F, G and Hessian H (simultaneously) at given point X | -//| There are several overloaded versions of MinLMOptimize() | -//| function which correspond to different LM-like optimization | -//| algorithms provided by this unit. You should choose version which| -//| accepts func(), grad() and hess() function pointers. First | -//| pointer is used to calculate F at given point, second one | -//| calculates F(x) and grad F(x), third one calculates F(x), grad | -//| F(x), hess F(x). | -//| You can try to initialize MinLMState structure with FGH-function | -//| and then use incorrect version of MinLMOptimize() (for example, | -//| version which does not provide Hessian matrix), but it will lead | -//| to exception being thrown after first attempt to calculate | -//| Hessian. | -//| USAGE: | -//| 1. User initializes algorithm state with MinLMCreateFGH() call | -//| 2. User tunes solver parameters with MinLMSetCond(), | -//| MinLMSetStpMax() and other functions | -//| 3. User calls MinLMOptimize() function which takes algorithm | -//| state and pointers (delegates, etc.) to callback functions. | -//| 4. User calls MinLMResults() to get solution | -//| 5. Optionally, user may call MinLMRestartFrom() to solve another | -//| problem with same N but another starting point and/or another | -//| function. MinLMRestartFrom() allows to reuse already | -//| initialized structure. | -//| INPUT PARAMETERS: | -//| N - dimension, N>1 | -//| * if given, only leading N elements of X are | -//| used | -//| * if not given, automatically determined from | -//| size of X | -//| X - initial solution, array[0..N-1] | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTES: | -//| 1. you may tune stopping conditions with MinLMSetCond() function | -//| 2. if target function contains exp() or other fast growing | -//| functions, and optimization algorithm makes too large steps | -//| which leads to overflow, use MinLMSetStpMax() function to | -//| bound algorithm's steps. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMCreateFGH(double &x[],CMinLMStateShell &state) - { -//--- create a variable - int n; -//--- initialization - n=CAp::Len(x); -//--- function call - CMinLM::MinLMCreateFGH(n,x,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets stopping conditions for Levenberg-Marquardt | -//| optimization algorithm. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| EpsG - >=0 | -//| The subroutine finishes its work if the | -//| condition |v|=0 | -//| The subroutine finishes its work if on k+1-th | -//| iteration the condition |F(k+1)-F(k)| <= | -//| <= EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. | -//| EpsX - >=0 | -//| The subroutine finishes its work if on k+1-th | -//| iteration the condition |v|<=EpsX is fulfilled, | -//| where: | -//| * |.| means Euclidian norm | -//| * v - scaled step vector, v[i]=dx[i]/s[i] | -//| * dx - ste pvector, dx=X(k+1)-X(k) | -//| * s - scaling coefficients set by MinLMSetScale()| -//| MaxIts - maximum number of iterations. If MaxIts=0, the | -//| number of iterations is unlimited. Only | -//| Levenberg-Marquardt iterations are counted | -//| (L-BFGS/CG iterations are NOT counted because | -//| their cost is very low compared to that of LM). | -//| Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will| -//| lead to automatic stopping criterion selection (small EpsX). | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMSetCond(CMinLMStateShell &state,const double epsg, - const double epsf,const double epsx, - const int maxits) - { -//--- function call - CMinLM::MinLMSetCond(state.GetInnerObj(),epsg,epsf,epsx,maxits); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function turns on/off reporting. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NeedXRep- whether iteration reports are needed or not | -//| If NeedXRep is True, algorithm will call rep() callback function | -//| if it is provided to MinLMOptimize(). Both Levenberg-Marquardt | -//| and internal L-BFGS iterations are reported. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMSetXRep(CMinLMStateShell &state,const bool needxrep) - { -//--- function call - CMinLM::MinLMSetXRep(state.GetInnerObj(),needxrep); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets maximum step length | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| StpMax - maximum step length, >=0. Set StpMax to 0.0, if | -//| you don't want to limit step length. | -//| Use this subroutine when you optimize target function which | -//| contains exp() or other fast growing functions, and optimization | -//| algorithm makes too large steps which leads to overflow. This | -//| function allows us to reject steps that are too large (and | -//| therefore expose us to the possible overflow) without actually | -//| calculating function value at the x+stp*d. | -//| NOTE: non-zero StpMax leads to moderate performance degradation | -//| because intermediate step of preconditioned L-BFGS optimization | -//| is incompatible with limits on step size. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMSetStpMax(CMinLMStateShell &state,const double stpmax) - { -//--- function call - CMinLM::MinLMSetStpMax(state.GetInnerObj(),stpmax); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets scaling coefficients for LM optimizer. | -//| ALGLIB optimizers use scaling matrices to test stopping | -//| conditions (step size and gradient are scaled before comparison | -//| with tolerances). Scale of the I-th variable is a translation | -//| invariant measure of: | -//| a) "how large" the variable is | -//| b) how large the step should be to make significant changes in | -//| the function | -//| Generally, scale is NOT considered to be a form of | -//| preconditioner. But LM optimizer is unique in that it uses | -//| scaling matrix both in the stopping condition tests and as | -//| Marquardt damping factor. | -//| Proper scaling is very important for the algorithm performance. | -//| It is less important for the quality of results, but still has | -//| some influence (it is easier to converge when variables are | -//| properly scaled, so premature stopping is possible when very | -//| badly scalled variables are combined with relaxed stopping | -//| conditions). | -//| INPUT PARAMETERS: | -//| State - structure stores algorithm state | -//| S - array[N], non-zero scaling coefficients | -//| S[i] may be negative, sign doesn't matter. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMSetScale(CMinLMStateShell &state,double &s[]) - { -//--- function call - CMinLM::MinLMSetScale(state.GetInnerObj(),s); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets boundary constraints for LM optimizer | -//| Boundary constraints are inactive by default (after initial | -//| creation). They are preserved until explicitly turned off with | -//| another SetBC() call. | -//| INPUT PARAMETERS: | -//| State - structure stores algorithm state | -//| BndL - lower bounds, array[N]. | -//| If some (all) variables are unbounded, you may | -//| specify very small number or -INF (latter is | -//| recommended because it will allow solver to use | -//| better algorithm). | -//| BndU - upper bounds, array[N]. | -//| If some (all) variables are unbounded, you may | -//| specify very large number or +INF (latter is | -//| recommended because it will allow solver to use | -//| better algorithm). | -//| NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case | -//| I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. | -//| NOTE 2: this solver has following useful properties: | -//| * bound constraints are always satisfied exactly | -//| * function is evaluated only INSIDE area specified by bound | -//| constraints or at its boundary | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMSetBC(CMinLMStateShell &state,double &bndl[], - double &bndu[]) - { -//--- function call - CMinLM::MinLMSetBC(state.GetInnerObj(),bndl,bndu); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function is used to change acceleration settings | -//| You can choose between three acceleration strategies: | -//| * AccType=0, no acceleration. | -//| * AccType=1, secant updates are used to update quadratic model | -//| after each iteration. After fixed number of iterations (or | -//| after model breakdown) we recalculate quadratic model using | -//| analytic Jacobian or finite differences. Number of secant-based| -//| iterations depends on optimization settings: about 3 | -//| iterations - when we have analytic Jacobian, up to 2*N | -//| iterations - when we use finite differences to calculate | -//| Jacobian. | -//| AccType=1 is recommended when Jacobian calculation cost is | -//| prohibitive high (several Mx1 function vector calculations | -//| followed by several NxN Cholesky factorizations are faster than | -//| calculation of one M*N Jacobian). It should also be used when we| -//| have no Jacobian, because finite difference approximation takes | -//| too much time to compute. | -//| Table below list optimization protocols (XYZ protocol corresponds| -//| to MinLMCreateXYZ) and acceleration types they support (and use | -//| by default). | -//| ACCELERATION TYPES SUPPORTED BY OPTIMIZATION PROTOCOLS: | -//| protocol 0 1 comment | -//| V + + | -//| VJ + + | -//| FGH + | -//| DAFAULT VALUES: | -//| protocol 0 1 comment | -//| V x without acceleration it is so slooooooooow | -//| VJ x | -//| FGH x | -//| NOTE: this function should be called before optimization. | -//| Attempt to call it during algorithm iterations may result in | -//| unexpected behavior. | -//| NOTE: attempt to call this function with unsupported | -//| protocol/acceleration combination will result in exception being | -//| thrown. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMSetAccType(CMinLMStateShell &state,const int acctype) - { -//--- function call - CMinLM::MinLMSetAccType(state.GetInnerObj(),acctype); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function provides reverse communication interface | -//| Reverse communication interface is not documented or recommended | -//| to use. | -//| See below for functions which provide better documented API | -//+------------------------------------------------------------------+ -static bool CAlglib::MinLMIteration(CMinLMStateShell &state) - { -//--- return result - return(CMinLM::MinLMIteration(state.GetInnerObj())); - } -//+------------------------------------------------------------------+ -//| This family of functions is used to launcn iterations of | -//| nonlinear optimizer | -//| These functions accept following parameters: | -//| func - callback which calculates function (or merit | -//| function) value func at given point x | -//| grad - callback which calculates function (or merit | -//| function) value func and gradient grad at given | -//| point x | -//| hess - callback which calculates function (or merit | -//| function) value func, gradient grad and Hessian | -//| hess at given point x | -//| fvec - callback which calculates function vector fi[] | -//| at given point x | -//| jac - callback which calculates function vector fi[] | -//| and Jacobian jac at given point x | -//| rep - optional callback which is called after each | -//| iteration can be null | -//| obj - optional object which is passed to | -//| func/grad/hess/jac/rep can be null | -//| NOTES: | -//| 1. Depending on function used to create state structure, this | -//| algorithm may accept Jacobian and/or Hessian and/or gradient. | -//| According to the said above, there ase several versions of | -//| this function, which accept different sets of callbacks. | -//| This flexibility opens way to subtle errors - you may create | -//| state with MinLMCreateFGH() (optimization using Hessian), but | -//| call function which does not accept Hessian. So when | -//| algorithm will request Hessian, there will be no callback to | -//| call. In this case exception will be thrown. | -//| Be careful to avoid such errors because there is no way to | -//| find them at compile time - you can see them at runtime only. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMOptimize(CMinLMStateShell &state,CNDimensional_FVec &fvec, - CNDimensional_Rep &rep,bool rep_status,CObject &obj) - { -//--- cycle - while(CAlglib::MinLMIteration(state)) - { - if(state.GetNeedFI()) - { - fvec.FVec(state.GetInnerObj().m_x,state.GetInnerObj().m_fi,obj); - //--- next iteration - continue; - } - //--- check - if(state.GetInnerObj().m_xupdated) - { - //--- check - if(rep_status) - rep.Rep(state.GetInnerObj().m_x,state.GetInnerObj().m_f,obj); - //--- next iteration - continue; - } - Print("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)"); - CAp::exception_happened=true; - return; - } - } -//+------------------------------------------------------------------+ -//| This family of functions is used to launcn iterations of | -//| nonlinear optimizer | -//| These functions accept following parameters: | -//| func - callback which calculates function (or merit | -//| function) value func at given point x | -//| grad - callback which calculates function (or merit | -//| function) value func and gradient grad at given | -//| point x | -//| hess - callback which calculates function (or merit | -//| function) value func, gradient grad and Hessian | -//| hess at given point x | -//| fvec - callback which calculates function vector fi[] | -//| at given point x | -//| jac - callback which calculates function vector fi[] | -//| and Jacobian jac at given point x | -//| rep - optional callback which is called after each | -//| iteration can be null | -//| obj - optional object which is passed to | -//| func/grad/hess/jac/rep can be null | -//| NOTES: | -//| 1. Depending on function used to create state structure, this | -//| algorithm may accept Jacobian and/or Hessian and/or gradient. | -//| According to the said above, there ase several versions of | -//| this function, which accept different sets of callbacks. | -//| This flexibility opens way to subtle errors - you may create | -//| state with MinLMCreateFGH() (optimization using Hessian), but | -//| call function which does not accept Hessian. So when | -//| algorithm will request Hessian, there will be no callback to | -//| call. In this case exception will be thrown. | -//| Be careful to avoid such errors because there is no way to | -//| find them at compile time - you can see them at runtime only. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMOptimize(CMinLMStateShell &state,CNDimensional_FVec &fvec, - CNDimensional_Jac &jac,CNDimensional_Rep &rep, - bool rep_status,CObject &obj) - { -//--- cycle - while(CAlglib::MinLMIteration(state)) - { - //--- check - if(state.GetNeedFI()) - { - fvec.FVec(state.GetInnerObj().m_x,state.GetInnerObj().m_fi,obj); - //--- next iteration - continue; - } - //--- check - if(state.GetNeedFIJ()) - { - jac.Jac(state.GetInnerObj().m_x,state.GetInnerObj().m_fi,state.GetInnerObj().m_j,obj); - //--- next iteration - continue; - } - //--- check - if(state.GetInnerObj().m_xupdated) - { - //--- check - if(rep_status) - rep.Rep(state.GetInnerObj().m_x,state.GetInnerObj().m_f,obj); - //--- next iteration - continue; - } - Print("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)"); - CAp::exception_happened=true; - return; - } - } -//+------------------------------------------------------------------+ -//| This family of functions is used to launcn iterations of | -//| nonlinear optimizer | -//| These functions accept following parameters: | -//| func - callback which calculates function (or merit | -//| function) value func at given point x | -//| grad - callback which calculates function (or merit | -//| function) value func and gradient grad at given | -//| point x | -//| hess - callback which calculates function (or merit | -//| function) value func, gradient grad and Hessian | -//| hess at given point x | -//| fvec - callback which calculates function vector fi[] | -//| at given point x | -//| jac - callback which calculates function vector fi[] | -//| and Jacobian jac at given point x | -//| rep - optional callback which is called after each | -//| iteration can be null | -//| obj - optional object which is passed to | -//| func/grad/hess/jac/rep can be null | -//| NOTES: | -//| 1. Depending on function used to create state structure, this | -//| algorithm may accept Jacobian and/or Hessian and/or gradient. | -//| According to the said above, there ase several versions of | -//| this function, which accept different sets of callbacks. | -//| This flexibility opens way to subtle errors - you may create | -//| state with MinLMCreateFGH() (optimization using Hessian), but | -//| call function which does not accept Hessian. So when | -//| algorithm will request Hessian, there will be no callback to | -//| call. In this case exception will be thrown. | -//| Be careful to avoid such errors because there is no way to | -//| find them at compile time - you can see them at runtime only. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMOptimize(CMinLMStateShell &state,CNDimensional_Func &func, - CNDimensional_Grad &grad,CNDimensional_Hess &hess, - CNDimensional_Rep &rep,bool rep_status,CObject &obj) - { -//--- cycle - while(CAlglib::MinLMIteration(state)) - { - //--- check - if(state.GetNeedF()) - { - func.Func(state.GetInnerObj().m_x,state.GetInnerObj().m_f,obj); - //--- next iteration - continue; - } - //--- check - if(state.GetNeedFG()) - { - grad.Grad(state.GetInnerObj().m_x,state.GetInnerObj().m_f,state.GetInnerObj().m_g,obj); - //--- next iteration - continue; - } - //--- check - if(state.GetNeedFGH()) - { - hess.Hess(state.GetInnerObj().m_x,state.GetInnerObj().m_f,state.GetInnerObj().m_g,state.GetInnerObj().m_h,obj); - //--- next iteration - continue; - } - //--- check - if(state.GetInnerObj().m_xupdated) - { - //--- check - if(rep_status) - rep.Rep(state.GetInnerObj().m_x,state.GetInnerObj().m_f,obj); - //--- next iteration - continue; - } - Print("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)"); - CAp::exception_happened=true; - return; - } - } -//+------------------------------------------------------------------+ -//| This family of functions is used to launcn iterations of | -//| nonlinear optimizer | -//| These functions accept following parameters: | -//| func - callback which calculates function (or merit | -//| function) value func at given point x | -//| grad - callback which calculates function (or merit | -//| function) value func and gradient grad at given | -//| point x | -//| hess - callback which calculates function (or merit | -//| function) value func, gradient grad and Hessian | -//| hess at given point x | -//| fvec - callback which calculates function vector fi[] | -//| at given point x | -//| jac - callback which calculates function vector fi[] | -//| and Jacobian jac at given point x | -//| rep - optional callback which is called after each | -//| iteration can be null | -//| obj - optional object which is passed to | -//| func/grad/hess/jac/rep can be null | -//| NOTES: | -//| 1. Depending on function used to create state structure, this | -//| algorithm may accept Jacobian and/or Hessian and/or gradient. | -//| According to the said above, there ase several versions of | -//| this function, which accept different sets of callbacks. | -//| This flexibility opens way to subtle errors - you may create | -//| state with MinLMCreateFGH() (optimization using Hessian), but | -//| call function which does not accept Hessian. So when | -//| algorithm will request Hessian, there will be no callback to | -//| call. In this case exception will be thrown. | -//| Be careful to avoid such errors because there is no way to | -//| find them at compile time - you can see them at runtime only. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMOptimize(CMinLMStateShell &state,CNDimensional_Func &func, - CNDimensional_Jac &jac,CNDimensional_Rep &rep, - bool rep_status,CObject &obj) - { -//--- cycle - while(CAlglib::MinLMIteration(state)) - { - //--- check - if(state.GetNeedF()) - { - func.Func(state.GetInnerObj().m_x,state.GetInnerObj().m_f,obj); - //--- next iteration - continue; - } - //--- check - if(state.GetNeedFIJ()) - { - jac.Jac(state.GetInnerObj().m_x,state.GetInnerObj().m_fi,state.GetInnerObj().m_j,obj); - //--- next iteration - continue; - } - //--- check - if(state.GetInnerObj().m_xupdated) - { - //--- check - if(rep_status) - rep.Rep(state.GetInnerObj().m_x,state.GetInnerObj().m_f,obj); - //--- next iteration - continue; - } - Print("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)"); - CAp::exception_happened=true; - return; - } - } -//+------------------------------------------------------------------+ -//| This family of functions is used to launcn iterations of | -//| nonlinear optimizer | -//| These functions accept following parameters: | -//| func - callback which calculates function (or merit | -//| function) value func at given point x | -//| grad - callback which calculates function (or merit | -//| function) value func and gradient grad at given | -//| point x | -//| hess - callback which calculates function (or merit | -//| function) value func, gradient grad and Hessian | -//| hess at given point x | -//| fvec - callback which calculates function vector fi[] | -//| at given point x | -//| jac - callback which calculates function vector fi[] | -//| and Jacobian jac at given point x | -//| rep - optional callback which is called after each | -//| iteration can be null | -//| obj - optional object which is passed to | -//| func/grad/hess/jac/rep can be null | -//| NOTES: | -//| 1. Depending on function used to create state structure, this | -//| algorithm may accept Jacobian and/or Hessian and/or gradient. | -//| According to the said above, there ase several versions of | -//| this function, which accept different sets of callbacks. | -//| This flexibility opens way to subtle errors - you may create | -//| state with MinLMCreateFGH() (optimization using Hessian), but | -//| call function which does not accept Hessian. So when | -//| algorithm will request Hessian, there will be no callback to | -//| call. In this case exception will be thrown. | -//| Be careful to avoid such errors because there is no way to | -//| find them at compile time - you can see them at runtime only. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMOptimize(CMinLMStateShell &state,CNDimensional_Func &func, - CNDimensional_Grad &grad,CNDimensional_Jac &jac, - CNDimensional_Rep &rep,bool rep_status,CObject &obj) - { -//--- cycle - while(CAlglib::MinLMIteration(state)) - { - //--- check - if(state.GetNeedF()) - { - func.Func(state.GetInnerObj().m_x,state.GetInnerObj().m_f,obj); - //--- next iteration - continue; - } - //--- check - if(state.GetNeedFG()) - { - grad.Grad(state.GetInnerObj().m_x,state.GetInnerObj().m_f,state.GetInnerObj().m_g,obj); - //--- next iteration - continue; - } - //--- check - if(state.GetNeedFIJ()) - { - jac.Jac(state.GetInnerObj().m_x,state.GetInnerObj().m_fi,state.GetInnerObj().m_j,obj); - //--- next iteration - continue; - } - //--- check - if(state.GetInnerObj().m_xupdated) - { - //--- check - if(rep_status) - rep.Rep(state.GetInnerObj().m_x,state.GetInnerObj().m_f,obj); - //--- next iteration - continue; - } - Print("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)"); - CAp::exception_happened=true; - return; - } - } -//+------------------------------------------------------------------+ -//| Levenberg-Marquardt algorithm results | -//| INPUT PARAMETERS: | -//| State - algorithm state | -//| OUTPUT PARAMETERS: | -//| X - array[0..N-1], solution | -//| Rep - optimization report; | -//| see comments for this structure for more info. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMResults(CMinLMStateShell &state,double &x[], - CMinLMReportShell &rep) - { -//--- function call - CMinLM::MinLMResults(state.GetInnerObj(),x,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Levenberg-Marquardt algorithm results | -//| Buffered implementation of MinLMResults(), which uses | -//| pre-allocated buffer to store X[]. If buffer size is too small, | -//| it resizes buffer. It is intended to be used in the inner cycles | -//| of performance critical algorithms where array reallocation | -//| penalty is too large to be ignored. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMResultsBuf(CMinLMStateShell &state,double &x[], - CMinLMReportShell &rep) - { -//--- function call - CMinLM::MinLMResultsBuf(state.GetInnerObj(),x,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This subroutine restarts LM algorithm from new point. All | -//| optimization parameters are left unchanged. | -//| This function allows to solve multiple optimization problems | -//| (which must have same number of dimensions) without object | -//| reallocation penalty. | -//| INPUT PARAMETERS: | -//| State - structure used for reverse communication | -//| previously allocated with MinLMCreateXXX call. | -//| X - new starting point. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMRestartFrom(CMinLMStateShell &state,double &x[]) - { -//--- function call - CMinLM::MinLMRestartFrom(state.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This is obsolete function. | -//| Since ALGLIB 3.3 it is equivalent to MinLMCreateVJ(). | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMCreateVGJ(const int n,const int m,double &x[], - CMinLMStateShell &state) - { -//--- function call - CMinLM::MinLMCreateVGJ(n,m,x,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This is obsolete function. | -//| Since ALGLIB 3.3 it is equivalent to MinLMCreateVJ(). | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMCreateVGJ(const int m,double &x[],CMinLMStateShell &state) - { -//--- create a variable - int n; -//--- initialization - n=CAp::Len(x); -//--- function call - CMinLM::MinLMCreateVGJ(n,m,x,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This is obsolete function. | -//| Since ALGLIB 3.3 it is equivalent to MinLMCreateFJ(). | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMCreateFGJ(const int n,const int m,double &x[], - CMinLMStateShell &state) - { -//--- function call - CMinLM::MinLMCreateFGJ(n,m,x,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This is obsolete function. | -//| Since ALGLIB 3.3 it is equivalent to MinLMCreateFJ(). | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMCreateFGJ(const int m,double &x[],CMinLMStateShell &state) - { -//--- create a variable - int n; -//--- initialization - n=CAp::Len(x); -//--- function call - CMinLM::MinLMCreateFGJ(n,m,x,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function is considered obsolete since ALGLIB 3.1.0 and is | -//| present for backward compatibility only. We recommend to use | -//| MinLMCreateVJ, which provides similar, but more consistent and | -//| feature-rich interface. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMCreateFJ(const int n,const int m,double &x[], - CMinLMStateShell &state) - { -//--- function call - CMinLM::MinLMCreateFJ(n,m,x,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function is considered obsolete since ALGLIB 3.1.0 and is | -//| present for backward compatibility only. We recommend to use | -//| MinLMCreateVJ, which provides similar, but more consistent and | -//| feature-rich interface. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLMCreateFJ(const int m,double &x[],CMinLMStateShell &state) - { -//--- create a variable - int n; -//--- initialization - n=CAp::Len(x); -//--- function call - CMinLM::MinLMCreateFJ(n,m,x,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Obsolete function, use MinLBFGSSetPrecDefault() instead. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLBFGSSetDefaultPreconditioner(CMinLBFGSStateShell &state) - { -//--- function call - CMinComp::MinLBFGSSetDefaultPreconditioner(state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Obsolete function, use MinLBFGSSetCholeskyPreconditioner() | -//| instead. | -//+------------------------------------------------------------------+ -static void CAlglib::MinLBFGSSetCholeskyPreconditioner(CMinLBFGSStateShell &state, - CMatrixDouble &p,bool isupper) - { -//--- function call - CMinComp::MinLBFGSSetCholeskyPreconditioner(state.GetInnerObj(),p,isupper); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This is obsolete function which was used by previous version of | -//| the BLEIC optimizer. It does nothing in the current version of | -//| BLEIC. | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICSetBarrierWidth(CMinBLEICStateShell &state, - const double mu) - { -//--- function call - CMinComp::MinBLEICSetBarrierWidth(state.GetInnerObj(),mu); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This is obsolete function which was used by previous version of | -//| the BLEIC optimizer. It does nothing in the current version of | -//| BLEIC. | -//+------------------------------------------------------------------+ -static void CAlglib::MinBLEICSetBarrierDecay(CMinBLEICStateShell &state, - const double mudecay) - { -//--- function call - CMinComp::MinBLEICSetBarrierDecay(state.GetInnerObj(),mudecay); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Obsolete optimization algorithm. | -//| Was replaced by MinBLEIC subpackage. | -//+------------------------------------------------------------------+ -static void CAlglib::MinASACreate(const int n,double &x[],double &bndl[], - double &bndu[],CMinASAStateShell &state) - { -//--- function call - CMinComp::MinASACreate(n,x,bndl,bndu,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Obsolete optimization algorithm. | -//| Was replaced by MinBLEIC subpackage. | -//+------------------------------------------------------------------+ -static void CAlglib::MinASACreate(double &x[],double &bndl[],double &bndu[], - CMinASAStateShell &state) - { -//--- create a variable - int n; -//--- check - if((CAp::Len(x)!=CAp::Len(bndl)) || (CAp::Len(x)!=CAp::Len(bndu))) - { - Print("Error while calling 'minasacreate': looks like one of arguments has wrong size"); - CAp::exception_happened=true; - return; - } -//--- initialization - n=CAp::Len(x); -//--- function call - CMinComp::MinASACreate(n,x,bndl,bndu,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Obsolete optimization algorithm. | -//| Was replaced by MinBLEIC subpackage. | -//+------------------------------------------------------------------+ -static void CAlglib::MinASASetCond(CMinASAStateShell &state,const double epsg, - const double epsf,const double epsx,const int maxits) - { -//--- function call - CMinComp::MinASASetCond(state.GetInnerObj(),epsg,epsf,epsx,maxits); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Obsolete optimization algorithm. | -//| Was replaced by MinBLEIC subpackage. | -//+------------------------------------------------------------------+ -static void CAlglib::MinASASetXRep(CMinASAStateShell &state,const bool needxrep) - { -//--- function call - CMinComp::MinASASetXRep(state.GetInnerObj(),needxrep); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Obsolete optimization algorithm. | -//| Was replaced by MinBLEIC subpackage. | -//+------------------------------------------------------------------+ -static void CAlglib::MinASASetAlgorithm(CMinASAStateShell &state,const int algotype) - { -//--- function call - CMinComp::MinASASetAlgorithm(state.GetInnerObj(),algotype); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Obsolete optimization algorithm. | -//| Was replaced by MinBLEIC subpackage. | -//+------------------------------------------------------------------+ -static void CAlglib::MinASASetStpMax(CMinASAStateShell &state,const double stpmax) - { -//--- function call - CMinComp::MinASASetStpMax(state.GetInnerObj(),stpmax); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function provides reverse communication interface | -//| Reverse communication interface is not documented or recommended | -//| to use. | -//| See below for functions which provide better documented API | -//+------------------------------------------------------------------+ -static bool CAlglib::MinASAIteration(CMinASAStateShell &state) - { -//--- return result - return(CMinComp::MinASAIteration(state.GetInnerObj())); - } -//+------------------------------------------------------------------+ -//| This family of functions is used to launcn iterations of | -//| nonlinear optimizer | -//| These functions accept following parameters: | -//| grad - callback which calculates function (or merit | -//| function) value func and gradient grad at given | -//| point x | -//| rep - optional callback which is called after each | -//| iteration can be null | -//| obj - optional object which is passed to | -//| func/grad/hess/jac/rep can be null | -//+------------------------------------------------------------------+ -static void CAlglib::MinASAOptimize(CMinASAStateShell &state,CNDimensional_Grad &grad, - CNDimensional_Rep &rep,bool rep_status,CObject &obj) - { -//--- cycle - while(CAlglib::MinASAIteration(state)) - { - //--- check - if(state.GetNeedFG()) - { - grad.Grad(state.GetInnerObj().m_x,state.GetInnerObj().m_f,state.GetInnerObj().m_g,obj); - //--- next iteration - continue; - } - //--- check - if(state.GetInnerObj().m_xupdated) - { - //--- check - if(rep_status) - rep.Rep(state.GetInnerObj().m_x,state.GetInnerObj().m_f,obj); - //--- next iteration - continue; - } - Print("ALGLIB: error in 'minasaoptimize' (some derivatives were not provided?)"); - CAp::exception_happened=true; - return; - } - } -//+------------------------------------------------------------------+ -//| Obsolete optimization algorithm. | -//| Was replaced by MinBLEIC subpackage. | -//+------------------------------------------------------------------+ -static void CAlglib::MinASAResults(CMinASAStateShell &state,double &x[], - CMinASAReportShell &rep) - { -//--- function call - CMinComp::MinASAResults(state.GetInnerObj(),x,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Obsolete optimization algorithm. | -//| Was replaced by MinBLEIC subpackage. | -//+------------------------------------------------------------------+ -static void CAlglib::MinASAResultsBuf(CMinASAStateShell &state,double &x[], - CMinASAReportShell &rep) - { -//--- function call - CMinComp::MinASAResultsBuf(state.GetInnerObj(),x,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Obsolete optimization algorithm. | -//| Was replaced by MinBLEIC subpackage. | -//+------------------------------------------------------------------+ -static void CAlglib::MinASARestartFrom(CMinASAStateShell &state,double &x[], - double &bndl[],double &bndu[]) - { -//--- function call - CMinComp::MinASARestartFrom(state.GetInnerObj(),x,bndl,bndu); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Dense solver. | -//| This subroutine solves a system A*x=b, where A is NxN | -//| non-denegerate real matrix, x and b are vectors. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * iterative refinement | -//| * O(N^3) complexity | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| N - size of A | -//| B - array[0..N-1], right part | -//| OUTPUT PARAMETERS | -//| Info - return code: | -//| * -3 A is singular, or VERY close to singular.| -//| X is filled by zeros in such cases. | -//| * -1 N<=0 was passed | -//| * 1 task is solved (but matrix A may be | -//| ill-conditioned, check R1/RInf parameters| -//| for condition numbers). | -//| Rep - solver report, see below for more info | -//| X - array[0..N-1], it contains: | -//| * solution of A*x=b if A is non-singular | -//| (well-conditioned or ill-conditioned, but not | -//| very close to singular) | -//| * zeros, if A is singular or VERY close to | -//| singular (in this case Info=-3). | -//| SOLVER REPORT | -//| Subroutine sets following fields of the Rep structure: | -//| * R1 reciprocal of condition number: 1/cond(A), 1-norm. | -//| * RInf reciprocal of condition number: 1/cond(A), inf-norm. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixSolve(CMatrixDouble &a,const int n,double &b[], - int &info,CDenseSolverReportShell &rep, - double &x[]) - { -//--- initialization - info=0; -//--- function call - CDenseSolver::RMatrixSolve(a,n,b,info,rep.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Dense solver. | -//| Similar to RMatrixSolve() but solves task with multiple right | -//| parts (where b and x are NxM matrices). | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * optional iterative refinement | -//| * O(N^3+M*N^2) complexity | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| N - size of A | -//| B - array[0..N-1,0..M-1], right part | -//| M - right part size | -//| RFS - iterative refinement switch: | -//| * True - refinement is used. | -//| Less performance, more precision. | -//| * False - refinement is not used. | -//| More performance, less precision. | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixSolveM(CMatrixDouble &a,const int n,CMatrixDouble &b, - const int m,const bool rfs,int &info, - CDenseSolverReportShell &rep,CMatrixDouble &x) - { -//--- initialization - info=0; -//--- function call - CDenseSolver::RMatrixSolveM(a,n,b,m,rfs,info,rep.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Dense solver. | -//| This subroutine solves a system A*X=B, where A is NxN | -//| non-denegerate real matrix given by its LU decomposition, X and | -//| B are NxM real matrices. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * O(N^2) complexity | -//| * condition number estimation | -//| No iterative refinement is provided because exact form of | -//| original matrix is not known to subroutine. Use RMatrixSolve or | -//| RMatrixMixedSolve if you need iterative refinement. | -//| INPUT PARAMETERS | -//| LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU| -//| result | -//| P - array[0..N-1], pivots array, RMatrixLU result | -//| N - size of A | -//| B - array[0..N-1], right part | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixLUSolve(CMatrixDouble &lua,int &p[],const int n, - double &b[],int &info, - CDenseSolverReportShell &rep,double &x[]) - {//--- initialization - info=0; -//--- function call - CDenseSolver::RMatrixLUSolve(lua,p,n,b,info,rep.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Dense solver. | -//| Similar to RMatrixLUSolve() but solves task with multiple right | -//| parts (where b and x are NxM matrices). | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * O(M*N^2) complexity | -//| * condition number estimation | -//| No iterative refinement is provided because exact form of | -//| original matrix is not known to subroutine. Use RMatrixSolve or | -//| RMatrixMixedSolve if you need iterative refinement. | -//| INPUT PARAMETERS | -//| LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU| -//| result | -//| P - array[0..N-1], pivots array, RMatrixLU result | -//| N - size of A | -//| B - array[0..N-1,0..M-1], right part | -//| M - right part size | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixLUSolveM(CMatrixDouble &lua,int &p[],const int n, - CMatrixDouble &b,const int m,int &info, - CDenseSolverReportShell &rep,CMatrixDouble &x) - { -//--- initialization - info=0; -//--- function call - CDenseSolver::RMatrixLUSolveM(lua,p,n,b,m,info,rep.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Dense solver. | -//| This subroutine solves a system A*x=b, where BOTH ORIGINAL A AND | -//| ITS LU DECOMPOSITION ARE KNOWN. You can use it if for some | -//| reasons you have both A and its LU decomposition. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * iterative refinement | -//| * O(N^2) complexity | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU| -//| result | -//| P - array[0..N-1], pivots array, RMatrixLU result | -//| N - size of A | -//| B - array[0..N-1], right part | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolveM | -//| Rep - same as in RMatrixSolveM | -//| X - same as in RMatrixSolveM | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixMixedSolve(CMatrixDouble &a,CMatrixDouble &lua, - int &p[],const int n,double &b[], - int &info,CDenseSolverReportShell &rep, - double &x[]) - { -//--- initialization - info=0; -//--- function call - CDenseSolver::RMatrixMixedSolve(a,lua,p,n,b,info,rep.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Dense solver. | -//| Similar to RMatrixMixedSolve() but solves task with multiple | -//| right parts (where b and x are NxM matrices). | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * iterative refinement | -//| * O(M*N^2) complexity | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU| -//| result | -//| P - array[0..N-1], pivots array, RMatrixLU result | -//| N - size of A | -//| B - array[0..N-1,0..M-1], right part | -//| M - right part size | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolveM | -//| Rep - same as in RMatrixSolveM | -//| X - same as in RMatrixSolveM | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixMixedSolveM(CMatrixDouble &a,CMatrixDouble &lua, - int &p[],const int n,CMatrixDouble &b, - const int m,int &info, - CDenseSolverReportShell &rep, - CMatrixDouble &x) - { -//--- initialization - info=0; -//--- function call - CDenseSolver::RMatrixMixedSolveM(a,lua,p,n,b,m,info,rep.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixSolveM(), but for complex matrices. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * iterative refinement | -//| * O(N^3+M*N^2) complexity | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| N - size of A | -//| B - array[0..N-1,0..M-1], right part | -//| M - right part size | -//| RFS - iterative refinement switch: | -//| * True - refinement is used. | -//| Less performance, more precision. | -//| * False - refinement is not used. | -//| More performance, less precision. | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixSolveM(CMatrixComplex &a,const int n,CMatrixComplex &b, - const int m,const bool rfs,int &info, - CDenseSolverReportShell &rep, - CMatrixComplex &x) - { -//--- initialization - info=0; -//--- function call - CDenseSolver::CMatrixSolveM(a,n,b,m,rfs,info,rep.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixSolve(), but for complex matrices. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * iterative refinement | -//| * O(N^3) complexity | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| N - size of A | -//| B - array[0..N-1], right part | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixSolve(CMatrixComplex &a,const int n,al_complex &b[], - int &info,CDenseSolverReportShell &rep, - al_complex &x[]) - { -//--- initialization - info=0; -//--- function call - CDenseSolver::CMatrixSolve(a,n,b,info,rep.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixLUSolveM(), but for complex | -//| matrices. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * O(M*N^2) complexity | -//| * condition number estimation | -//| No iterative refinement is provided because exact form of | -//| original matrix is not known to subroutine. Use CMatrixSolve or | -//| CMatrixMixedSolve if you need iterative refinement. | -//| INPUT PARAMETERS | -//| LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU| -//| result | -//| P - array[0..N-1], pivots array, RMatrixLU result | -//| N - size of A | -//| B - array[0..N-1,0..M-1], right part | -//| M - right part size | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixLUSolveM(CMatrixComplex &lua,int &p[],const int n, - CMatrixComplex &b,const int m,int &info, - CDenseSolverReportShell &rep,CMatrixComplex &x) - { -//--- initialization - info=0; -//--- function call - CDenseSolver::CMatrixLUSolveM(lua,p,n,b,m,info,rep.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixLUSolve(), but for complex matrices.| -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * O(N^2) complexity | -//| * condition number estimation | -//| No iterative refinement is provided because exact form of | -//| original matrix is not known to subroutine. Use CMatrixSolve or | -//| CMatrixMixedSolve if you need iterative refinement. | -//| INPUT PARAMETERS | -//| LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU| -//| result | -//| P - array[0..N-1], pivots array, CMatrixLU result | -//| N - size of A | -//| B - array[0..N-1], right part | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixLUSolve(CMatrixComplex &lua,int &p[],const int n, - al_complex &b[],int &info,CDenseSolverReportShell &rep, - al_complex &x[]) - { -//--- initialization - info=0; -//--- function call - CDenseSolver::CMatrixLUSolve(lua,p,n,b,info,rep.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixMixedSolveM(), but for complex | -//| matrices. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * iterative refinement | -//| * O(M*N^2) complexity | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU| -//| result | -//| P - array[0..N-1], pivots array, CMatrixLU result | -//| N - size of A | -//| B - array[0..N-1,0..M-1], right part | -//| M - right part size | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolveM | -//| Rep - same as in RMatrixSolveM | -//| X - same as in RMatrixSolveM | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixMixedSolveM(CMatrixComplex &a,CMatrixComplex &lua, - int &p[],const int n,CMatrixComplex &b, - const int m,int &info, - CDenseSolverReportShell &rep, - CMatrixComplex &x) - { -//--- initialization - info=0; -//--- function call - CDenseSolver::CMatrixMixedSolveM(a,lua,p,n,b,m,info,rep.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixMixedSolve(), but for complex | -//| matrices. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * iterative refinement | -//| * O(N^2) complexity | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU| -//| result | -//| P - array[0..N-1], pivots array, CMatrixLU result | -//| N - size of A | -//| B - array[0..N-1], right part | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolveM | -//| Rep - same as in RMatrixSolveM | -//| X - same as in RMatrixSolveM | -//+------------------------------------------------------------------+ -static void CAlglib::CMatrixMixedSolve(CMatrixComplex &a,CMatrixComplex &lua, - int &p[],const int n,al_complex &b[], - int &info,CDenseSolverReportShell &rep, - al_complex &x[]) - { -//--- initialization - info=0; -//--- function call - CDenseSolver::CMatrixMixedSolve(a,lua,p,n,b,info,rep.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixSolveM(), but for symmetric positive| -//| definite matrices. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * O(N^3+M*N^2) complexity | -//| * matrix is represented by its upper or lower triangle | -//| No iterative refinement is provided because such partial | -//| representation of matrix does not allow efficient calculation of | -//| extra-precise matrix-vector products for large matrices. Use | -//| RMatrixSolve or RMatrixMixedSolve if you need iterative | -//| refinement. | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| N - size of A | -//| IsUpper - what half of A is provided | -//| B - array[0..N-1,0..M-1], right part | -//| M - right part size | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve. | -//| Returns -3 for non-SPD matrices. | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CAlglib::SPDMatrixSolveM(CMatrixDouble &a,const int n,const bool isupper, - CMatrixDouble &b,const int m,int &info, - CDenseSolverReportShell &rep,CMatrixDouble &x) - { -//--- initialization - info=0; -//--- function call - CDenseSolver::SPDMatrixSolveM(a,n,isupper,b,m,info,rep.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixSolve(), but for SPD matrices. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * O(N^3) complexity | -//| * matrix is represented by its upper or lower triangle | -//| No iterative refinement is provided because such partial | -//| representation of matrix does not allow efficient calculation of | -//| extra-precise matrix-vector products for large matrices. Use | -//| RMatrixSolve or RMatrixMixedSolve if you need iterative | -//| refinement. | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| N - size of A | -//| IsUpper - what half of A is provided | -//| B - array[0..N-1], right part | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Returns -3 for non-SPD matrices. | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CAlglib::SPDMatrixSolve(CMatrixDouble &a,const int n,const bool isupper, - double &b[],int &info,CDenseSolverReportShell &rep, - double &x[]) - { -//--- initialization - info=0; -//--- function call - CDenseSolver::SPDMatrixSolve(a,n,isupper,b,info,rep.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixLUSolveM(), but for SPD matrices | -//| represented by their Cholesky decomposition. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * O(M*N^2) complexity | -//| * condition number estimation | -//| * matrix is represented by its upper or lower triangle | -//| No iterative refinement is provided because such partial | -//| representation of matrix does not allow efficient calculation of | -//| extra-precise matrix-vector products for large matrices. Use | -//| RMatrixSolve or RMatrixMixedSolve if you need iterative | -//| refinement. | -//| INPUT PARAMETERS | -//| CHA - array[0..N-1,0..N-1], Cholesky decomposition, | -//| SPDMatrixCholesky result | -//| N - size of CHA | -//| IsUpper - what half of CHA is provided | -//| B - array[0..N-1,0..M-1], right part | -//| M - right part size | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CAlglib::SPDMatrixCholeskySolveM(CMatrixDouble &cha,const int n, - const bool isupper,CMatrixDouble &b, - const int m,int &info, - CDenseSolverReportShell &rep, - CMatrixDouble &x) - { -//--- initialization - info=0; -//--- function call - CDenseSolver::SPDMatrixCholeskySolveM(cha,n,isupper,b,m,info,rep.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixLUSolve(), but for SPD matrices | -//| represented by their Cholesky decomposition. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * O(N^2) complexity | -//| * condition number estimation | -//| * matrix is represented by its upper or lower triangle | -//| No iterative refinement is provided because such partial | -//| representation of matrix does not allow efficient calculation of | -//| extra-precise matrix-vector products for large matrices. Use | -//| RMatrixSolve or RMatrixMixedSolve if you need iterative | -//| refinement. | -//| INPUT PARAMETERS | -//| CHA - array[0..N-1,0..N-1], Cholesky decomposition, | -//| SPDMatrixCholesky result | -//| N - size of A | -//| IsUpper - what half of CHA is provided | -//| B - array[0..N-1], right part | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CAlglib::SPDMatrixCholeskySolve(CMatrixDouble &cha,const int n, - const bool isupper,double &b[], - int &info,CDenseSolverReportShell &rep, - double &x[]) - { -//--- initialization - info=0; -//--- function call - CDenseSolver::SPDMatrixCholeskySolve(cha,n,isupper,b,info,rep.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixSolveM(), but for Hermitian positive| -//| definite matrices. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * O(N^3+M*N^2) complexity | -//| * matrix is represented by its upper or lower triangle | -//| No iterative refinement is provided because such partial | -//| representation of matrix does not allow efficient calculation of | -//| extra-precise matrix-vector products for large matrices. Use | -//| RMatrixSolve or RMatrixMixedSolve if you need iterative | -//| refinement. | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| N - size of A | -//| IsUpper - what half of A is provided | -//| B - array[0..N-1,0..M-1], right part | -//| M - right part size | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve. | -//| Returns -3 for non-HPD matrices. | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CAlglib::HPDMatrixSolveM(CMatrixComplex &a,const int n,const bool isupper, - CMatrixComplex &b,const int m,int &info, - CDenseSolverReportShell &rep,CMatrixComplex &x) - { -//--- initialization - info=0; -//--- function call - CDenseSolver::HPDMatrixSolveM(a,n,isupper,b,m,info,rep.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixSolve(), but for Hermitian positive | -//| definite matrices. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * O(N^3) complexity | -//| * matrix is represented by its upper or lower triangle | -//| No iterative refinement is provided because such partial | -//| representation of matrix does not allow efficient calculation of | -//| extra-precise matrix-vector products for large matrices. Use | -//| RMatrixSolve or RMatrixMixedSolve if you need iterative | -//| refinement. | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| N - size of A | -//| IsUpper - what half of A is provided | -//| B - array[0..N-1], right part | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Returns -3 for non-HPD matrices. | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CAlglib::HPDMatrixSolve(CMatrixComplex &a,const int n, - const bool isupper,al_complex &b[], - int &info,CDenseSolverReportShell &rep, - al_complex &x[]) - { -//--- initialization - info=0; -//--- function call - CDenseSolver::HPDMatrixSolve(a,n,isupper,b,info,rep.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixLUSolveM(), but for HPD matrices | -//| represented by their Cholesky decomposition. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * O(M*N^2) complexity | -//| * condition number estimation | -//| * matrix is represented by its upper or lower triangle | -//| No iterative refinement is provided because such partial | -//| representation of matrix does not allow efficient calculation of | -//| extra-precise matrix-vector products for large matrices. Use | -//| RMatrixSolve or RMatrixMixedSolve if you need iterative | -//| refinement. | -//| INPUT PARAMETERS | -//| CHA - array[0..N-1,0..N-1], Cholesky decomposition, | -//| HPDMatrixCholesky result | -//| N - size of CHA | -//| IsUpper - what half of CHA is provided | -//| B - array[0..N-1,0..M-1], right part | -//| M - right part size | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CAlglib::HPDMatrixCholeskySolveM(CMatrixComplex &cha,const int n, - const bool isupper,CMatrixComplex &b, - const int m,int &info, - CDenseSolverReportShell &rep, - CMatrixComplex &x) - { -//--- initialization - info=0; -//--- function call - CDenseSolver::HPDMatrixCholeskySolveM(cha,n,isupper,b,m,info,rep.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixLUSolve(), but for HPD matrices | -//| represented by their Cholesky decomposition. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * O(N^2) complexity | -//| * condition number estimation | -//| * matrix is represented by its upper or lower triangle | -//| No iterative refinement is provided because such partial | -//| representation of matrix does not allow efficient calculation of | -//| extra-precise matrix-vector products for large matrices. Use | -//| RMatrixSolve or RMatrixMixedSolve if you need iterative | -//| refinement. | -//| INPUT PARAMETERS | -//| CHA - array[0..N-1,0..N-1], Cholesky decomposition, | -//| SPDMatrixCholesky result | -//| N - size of A | -//| IsUpper - what half of CHA is provided | -//| B - array[0..N-1], right part | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CAlglib::HPDMatrixCholeskySolve(CMatrixComplex &cha,const int n, - const bool isupper,al_complex &b[], - int &info,CDenseSolverReportShell &rep, - al_complex &x[]) - { -//--- initialization - info=0; -//--- function call - CDenseSolver::HPDMatrixCholeskySolve(cha,n,isupper,b,info,rep.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Dense solver. | -//| This subroutine finds solution of the linear system A*X=B with | -//| non-square, possibly degenerate A. System is solved in the least | -//| squares sense, and general least squares solution X = X0 + CX*y | -//| which minimizes |A*X-B| is returned. If A is non-degenerate, | -//| solution in the usual sense is returned | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * iterative refinement | -//| * O(N^3) complexity | -//| INPUT PARAMETERS | -//| A - array[0..NRows-1,0..NCols-1], system matrix | -//| NRows - vertical size of A | -//| NCols - horizontal size of A | -//| B - array[0..NCols-1], right part | -//| Threshold- a number in [0,1]. Singular values beyond | -//| Threshold are considered zero. Set it to 0.0, | -//| if you don't understand what it means, so the | -//| solver will choose good value on its own. | -//| OUTPUT PARAMETERS | -//| Info - return code: | -//| * -4 SVD subroutine failed | -//| * -1 if NRows<=0 or NCols<=0 or Threshold<0 | -//| was passed | -//| * 1 if task is solved | -//| Rep - solver report, see below for more info | -//| X - array[0..N-1,0..M-1], it contains: | -//| * solution of A*X=B if A is non-singular | -//| (well-conditioned or ill-conditioned, but not | -//| very close to singular) | -//| * zeros, if A is singular or VERY close to | -//| singular (in this case Info=-3). | -//| SOLVER REPORT | -//| Subroutine sets following fields of the Rep structure: | -//| * R2 reciprocal of condition number: 1/cond(A), 2-norm. | -//| * N = NCols | -//| * K dim(Null(A)) | -//| * CX array[0..N-1,0..K-1], kernel of A. | -//| Columns of CX store such vectors that A*CX[i]=0. | -//+------------------------------------------------------------------+ -static void CAlglib::RMatrixSolveLS(CMatrixDouble &a,const int nrows, - const int ncols,double &b[], - const double threshold,int &info, - CDenseSolverLSReportShell &rep, - double &x[]) - { -//--- initialization - info=0; -//--- function call - CDenseSolver::RMatrixSolveLS(a,nrows,ncols,b,threshold,info,rep.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| LEVENBERG-MARQUARDT-LIKE NONLINEAR SOLVER | -//| DESCRIPTION: | -//| This algorithm solves system of nonlinear equations | -//| F[0](x[0], ..., x[n-1]) = 0 | -//| F[1](x[0], ..., x[n-1]) = 0 | -//| ... | -//| F[M-1](x[0], ..., x[n-1]) = 0 | -//| with M/N do not necessarily coincide. Algorithm converges | -//| quadratically under following conditions: | -//| * the solution set XS is nonempty | -//| * for some xs in XS there exist such neighbourhood N(xs) | -//| that: | -//| * vector function F(x) and its Jacobian J(x) are | -//| continuously differentiable on N | -//| * ||F(x)|| provides local error bound on N, i.e. there | -//| exists such c1, that ||F(x)||>c1*distance(x,XS) | -//| Note that these conditions are much more weaker than usual | -//| non-singularity conditions. For example, algorithm will converge | -//| for any affine function F (whether its Jacobian singular or not).| -//| REQUIREMENTS: | -//| Algorithm will request following information during its | -//| operation: | -//| * function vector F[] and Jacobian matrix at given point X | -//| * value of merit function f(x)=F[0]^2(x)+...+F[M-1]^2(x) at given| -//| point X | -//| USAGE: | -//| 1. User initializes algorithm state with NLEQCreateLM() call | -//| 2. User tunes solver parameters with NLEQSetCond(), | -//| NLEQSetStpMax() and other functions | -//| 3. User calls NLEQSolve() function which takes algorithm state | -//| and pointers (delegates, etc.) to callback functions which | -//| calculate merit function value and Jacobian. | -//| 4. User calls NLEQResults() to get solution | -//| 5. Optionally, user may call NLEQRestartFrom() to solve another | -//| problem with same parameters (N/M) but another starting point | -//| and/or another function vector. NLEQRestartFrom() allows to | -//| reuse already initialized structure. | -//| INPUT PARAMETERS: | -//| N - space dimension, N>1: | -//| * if provided, only leading N elements of X are | -//| used | -//| * if not provided, determined automatically from | -//| size of X | -//| M - system size | -//| X - starting point | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTES: | -//| 1. you may tune stopping conditions with NLEQSetCond() function | -//| 2. if target function contains exp() or other fast growing | -//| functions, and optimization algorithm makes too large steps | -//| which leads to overflow, use NLEQSetStpMax() function to bound| -//| algorithm's steps. | -//| 3. this algorithm is a slightly modified implementation of the | -//| method described in 'Levenberg-Marquardt method for | -//| constrained nonlinear equations with strong local convergence | -//| properties' by Christian Kanzow Nobuo Yamashita and Masao | -//| Fukushima and further developed in 'On the convergence of a | -//| New Levenberg-Marquardt Method' by Jin-yan Fan and Ya-Xiang | -//| Yuan. | -//+------------------------------------------------------------------+ -static void CAlglib::NlEqCreateLM(const int n,const int m,double &x[], - CNlEqStateShell &state) - { -//--- function call - CNlEq::NlEqCreateLM(n,m,x,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| LEVENBERG-MARQUARDT-LIKE NONLINEAR SOLVER | -//| DESCRIPTION: | -//| This algorithm solves system of nonlinear equations | -//| F[0](x[0], ..., x[n-1]) = 0 | -//| F[1](x[0], ..., x[n-1]) = 0 | -//| ... | -//| F[M-1](x[0], ..., x[n-1]) = 0 | -//| with M/N do not necessarily coincide. Algorithm converges | -//| quadratically under following conditions: | -//| * the solution set XS is nonempty | -//| * for some xs in XS there exist such neighbourhood N(xs) | -//| that: | -//| * vector function F(x) and its Jacobian J(x) are | -//| continuously differentiable on N | -//| * ||F(x)|| provides local error bound on N, i.e. there | -//| exists such c1, that ||F(x)||>c1*distance(x,XS) | -//| Note that these conditions are much more weaker than usual | -//| non-singularity conditions. For example, algorithm will converge | -//| for any affine function F (whether its Jacobian singular or not).| -//| REQUIREMENTS: | -//| Algorithm will request following information during its | -//| operation: | -//| * function vector F[] and Jacobian matrix at given point X | -//| * value of merit function f(x)=F[0]^2(x)+...+F[M-1]^2(x) at given| -//| point X | -//| USAGE: | -//| 1. User initializes algorithm state with NLEQCreateLM() call | -//| 2. User tunes solver parameters with NLEQSetCond(), | -//| NLEQSetStpMax() and other functions | -//| 3. User calls NLEQSolve() function which takes algorithm state | -//| and pointers (delegates, etc.) to callback functions which | -//| calculate merit function value and Jacobian. | -//| 4. User calls NLEQResults() to get solution | -//| 5. Optionally, user may call NLEQRestartFrom() to solve another | -//| problem with same parameters (N/M) but another starting point | -//| and/or another function vector. NLEQRestartFrom() allows to | -//| reuse already initialized structure. | -//| INPUT PARAMETERS: | -//| N - space dimension, N>1: | -//| * if provided, only leading N elements of X are | -//| used | -//| * if not provided, determined automatically from | -//| size of X | -//| M - system size | -//| X - starting point | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTES: | -//| 1. you may tune stopping conditions with NLEQSetCond() function | -//| 2. if target function contains exp() or other fast growing | -//| functions, and optimization algorithm makes too large steps | -//| which leads to overflow, use NLEQSetStpMax() function to bound| -//| algorithm's steps. | -//| 3. this algorithm is a slightly modified implementation of the | -//| method described in 'Levenberg-Marquardt method for | -//| constrained nonlinear equations with strong local convergence | -//| properties' by Christian Kanzow Nobuo Yamashita and Masao | -//| Fukushima and further developed in 'On the convergence of a | -//| New Levenberg-Marquardt Method' by Jin-yan Fan and Ya-Xiang | -//| Yuan. | -//+------------------------------------------------------------------+ -static void CAlglib::NlEqCreateLM(const int m,double &x[],CNlEqStateShell &state) - { -//--- create a variable - int n; -//--- initialization - n=CAp::Len(x); -//--- function call - CNlEq::NlEqCreateLM(n,m,x,state.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets stopping conditions for the nonlinear solver | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| EpsF - >=0 | -//| The subroutine finishes its work if on k+1-th | -//| iteration the condition ||F||<=EpsF is satisfied | -//| MaxIts - maximum number of iterations. If MaxIts=0, the | -//| number of iterations is unlimited. | -//| Passing EpsF=0 and MaxIts=0 simultaneously will lead to | -//| automatic stopping criterion selection (small EpsF). | -//| NOTES: | -//+------------------------------------------------------------------+ -static void CAlglib::NlEqSetCond(CNlEqStateShell &state,const double epsf, - const int maxits) - { -//--- function call - CNlEq::NlEqSetCond(state.GetInnerObj(),epsf,maxits); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function turns on/off reporting. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NeedXRep- whether iteration reports are needed or not | -//| If NeedXRep is True, algorithm will call rep() callback function | -//| if it is provided to NLEQSolve(). | -//+------------------------------------------------------------------+ -static void CAlglib::NlEqSetXRep(CNlEqStateShell &state,const bool needxrep) - { -//--- function call - CNlEq::NlEqSetXRep(state.GetInnerObj(),needxrep); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function sets maximum step length | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| StpMax - maximum step length, >=0. Set StpMax to 0.0, if | -//| you don't want to limit step length. | -//| Use this subroutine when target function contains exp() or other | -//| fast growing functions, and algorithm makes too large steps which| -//| lead to overflow. This function allows us to reject steps that | -//| are too large (and therefore expose us to the possible overflow) | -//| without actually calculating function value at the x+stp*d. | -//+------------------------------------------------------------------+ -static void CAlglib::NlEqSetStpMax(CNlEqStateShell &state,const double stpmax) - { -//--- function call - CNlEq::NlEqSetStpMax(state.GetInnerObj(),stpmax); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This function provides reverse communication interface | -//| Reverse communication interface is not documented or recommended | -//| to use. | -//| See below for functions which provide better documented API | -//+------------------------------------------------------------------+ -static bool CAlglib::NlEqIteration(CNlEqStateShell &state) - { -//--- return result - return(CNlEq::NlEqIteration(state.GetInnerObj())); - } -//+------------------------------------------------------------------+ -//| This family of functions is used to launcn iterations of | -//| nonlinear solver | -//| These functions accept following parameters: | -//| func - callback which calculates function (or merit | -//| function) value func at given point x | -//| jac - callback which calculates function vector fi[] | -//| and Jacobian jac at given point x | -//| rep - optional callback which is called after each | -//| iteration can be null | -//| obj - optional object which is passed to | -//| func/grad/hess/jac/rep can be null | -//+------------------------------------------------------------------+ -static void CAlglib::NlEqSolve(CNlEqStateShell &state,CNDimensional_Func &func, - CNDimensional_Jac &jac,CNDimensional_Rep &rep, - bool rep_status,CObject &obj) - { -//--- cycle - while(CAlglib::NlEqIteration(state)) - { - //--- check - if(state.GetNeedF()) - { - func.Func(state.GetInnerObj().m_x,state.GetInnerObj().m_f,obj); - //--- next iteration - continue; - } - //--- check - if(state.GetNeedFIJ()) - { - jac.Jac(state.GetInnerObj().m_x,state.GetInnerObj().m_fi,state.GetInnerObj().m_j,obj); - //--- next iteration - continue; - } - //--- check - if(state.GetInnerObj().m_xupdated) - { - //--- check - if(rep_status) - rep.Rep(state.GetInnerObj().m_x,state.GetInnerObj().m_f,obj); - //--- next iteration - continue; - } - Print("ALGLIB: error in 'nleqsolve' (some derivatives were not provided?)"); - CAp::exception_happened=true; - return; - } - } -//+------------------------------------------------------------------+ -//| NLEQ solver results | -//| INPUT PARAMETERS: | -//| State - algorithm state. | -//| OUTPUT PARAMETERS: | -//| X - array[0..N-1], solution | -//| Rep - optimization report: | -//| * Rep.TerminationType completetion code: | -//| * -4 ERROR: algorithm has converged to the| -//| stationary point Xf which is local | -//| minimum of f=F[0]^2+...+F[m-1]^2, | -//| but is not solution of nonlinear | -//| system. | -//| * 1 sqrt(f)<=EpsF. | -//| * 5 MaxIts steps was taken | -//| * 7 stopping conditions are too | -//| stringent, further improvement is | -//| impossible | -//| * Rep.IterationsCount contains iterations count | -//| * NFEV countains number of function calculations | -//| * ActiveConstraints contains number of active | -//| constraints | -//+------------------------------------------------------------------+ -static void CAlglib::NlEqResults(CNlEqStateShell &state,double &x[], - CNlEqReportShell &rep) - { -//--- function call - CNlEq::NlEqResults(state.GetInnerObj(),x,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| NLEQ solver results | -//| Buffered implementation of NLEQResults(), which uses | -//| pre-allocated buffer to store X[]. If buffer size is too small, | -//| it resizes buffer. It is intended to be used in the inner cycles | -//| of performance critical algorithms where array reallocation | -//| penalty is too large to be ignored. | -//+------------------------------------------------------------------+ -static void CAlglib::NlEqResultsBuf(CNlEqStateShell &state,double &x[], - CNlEqReportShell &rep) - { -//--- function call - CNlEq::NlEqResultsBuf(state.GetInnerObj(),x,rep.GetInnerObj()); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This subroutine restarts CG algorithm from new point. All | -//| optimization parameters are left unchanged. | -//| This function allows to solve multiple optimization problems | -//| (which must have same number of dimensions) without object | -//| reallocation penalty. | -//| INPUT PARAMETERS: | -//| State - structure used for reverse communication | -//| previously allocated with MinCGCreate call. | -//| X - new starting point. | -//| BndL - new lower bounds | -//| BndU - new upper bounds | -//+------------------------------------------------------------------+ -static void CAlglib::NlEqRestartFrom(CNlEqStateShell &state,double &x[]) - { -//--- function call - CNlEq::NlEqRestartFrom(state.GetInnerObj(),x); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Gamma function | -//| Input parameters: | -//| X - argument | -//| Domain: | -//| 0 < X < 171.6 | -//| -170 < X < 0, X is not an integer. | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE -170,-33 20000 2.3e-15 3.3e-16 | -//| IEEE -33, 33 20000 9.4e-16 2.2e-16 | -//| IEEE 33, 171.6 20000 2.3e-15 3.2e-16 | -//+------------------------------------------------------------------+ -static double CAlglib::GammaFunction(const double x) - { -//--- return result - return(CGammaFunc::GammaFunc(x)); - } -//+------------------------------------------------------------------+ -//| Natural logarithm of gamma function | -//| Input parameters: | -//| X - argument | -//| Result: | -//| logarithm of the absolute value of the Gamma(X). | -//| Output parameters: | -//| SgnGam - sign(Gamma(X)) | -//| Domain: | -//| 0 < X < 2.55e305 | -//| -2.55e305 < X < 0, X is not an integer. | -//| ACCURACY: | -//| arithmetic domain # trials peak rms | -//| IEEE 0, 3 28000 5.4e-16 1.1e-16 | -//| IEEE 2.718, 2.556e305 40000 3.5e-16 8.3e-17 | -//| The error criterion was relative when the function magnitude | -//| was greater than one but absolute when it was less than one. | -//| The following test used the relative error criterion, though | -//| at certain points the relative error could be much higher than | -//| indicated. | -//| IEEE -200, -4 10000 4.8e-16 1.3e-16 | -//+------------------------------------------------------------------+ -static double CAlglib::LnGamma(const double x,double &sgngam) - { -//--- initialization - sgngam=0; -//--- return result - return(CGammaFunc::LnGamma(x,sgngam)); - } -//+------------------------------------------------------------------+ -//| Error function | -//| The integral is | -//| x | -//| - | -//| 2 | | 2 | -//| erf(x) = -------- | exp( - t ) dt. | -//| sqrt(pi) | | | -//| - | -//| 0 | -//| For 0 <= |x| < 1, erf(x) = x * P4(x**2)/Q5(x**2); otherwise | -//| erf(x) = 1 - erfc(x). | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0,1 30000 3.7e-16 1.0e-16 | -//+------------------------------------------------------------------+ -static double CAlglib::ErrorFunction(const double x) - { -//--- return result - return(CNormalDistr::ErrorFunction(x)); - } -//+------------------------------------------------------------------+ -//| Complementary error function | -//| 1 - erf(x) = | -//| inf. | -//| - | -//| 2 | | 2 | -//| erfc(x) = -------- | exp( - t ) dt | -//| sqrt(pi) | | | -//| - | -//| x | -//| For small x, erfc(x) = 1 - erf(x); otherwise rational | -//| approximations are computed. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0,26.6417 30000 5.7e-14 1.5e-14 | -//+------------------------------------------------------------------+ -static double CAlglib::ErrorFunctionC(const double x) - { -//--- return result - return(CNormalDistr::ErrorFunctionC(x)); - } -//+------------------------------------------------------------------+ -//| Normal distribution function | -//| Returns the area under the Gaussian probability density | -//| function, integrated from minus infinity to x: | -//| x | -//| - | -//| 1 | | 2 | -//| ndtr(x) = --------- | exp( - t /2 ) dt | -//| sqrt(2pi) | | | -//| - | -//| -inf. | -//| = ( 1 + erf(z) ) / 2 | -//| = erfc(z) / 2 | -//| where z = x/sqrt(2). Computation is via the functions | -//| erf and erfc. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE -13,0 30000 3.4e-14 6.7e-15 | -//+------------------------------------------------------------------+ -static double CAlglib::NormalDistribution(const double x) - { -//--- return result - return(CNormalDistr::NormalDistribution(x)); - } -//+------------------------------------------------------------------+ -//| Inverse of the error function | -//+------------------------------------------------------------------+ -static double CAlglib::InvErF(double e) - { -//--- return result - return(CNormalDistr::InvErF(e)); - } -//+------------------------------------------------------------------+ -//| Inverse of Normal distribution function | -//| Returns the argument, x, for which the area under the | -//| Gaussian probability density function (integrated from | -//| minus infinity to x) is equal to y. | -//| For small arguments 0 < y < exp(-2), the program computes | -//| z = sqrt( -2.0 * log(y) ); then the approximation is | -//| x = z - log(z)/z - (1/z) P(1/z) / Q(1/z). | -//| There are two rational functions P/Q, one for 0 < y < exp(-32) | -//| and the other for y up to exp(-2). For larger arguments, | -//| w = y - 0.5, and x/sqrt(2pi) = w + w**3 R(w**2)/S(w**2)). | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0.125, 1 20000 7.2e-16 1.3e-16 | -//| IEEE 3e-308, 0.135 50000 4.6e-16 9.8e-17 | -//+------------------------------------------------------------------+ -static double CAlglib::InvNormalDistribution(const double y0) - { -//--- return result - return(CNormalDistr::InvNormalDistribution(y0)); - } -//+------------------------------------------------------------------+ -//| Incomplete gamma integral | -//| The function is defined by | -//| x | -//| - | -//| 1 | | -t a-1 | -//| igam(a,x) = ----- | e t dt. | -//| - | | | -//| | (a) - | -//| 0 | -//| In this implementation both arguments must be positive. | -//| The integral is evaluated by either a power series or | -//| continued fraction expansion, depending on the relative | -//| values of a and x. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0,30 200000 3.6e-14 2.9e-15 | -//| IEEE 0,100 300000 9.9e-14 1.5e-14 | -//+------------------------------------------------------------------+ -static double CAlglib::IncompleteGamma(const double a,const double x) - { -//--- return result - return(CIncGammaF::IncompleteGamma(a,x)); - } -//+------------------------------------------------------------------+ -//| Complemented incomplete gamma integral | -//| The function is defined by | -//| igamc(a,x) = 1 - igam(a,x) | -//| inf. | -//| - | -//| 1 | | -t a-1 | -//| = ----- | e t dt. | -//| - | | | -//| | (a) - | -//| x | -//| In this implementation both arguments must be positive. | -//| The integral is evaluated by either a power series or | -//| continued fraction expansion, depending on the relative | -//| values of a and x. | -//| ACCURACY: | -//| Tested at random a, x. | -//| a x Relative error: | -//| arithmetic domain domain # trials peak rms | -//| IEEE 0.5,100 0,100 200000 1.9e-14 1.7e-15| -//| IEEE 0.01,0.5 0,100 200000 1.4e-13 1.6e-15| -//+------------------------------------------------------------------+ -static double CAlglib::IncompleteGammaC(const double a,const double x) - { -//--- return result - return(CIncGammaF::IncompleteGammaC(a,x)); - } -//+------------------------------------------------------------------+ -//| Inverse of complemented imcomplete gamma integral | -//| Given p, the function finds x such that | -//| igamc( a, x ) = p. | -//| Starting with the approximate value | -//| 3 | -//| x = a t | -//| where | -//| t = 1 - d - ndtri(p) sqrt(d) | -//| and | -//| d = 1/9a, | -//| the routine performs up to 10 Newton iterations to find the | -//| root of igamc(a,x) - p = 0. | -//| ACCURACY: | -//| Tested at random a, p in the intervals indicated. | -//| a p Relative error: | -//| arithmetic domain domain # trials peak rms | -//| IEEE 0.5,100 0,0.5 100000 1.0e-14 1.7e-15| -//| IEEE 0.01,0.5 0,0.5 100000 9.0e-14 3.4e-15| -//| IEEE 0.5,10000 0,0.5 20000 2.3e-13 3.8e-14| -//+------------------------------------------------------------------+ -static double CAlglib::InvIncompleteGammaC(const double a,const double y0) - { -//--- return result - return(CIncGammaF::InvIncompleteGammaC(a,y0)); - } -//+------------------------------------------------------------------+ -//| Airy function | -//| Solution of the differential equation | -//| y"(x) = xy. | -//| The function returns the two independent solutions Ai, Bi | -//| and their first derivatives Ai'(x), Bi'(x). | -//| Evaluation is by power series summation for small x, | -//| by rational minimax approximations for large x. | -//| ACCURACY: | -//| Error criterion is absolute when function <= 1, relative | -//| when function > 1, except * denotes relative error criterion. | -//| For large negative x, the absolute error increases as x^1.5. | -//| For large positive x, the relative error increases as x^1.5. | -//| Arithmetic domain function # trials peak rms | -//| IEEE -10, 0 Ai 10000 1.6e-15 2.7e-16 | -//| IEEE 0, 10 Ai 10000 2.3e-14* 1.8e-15*| -//| IEEE -10, 0 Ai' 10000 4.6e-15 7.6e-16 | -//| IEEE 0, 10 Ai' 10000 1.8e-14* 1.5e-15*| -//| IEEE -10, 10 Bi 30000 4.2e-15 5.3e-16 | -//| IEEE -10, 10 Bi' 30000 4.9e-15 7.3e-16 | -//+------------------------------------------------------------------+ -static void CAlglib::Airy(const double x,double &ai,double &aip,double &bi, - double &bip) - { -//--- create variables - ai=0; - aip=0; - bi=0; - bip=0; -//--- function call - CAiryF::Airy(x,ai,aip,bi,bip); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Bessel function of order zero | -//| Returns Bessel function of order zero of the argument. | -//| The domain is divided into the intervals [0, 5] and | -//| (5, infinity). In the first interval the following rational | -//| approximation is used: | -//| 2 2 | -//| (w - r ) (w - r ) P (w) / Q (w) | -//| 1 2 3 8 | -//| 2 | -//| where w = x and the two r's are zeros of the function. | -//| In the second interval, the Hankel asymptotic expansion | -//| is employed with two rational functions of degree 6/6 | -//| and 7/7. | -//| ACCURACY: | -//| Absolute error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0, 30 60000 4.2e-16 1.1e-16 | -//+------------------------------------------------------------------+ -static double CAlglib::BesselJ0(const double x) - { -//--- return result - return(CBessel::BesselJ0(x)); - } -//+------------------------------------------------------------------+ -//| Bessel function of order one | -//| Returns Bessel function of order one of the argument. | -//| The domain is divided into the intervals [0, 8] and | -//| (8, infinity). In the first interval a 24 term Chebyshev | -//| expansion is used. In the second, the asymptotic | -//| trigonometric representation is employed using two | -//| rational functions of degree 5/5. | -//| ACCURACY: | -//| Absolute error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0, 30 30000 2.6e-16 1.1e-16 | -//+------------------------------------------------------------------+ -static double CAlglib::BesselJ1(const double x) - { -//--- return result - return(CBessel::BesselJ1(x)); - } -//+------------------------------------------------------------------+ -//| Bessel function of integer order | -//| Returns Bessel function of order n, where n is a | -//| (possibly negative) integer. | -//| The ratio of jn(x) to j0(x) is computed by backward | -//| recurrence. First the ratio jn/jn-1 is found by a | -//| continued fraction expansion. Then the recurrence | -//| relating successive orders is applied until j0 or j1 is | -//| reached. | -//| If n = 0 or 1 the routine for j0 or j1 is called | -//| directly. | -//| ACCURACY: | -//| Absolute error: | -//| arithmetic range # trials peak rms | -//| IEEE 0, 30 5000 4.4e-16 7.9e-17 | -//| Not suitable for large n or x. Use jv() (fractional order) | -//| instead. | -//+------------------------------------------------------------------+ -static double CAlglib::BesselJN(const int n,const double x) - { -//--- return result - return(CBessel::BesselJN(n,x)); - } -//+------------------------------------------------------------------+ -//| Bessel function of the second kind, order zero | -//| Returns Bessel function of the second kind, of order | -//| zero, of the argument. | -//| The domain is divided into the intervals [0, 5] and | -//| (5, infinity). In the first interval a rational approximation | -//| R(x) is employed to compute | -//| y0(x) = R(x) + 2 * log(x) * j0(x) / PI. | -//| Thus a call to j0() is required. | -//| In the second interval, the Hankel asymptotic expansion | -//| is employed with two rational functions of degree 6/6 | -//| and 7/7. | -//| ACCURACY: | -//| Absolute error, when y0(x) < 1; else relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0, 30 30000 1.3e-15 1.6e-16 | -//+------------------------------------------------------------------+ -static double CAlglib::BesselY0(const double x) - { -//--- return result - return(CBessel::BesselY0(x)); - } -//+------------------------------------------------------------------+ -//| Bessel function of second kind of order one | -//| Returns Bessel function of the second kind of order one | -//| of the argument. | -//| The domain is divided into the intervals [0, 8] and | -//| (8, infinity). In the first interval a 25 term Chebyshev | -//| expansion is used, and a call to j1() is required. | -//| In the second, the asymptotic trigonometric representation | -//| is employed using two rational functions of degree 5/5. | -//| ACCURACY: | -//| Absolute error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0, 30 30000 1.0e-15 1.3e-16 | -//+------------------------------------------------------------------+ -static double CAlglib::BesselY1(const double x) - { -//--- return result - return(CBessel::BesselY1(x)); - } -//+------------------------------------------------------------------+ -//| Bessel function of second kind of integer order | -//| Returns Bessel function of order n, where n is a | -//| (possibly negative) integer. | -//| The function is evaluated by forward recurrence on | -//| n, starting with values computed by the routines | -//| y0() and y1(). | -//| If n = 0 or 1 the routine for y0 or y1 is called | -//| directly. | -//| ACCURACY: | -//| Absolute error, except relative | -//| when y > 1: | -//| arithmetic domain # trials peak rms | -//| IEEE 0, 30 30000 3.4e-15 4.3e-16 | -//+------------------------------------------------------------------+ -static double CAlglib::BesselYN(const int n,const double x) - { -//--- return result - return(CBessel::BesselYN(n,x)); - } -//+------------------------------------------------------------------+ -//| Modified Bessel function of order zero | -//| Returns modified Bessel function of order zero of the | -//| argument. | -//| The function is defined as i0(x) = j0( ix ). | -//| The range is partitioned into the two intervals [0,8] and | -//| (8, infinity). Chebyshev polynomial expansions are employed | -//| in each interval. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0,30 30000 5.8e-16 1.4e-16 | -//+------------------------------------------------------------------+ -static double CAlglib::BesselI0(const double x) - { -//--- return result - return(CBessel::BesselI0(x)); - } -//+------------------------------------------------------------------+ -//| Modified Bessel function of order one | -//| Returns modified Bessel function of order one of the | -//| argument. | -//| The function is defined as i1(x) = -i j1( ix ). | -//| The range is partitioned into the two intervals [0,8] and | -//| (8, infinity). Chebyshev polynomial expansions are employed | -//| in each interval. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0, 30 30000 1.9e-15 2.1e-16 | -//+------------------------------------------------------------------+ -static double CAlglib::BesselI1(const double x) - { -//--- return result - return(CBessel::BesselI1(x)); - } -//+------------------------------------------------------------------+ -//| Modified Bessel function, second kind, order zero | -//| Returns modified Bessel function of the second kind | -//| of order zero of the argument. | -//| The range is partitioned into the two intervals [0,8] and | -//| (8, infinity). Chebyshev polynomial expansions are employed | -//| in each interval. | -//| ACCURACY: | -//| Tested at 2000 random points between 0 and 8. Peak absolute | -//| error (relative when K0 > 1) was 1.46e-14; rms, 4.26e-15. | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0, 30 30000 1.2e-15 1.6e-16 | -//+------------------------------------------------------------------+ -static double CAlglib::BesselK0(const double x) - { -//--- return result - return(CBessel::BesselK0(x)); - } -//+------------------------------------------------------------------+ -//| Modified Bessel function, second kind, order one | -//| Computes the modified Bessel function of the second kind | -//| of order one of the argument. | -//| The range is partitioned into the two intervals [0,2] and | -//| (2, infinity). Chebyshev polynomial expansions are employed | -//| in each interval. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0, 30 30000 1.2e-15 1.6e-16 | -//+------------------------------------------------------------------+ -static double CAlglib::BesselK1(const double x) - { -//--- return result - return(CBessel::BesselK1(x)); - } -//+------------------------------------------------------------------+ -//| Modified Bessel function, second kind, integer order | -//| Returns modified Bessel function of the second kind | -//| of order n of the argument. | -//| The range is partitioned into the two intervals [0,9.55] and | -//| (9.55, infinity). An ascending power series is used in the | -//| low range, and an asymptotic expansion in the high range. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0,30 90000 1.8e-8 3.0e-10 | -//| Error is high only near the crossover point x = 9.55 | -//| between the two expansions used. | -//+------------------------------------------------------------------+ -static double CAlglib::BesselKN(const int nn,const double x) - { -//--- return result - return(CBessel::BesselKN(nn,x)); - } -//+------------------------------------------------------------------+ -//| Beta function | -//| - - | -//| | (a) | (b) | -//| beta( a, b ) = -----------. | -//| - | -//| | (a+b) | -//| For large arguments the logarithm of the function is | -//| evaluated using lgam(), then exponentiated. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0,30 30000 8.1e-14 1.1e-14 | -//+------------------------------------------------------------------+ -static double CAlglib::Beta(const double a,const double b) - { -//--- return result - return(CBetaF::Beta(a,b)); - } -//+------------------------------------------------------------------+ -//| Incomplete beta integral | -//| Returns incomplete beta integral of the arguments, evaluated | -//| from zero to x. The function is defined as | -//| x | -//| - - | -//| | (a+b) | | a-1 b-1 | -//| ----------- | t (1-t) dt. | -//| - - | | | -//| | (a) | (b) - | -//| 0 | -//| The domain of definition is 0 <= x <= 1. In this | -//| implementation a and b are restricted to positive values. | -//| The integral from x to 1 may be obtained by the symmetry | -//| relation | -//| 1 - incbet( a, b, x ) = incbet( b, a, 1-x ). | -//| The integral is evaluated by a continued fraction expansion | -//| or, when b*x is small, by a power series. | -//| ACCURACY: | -//| Tested at uniformly distributed random points (a,b,x) with a and | -//| b in "domain" and x between 0 and 1. | -//| Relative error | -//| arithmetic domain # trials peak rms | -//| IEEE 0,5 10000 6.9e-15 4.5e-16 | -//| IEEE 0,85 250000 2.2e-13 1.7e-14 | -//| IEEE 0,1000 30000 5.3e-12 6.3e-13 | -//| IEEE 0,10000 250000 9.3e-11 7.1e-12 | -//| IEEE 0,100000 10000 8.7e-10 4.8e-11 | -//| Outputs smaller than the IEEE gradual underflow threshold | -//| were excluded from these statistics. | -//+------------------------------------------------------------------+ -static double CAlglib::IncompleteBeta(const double a,const double b,const double x) - { -//--- return result - return(CIncBetaF::IncompleteBeta(a,b,x)); - } -//+------------------------------------------------------------------+ -//| Inverse of imcomplete beta integral | -//| Given y, the function finds x such that | -//| incbet( a, b, x ) = y . | -//| The routine performs interval halving or Newton iterations to | -//| find the root of incbet(a,b,x) - y = 0. | -//| ACCURACY: | -//| Relative error: | -//| x a,b | -//| arithmetic domain domain # trials peak rms | -//| IEEE 0,1 .5,10000 50000 5.8e-12 1.3e-13 | -//| IEEE 0,1 .25,100 100000 1.8e-13 3.9e-15 | -//| IEEE 0,1 0,5 50000 1.1e-12 5.5e-15 | -//| With a and b constrained to half-integer or integer values: | -//| IEEE 0,1 .5,10000 50000 5.8e-12 1.1e-13 | -//| IEEE 0,1 .5,100 100000 1.7e-14 7.9e-16 | -//| With a = .5, b constrained to half-integer or integer values: | -//| IEEE 0,1 .5,10000 10000 8.3e-11 1.0e-11 | -//+------------------------------------------------------------------+ -static double CAlglib::InvIncompleteBeta(const double a,const double b,double y) - { -//--- return result - return(CIncBetaF::InvIncompleteBeta(a,b,y)); - } -//+------------------------------------------------------------------+ -//| Binomial distribution | -//| Returns the sum of the terms 0 through k of the Binomial | -//| probability density: | -//| k | -//| -- ( n ) j n-j | -//| > ( ) p (1-p) | -//| -- ( j ) | -//| j=0 | -//| The terms are not summed directly; instead the incomplete | -//| beta integral is employed, according to the formula | -//| y = bdtr( k, n, p ) = incbet( n-k, k+1, 1-p ). | -//| The arguments must be positive, with p ranging from 0 to 1. | -//| ACCURACY: | -//| Tested at random points (a,b,p), with p between 0 and 1. | -//| a,b Relative error: | -//| arithmetic domain # trials peak rms | -//| For p between 0.001 and 1: | -//| IEEE 0,100 100000 4.3e-15 2.6e-16 | -//+------------------------------------------------------------------+ -static double CAlglib::BinomialDistribution(const int k,const int n,const double p) - { -//--- return result - return(CBinomialDistr::BinomialDistribution(k,n,p)); - } -//+------------------------------------------------------------------+ -//| Complemented binomial distribution | -//| Returns the sum of the terms k+1 through n of the Binomial | -//| probability density: | -//| n | -//| -- ( n ) j n-j | -//| > ( ) p (1-p) | -//| -- ( j ) | -//| j=k+1 | -//| The terms are not summed directly; instead the incomplete | -//| beta integral is employed, according to the formula | -//| y = bdtrc( k, n, p ) = incbet( k+1, n-k, p ). | -//| The arguments must be positive, with p ranging from 0 to 1. | -//| ACCURACY: | -//| Tested at random points (a,b,p). | -//| a,b Relative error: | -//| arithmetic domain # trials peak rms | -//| For p between 0.001 and 1: | -//| IEEE 0,100 100000 6.7e-15 8.2e-16 | -//| For p between 0 and .001: | -//| IEEE 0,100 100000 1.5e-13 2.7e-15 | -//+------------------------------------------------------------------+ -static double CAlglib::BinomialComplDistribution(const int k,const int n,const double p) - { -//--- return result - return(CBinomialDistr::BinomialComplDistribution(k,n,p)); - } -//+------------------------------------------------------------------+ -//| Inverse binomial distribution | -//| Finds the event probability p such that the sum of the | -//| terms 0 through k of the Binomial probability density | -//| is equal to the given cumulative probability y. | -//| This is accomplished using the inverse beta integral | -//| function and the relation | -//| 1 - p = incbi( n-k, k+1, y ). | -//| ACCURACY: | -//| Tested at random points (a,b,p). | -//| a,b Relative error: | -//| arithmetic domain # trials peak rms | -//| For p between 0.001 and 1: | -//| IEEE 0,100 100000 2.3e-14 6.4e-16 | -//| IEEE 0,10000 100000 6.6e-12 1.2e-13 | -//| For p between 10^-6 and 0.001: | -//| IEEE 0,100 100000 2.0e-12 1.3e-14 | -//| IEEE 0,10000 100000 1.5e-12 3.2e-14 | -//+------------------------------------------------------------------+ -static double CAlglib::InvBinomialDistribution(const int k,const int n,const double y) - { -//--- return result - return(CBinomialDistr::InvBinomialDistribution(k,n,y)); - } -//+------------------------------------------------------------------+ -//| Calculation of the value of the Chebyshev polynomials of the | -//| first and second kinds. | -//| Parameters: | -//| r - polynomial kind, either 1 or 2. | -//| n - degree, n>=0 | -//| x - argument, -1 <= x <= 1 | -//| Result: | -//| the value of the Chebyshev polynomial at x | -//+------------------------------------------------------------------+ -static double CAlglib::ChebyshevCalculate(int r,const int n,const double x) - { -//--- return result - return(CChebyshev::ChebyshevCalculate(r,n,x)); - } -//+------------------------------------------------------------------+ -//| Summation of Chebyshev polynomials using Clenshaw?s recurrence | -//| formula. | -//| This routine calculates | -//| c[0]*T0(x) + c[1]*T1(x) + ... + c[N]*TN(x) | -//| or | -//| c[0]*U0(x) + c[1]*U1(x) + ... + c[N]*UN(x) | -//| depending on the R. | -//| Parameters: | -//| r - polynomial kind, either 1 or 2. | -//| n - degree, n>=0 | -//| x - argument | -//| Result: | -//| the value of the Chebyshev polynomial at x | -//+------------------------------------------------------------------+ -static double CAlglib::ChebyshevSum(double &c[],const int r,const int n,const double x) - { -//--- return result - return(CChebyshev::ChebyshevSum(c,r,n,x)); - } -//+------------------------------------------------------------------+ -//| Representation of Tn as C[0] + C[1]*X + ... + C[N]*X^N | -//| Input parameters: | -//| N - polynomial degree, n>=0 | -//| Output parameters: | -//| C - coefficients | -//+------------------------------------------------------------------+ -static void CAlglib::ChebyshevCoefficients(const int n,double &c[]) - { -//--- function call - CChebyshev::ChebyshevCoefficients(n,c); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Conversion of a series of Chebyshev polynomials to a power | -//| series. | -//| Represents A[0]*T0(x) + A[1]*T1(x) + ... + A[N]*Tn(x) as | -//| B[0] + B[1]*X + ... + B[N]*X^N. | -//| Input parameters: | -//| A - Chebyshev series coefficients | -//| N - degree, N>=0 | -//| Output parameters | -//| B - power series coefficients | -//+------------------------------------------------------------------+ -static void CAlglib::FromChebyshev(double &a[],const int n,double &b[]) - { -//--- function call - CChebyshev::FromChebyshev(a,n,b); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Chi-square distribution | -//| Returns the area under the left hand tail (from 0 to x) | -//| of the Chi square probability density function with | -//| v degrees of freedom. | -//| x | -//| - | -//| 1 | | v/2-1 -t/2 | -//| P( x | v ) = ----------- | t e dt | -//| v/2 - | | | -//| 2 | (v/2) - | -//| 0 | -//| where x is the Chi-square variable. | -//| The incomplete gamma integral is used, according to the | -//| formula | -//| y = chdtr( v, x ) = igam( v/2.0, x/2.0 ). | -//| The arguments must both be positive. | -//| ACCURACY: | -//| See incomplete gamma function | -//+------------------------------------------------------------------+ -static double CAlglib::ChiSquareDistribution(const double v,const double x) - { -//--- return result - return(CChiSquareDistr::ChiSquareDistribution(v,x)); - } -//+------------------------------------------------------------------+ -//| Complemented Chi-square distribution | -//| Returns the area under the right hand tail (from x to | -//| infinity) of the Chi square probability density function | -//| with v degrees of freedom: | -//| inf. | -//| - | -//| 1 | | v/2-1 -t/2 | -//| P( x | v ) = ----------- | t e dt | -//| v/2 - | | | -//| 2 | (v/2) - | -//| x | -//| where x is the Chi-square variable. | -//| The incomplete gamma integral is used, according to the | -//| formula | -//| y = chdtr( v, x ) = igamc( v/2.0, x/2.0 ). | -//| The arguments must both be positive. | -//| ACCURACY: | -//| See incomplete gamma function | -//+------------------------------------------------------------------+ -static double CAlglib::ChiSquareComplDistribution(const double v,const double x) - { -//--- return result - return(CChiSquareDistr::ChiSquareComplDistribution(v,x)); - } -//+------------------------------------------------------------------+ -//| Inverse of complemented Chi-square distribution | -//| Finds the Chi-square argument x such that the integral | -//| from x to infinity of the Chi-square density is equal | -//| to the given cumulative probability y. | -//| This is accomplished using the inverse gamma integral | -//| function and the relation | -//| x/2 = igami( df/2, y ); | -//| ACCURACY: | -//| See inverse incomplete gamma function | -//+------------------------------------------------------------------+ -static double CAlglib::InvChiSquareDistribution(const double v,const double y) - { -//--- return result - return(CChiSquareDistr::InvChiSquareDistribution(v,y)); - } -//+------------------------------------------------------------------+ -//| Dawson's Integral | -//| Approximates the integral | -//| x | -//| - | -//| 2 | | 2 | -//| dawsn(x) = exp( -x ) | exp( t ) dt | -//| | | | -//| - | -//| 0 | -//| Three different rational approximations are employed, for | -//| the intervals 0 to 3.25; 3.25 to 6.25; and 6.25 up. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0,10 10000 6.9e-16 1.0e-16 | -//+------------------------------------------------------------------+ -static double CAlglib::DawsonIntegral(const double x) - { -//--- return result - return(CDawson::DawsonIntegral(x)); - } -//+------------------------------------------------------------------+ -//| Complete elliptic integral of the first kind | -//| Approximates the integral | -//| pi/2 | -//| - | -//| | | | -//| | dt | -//| K(m) = | ------------------ | -//| | 2 | -//| | | sqrt( 1 - m sin t ) | -//| - | -//| 0 | -//| using the approximation | -//| P(x) - log x Q(x). | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0,1 30000 2.5e-16 6.8e-17 | -//+------------------------------------------------------------------+ -static double CAlglib::EllipticIntegralK(const double m) - { -//--- return result - return(CElliptic::EllipticIntegralK(m)); - } -//+------------------------------------------------------------------+ -//| Complete elliptic integral of the first kind | -//| Approximates the integral | -//| pi/2 | -//| - | -//| | | | -//| | dt | -//| K(m) = | ------------------ | -//| | 2 | -//| | | sqrt( 1 - m sin t ) | -//| - | -//| 0 | -//| where m = 1 - m1, using the approximation | -//| P(x) - log x Q(x). | -//| The argument m1 is used rather than m so that the logarithmic | -//| singularity at m = 1 will be shifted to the origin; this | -//| preserves maximum accuracy. | -//| K(0) = pi/2. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0,1 30000 2.5e-16 6.8e-17 | -//+------------------------------------------------------------------+ -static double CAlglib::EllipticIntegralKhighPrecision(const double m1) - { -//--- return result - return(CElliptic::EllipticIntegralKhighPrecision(m1)); - } -//+------------------------------------------------------------------+ -//| Incomplete elliptic integral of the first kind F(phi|m) | -//| Approximates the integral | -//| phi | -//| - | -//| | | | -//| | dt | -//| F(phi_\m) = | ------------------ | -//| | 2 | -//| | | sqrt( 1 - m sin t ) | -//| - | -//| 0 | -//| of amplitude phi and modulus m, using the arithmetic - | -//| geometric mean algorithm. | -//| ACCURACY: | -//| Tested at random points with m in [0, 1] and phi as indicated. | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE -10,10 200000 7.4e-16 1.0e-16 | -//+------------------------------------------------------------------+ -static double CAlglib::IncompleteEllipticIntegralK(const double phi,const double m) - { -//--- return result - return(CElliptic::IncompleteEllipticIntegralK(phi,m)); - } -//+------------------------------------------------------------------+ -//| Complete elliptic integral of the second kind | -//| Approximates the integral | -//| pi/2 | -//| - | -//| | | 2 | -//| E(m) = | sqrt( 1 - m sin t ) dt | -//| | | | -//| - | -//| 0 | -//| using the approximation | -//| P(x) - x log x Q(x). | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0, 1 10000 2.1e-16 7.3e-17 | -//+------------------------------------------------------------------+ -static double CAlglib::EllipticIntegralE(const double m) - { -//--- return result - return(CElliptic::EllipticIntegralE(m)); - } -//+------------------------------------------------------------------+ -//| Incomplete elliptic integral of the second kind | -//| Approximates the integral | -//| phi | -//| - | -//| | | | -//| | 2 | -//| E(phi_\m) = | sqrt( 1 - m sin t ) dt | -//| | | -//| | | | -//| - | -//| 0 | -//| of amplitude phi and modulus m, using the arithmetic - | -//| geometric mean algorithm. | -//| ACCURACY: | -//| Tested at random arguments with phi in [-10, 10] and m in | -//| [0, 1]. | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE -10,10 150000 3.3e-15 1.4e-16 | -//+------------------------------------------------------------------+ -static double CAlglib::IncompleteEllipticIntegralE(const double phi,const double m) - { -//--- return result - return(CElliptic::IncompleteEllipticIntegralE(phi,m)); - } -//+------------------------------------------------------------------+ -//| Exponential integral Ei(x) | -//| x | -//| - t | -//| | | e | -//| Ei(x) = -|- --- dt . | -//| | | t | -//| - | -//| -inf | -//| Not defined for x <= 0. | -//| See also expn.c. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0,100 50000 8.6e-16 1.3e-16 | -//+------------------------------------------------------------------+ -static double CAlglib::ExponentialIntegralEi(const double x) - { -//--- return result - return(CExpIntegrals::ExponentialIntegralEi(x)); - } -//+------------------------------------------------------------------+ -//| Exponential integral En(x) | -//| Evaluates the exponential integral | -//| inf. | -//| - | -//| | | -xt | -//| | e | -//| E (x) = | ---- dt. | -//| n | n | -//| | | t | -//| - | -//| 1 | -//| Both n and x must be nonnegative. | -//| The routine employs either a power series, a continued | -//| fraction, or an asymptotic formula depending on the | -//| relative values of n and x. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0, 30 10000 1.7e-15 3.6e-16 | -//+------------------------------------------------------------------+ -static double CAlglib::ExponentialIntegralEn(const double x,const int n) - { -//--- return result - return(CExpIntegrals::ExponentialIntegralEn(x,n)); - } -//+------------------------------------------------------------------+ -//| F distribution | -//| Returns the area from zero to x under the F density | -//| function (also known as Snedcor's density or the | -//| variance ratio density). This is the density | -//| of x = (u1/df1)/(u2/df2), where u1 and u2 are random | -//| variables having Chi square distributions with df1 | -//| and df2 degrees of freedom, respectively. | -//| The incomplete beta integral is used, according to the | -//| formula | -//| P(x) = incbet( df1/2, df2/2, (df1*x/(df2 + df1*x) ). | -//| The arguments a and b are greater than zero, and x is | -//| nonnegative. | -//| ACCURACY: | -//| Tested at random points (a,b,x). | -//| x a,b Relative error: | -//| arithmetic domain domain # trials peak rms | -//| IEEE 0,1 0,100 100000 9.8e-15 1.7e-15 | -//| IEEE 1,5 0,100 100000 6.5e-15 3.5e-16 | -//| IEEE 0,1 1,10000 100000 2.2e-11 3.3e-12 | -//| IEEE 1,5 1,10000 100000 1.1e-11 1.7e-13 | -//+------------------------------------------------------------------+ -static double CAlglib::FDistribution(const int a,const int b,const double x) - { -//--- return result - return(CFDistr::FDistribution(a,b,x)); - } -//+------------------------------------------------------------------+ -//| Complemented F distribution | -//| Returns the area from x to infinity under the F density | -//| function (also known as Snedcor's density or the | -//| variance ratio density). | -//| inf. | -//| - | -//| 1 | | a-1 b-1 | -//| 1-P(x) = ------ | t (1-t) dt | -//| B(a,b) | | | -//| - | -//| x | -//| The incomplete beta integral is used, according to the | -//| formula | -//| P(x) = incbet( df2/2, df1/2, (df2/(df2 + df1*x) ). | -//| ACCURACY: | -//| Tested at random points (a,b,x) in the indicated intervals. | -//| x a,b Relative error: | -//| arithmetic domain domain # trials peak rms | -//| IEEE 0,1 1,100 100000 3.7e-14 5.9e-16 | -//| IEEE 1,5 1,100 100000 8.0e-15 1.6e-15 | -//| IEEE 0,1 1,10000 100000 1.8e-11 3.5e-13 | -//| IEEE 1,5 1,10000 100000 2.0e-11 3.0e-12 | -//+------------------------------------------------------------------+ -static double CAlglib::FComplDistribution(const int a,const int b,const double x) - { -//--- return result - return(CFDistr::FComplDistribution(a,b,x)); - } -//+------------------------------------------------------------------+ -//| Inverse of complemented F distribution | -//| Finds the F density argument x such that the integral | -//| from x to infinity of the F density is equal to the | -//| given probability p. | -//| This is accomplished using the inverse beta integral | -//| function and the relations | -//| z = incbi( df2/2, df1/2, p ) | -//| x = df2 (1-z) / (df1 z). | -//| Note: the following relations hold for the inverse of | -//| the uncomplemented F distribution: | -//| z = incbi( df1/2, df2/2, p ) | -//| x = df2 z / (df1 (1-z)). | -//| ACCURACY: | -//| Tested at random points (a,b,p). | -//| a,b Relative error: | -//| arithmetic domain # trials peak rms | -//| For p between .001 and 1: | -//| IEEE 1,100 100000 8.3e-15 4.7e-16 | -//| IEEE 1,10000 100000 2.1e-11 1.4e-13 | -//| For p between 10^-6 and 10^-3: | -//| IEEE 1,100 50000 1.3e-12 8.4e-15 | -//| IEEE 1,10000 50000 3.0e-12 4.8e-14 | -//+------------------------------------------------------------------+ -static double CAlglib::InvFDistribution(const int a,const int b,const double y) - { -//--- return result - return(CFDistr::InvFDistribution(a,b,y)); - } -//+------------------------------------------------------------------+ -//| Fresnel integral | -//| Evaluates the Fresnel integrals | -//| x | -//| - | -//| | | | -//| C(x) = | cos(pi/2 t**2) dt, | -//| | | | -//| - | -//| 0 | -//| x | -//| - | -//| | | | -//| S(x) = | sin(pi/2 t**2) dt. | -//| | | | -//| - | -//| 0 | -//| The integrals are evaluated by a power series for x < 1. | -//| For x >= 1 auxiliary functions f(x) and g(x) are employed | -//| such that | -//| C(x) = 0.5 + f(x) sin( pi/2 x**2 ) - g(x) cos( pi/2 x**2 ) | -//| S(x) = 0.5 - f(x) cos( pi/2 x**2 ) - g(x) sin( pi/2 x**2 ) | -//| ACCURACY: | -//| Relative error. | -//| Arithmetic function domain # trials peak rms | -//| IEEE S(x) 0, 10 10000 2.0e-15 3.2e-16| -//| IEEE C(x) 0, 10 10000 1.8e-15 3.3e-16| -//+------------------------------------------------------------------+ -static void CAlglib::FresnelIntegral(const double x,double &c,double &s) - { -//--- function call - CFresnel::FresnelIntegral(x,c,s); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Calculation of the value of the Hermite polynomial. | -//| Parameters: | -//| n - degree, n>=0 | -//| x - argument | -//| Result: | -//| the value of the Hermite polynomial Hn at x | -//+------------------------------------------------------------------+ -static double CAlglib::HermiteCalculate(const int n,const double x) - { -//--- return result - return(CHermite::HermiteCalculate(n,x)); - } -//+------------------------------------------------------------------+ -//| Summation of Hermite polynomials using Clenshaw?s recurrence | -//| formula. | -//| This routine calculates | -//| c[0]*H0(x) + c[1]*H1(x) + ... + c[N]*HN(x) | -//| Parameters: | -//| n - degree, n>=0 | -//| x - argument | -//| Result: | -//| the value of the Hermite polynomial at x | -//+------------------------------------------------------------------+ -static double CAlglib::HermiteSum(double &c[],const int n,const double x) - { -//--- return result - return(CHermite::HermiteSum(c,n,x)); - } -//+------------------------------------------------------------------+ -//| Representation of Hn as C[0] + C[1]*X + ... + C[N]*X^N | -//| Input parameters: | -//| N - polynomial degree, n>=0 | -//| Output parameters: | -//| C - coefficients | -//+------------------------------------------------------------------+ -static void CAlglib::HermiteCoefficients(const int n,double &c[]) - { -//--- function call - CHermite::HermiteCoefficients(n,c); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Jacobian Elliptic Functions | -//| Evaluates the Jacobian elliptic functions sn(u|m), cn(u|m), | -//| and dn(u|m) of parameter m between 0 and 1, and real | -//| argument u. | -//| These functions are periodic, with quarter-period on the | -//| real axis equal to the complete elliptic integral | -//| ellpk(1.0-m). | -//| Relation to incomplete elliptic integral: | -//| If u = ellik(phi,m), then sn(u|m) = sin(phi), | -//| and cn(u|m) = cos(phi). Phi is called the amplitude of u. | -//| Computation is by means of the arithmetic-geometric mean | -//| algorithm, except when m is within 1e-9 of 0 or 1. In the | -//| latter case with m close to 1, the approximation applies | -//| only for phi < pi/2. | -//| ACCURACY: | -//| Tested at random points with u between 0 and 10, m between | -//| 0 and 1. | -//| Absolute error (* = relative error): | -//| arithmetic function # trials peak rms | -//| IEEE phi 10000 9.2e-16* 1.4e-16* | -//| IEEE sn 50000 4.1e-15 4.6e-16 | -//| IEEE cn 40000 3.6e-15 4.4e-16 | -//| IEEE dn 10000 1.3e-12 1.8e-14 | -//| Peak error observed in consistency check using addition | -//| theorem for sn(u+v) was 4e-16 (absolute). Also tested by | -//| the above relation to the incomplete elliptic integral. | -//| Accuracy deteriorates when u is large. | -//+------------------------------------------------------------------+ -static void CAlglib::JacobianEllipticFunctions(const double u,const double m, - double &sn,double &cn, - double &dn,double &ph) - { -//--- create variables - sn=0; - cn=0; - dn=0; - ph=0; -//--- function call - CJacobianElliptic::JacobianEllipticFunctions(u,m,sn,cn,dn,ph); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Calculation of the value of the Laguerre polynomial. | -//| Parameters: | -//| n - degree, n>=0 | -//| x - argument | -//| Result: | -//| the value of the Laguerre polynomial Ln at x | -//+------------------------------------------------------------------+ -static double CAlglib::LaguerreCalculate(const int n,const double x) - { -//--- return result - return(CLaguerre::LaguerreCalculate(n,x)); - } -//+------------------------------------------------------------------+ -//| Summation of Laguerre polynomials using Clenshaw?s recurrence | -//| formula. | -//| This routine calculates c[0]*L0(x) + c[1]*L1(x) + ... + | -//| + c[N]*LN(x) | -//| Parameters: | -//| n - degree, n>=0 | -//| x - argument | -//| Result: | -//| the value of the Laguerre polynomial at x | -//+------------------------------------------------------------------+ -static double CAlglib::LaguerreSum(double &c[],const int n,const double x) - { -//--- return result - return(CLaguerre::LaguerreSum(c,n,x)); - } -//+------------------------------------------------------------------+ -//| Representation of Ln as C[0] + C[1]*X + ... + C[N]*X^N | -//| Input parameters: | -//| N - polynomial degree, n>=0 | -//| Output parameters: | -//| C - coefficients | -//+------------------------------------------------------------------+ -static void CAlglib::LaguerreCoefficients(const int n,double &c[]) - { -//--- function call - CLaguerre::LaguerreCoefficients(n,c); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Calculation of the value of the Legendre polynomial Pn. | -//| Parameters: | -//| n - degree, n>=0 | -//| x - argument | -//| Result: | -//| the value of the Legendre polynomial Pn at x | -//+------------------------------------------------------------------+ -static double CAlglib::LegendreCalculate(const int n,const double x) - { -//--- return result - return(CLegendre::LegendreCalculate(n,x)); - } -//+------------------------------------------------------------------+ -//| Summation of Legendre polynomials using Clenshaw?s recurrence | -//| formula. | -//| This routine calculates | -//| c[0]*P0(x) + c[1]*P1(x) + ... + c[N]*PN(x) | -//| Parameters: | -//| n - degree, n>=0 | -//| x - argument | -//| Result: | -//| the value of the Legendre polynomial at x | -//+------------------------------------------------------------------+ -static double CAlglib::LegendreSum(double &c[],const int n,const double x) - { -//--- return result - return(CLegendre::LegendreSum(c,n,x)); - } -//+------------------------------------------------------------------+ -//| Representation of Pn as C[0] + C[1]*X + ... + C[N]*X^N | -//| Input parameters: | -//| N - polynomial degree, n>=0 | -//| Output parameters: | -//| C - coefficients | -//+------------------------------------------------------------------+ -static void CAlglib::LegendreCoefficients(const int n,double &c[]) - { -//--- function call - CLegendre::LegendreCoefficients(n,c); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Poisson distribution | -//| Returns the sum of the first k+1 terms of the Poisson | -//| distribution: | -//| k j | -//| -- -m m | -//| > e -- | -//| -- j! | -//| j=0 | -//| The terms are not summed directly; instead the incomplete | -//| gamma integral is employed, according to the relation | -//| y = pdtr( k, m ) = igamc( k+1, m ). | -//| The arguments must both be positive. | -//| ACCURACY: | -//| See incomplete gamma function | -//+------------------------------------------------------------------+ -static double CAlglib::PoissonDistribution(const int k,const double m) - { -//--- return result - return(CPoissonDistr::PoissonDistribution(k,m)); - } -//+------------------------------------------------------------------+ -//| Complemented Poisson distribution | -//| Returns the sum of the terms k+1 to infinity of the Poisson | -//| distribution: | -//| inf. j | -//| -- -m m | -//| > e -- | -//| -- j! | -//| j=k+1 | -//| The terms are not summed directly; instead the incomplete | -//| gamma integral is employed, according to the formula | -//| y = pdtrc( k, m ) = igam( k+1, m ). | -//| The arguments must both be positive. | -//| ACCURACY: | -//| See incomplete gamma function | -//+------------------------------------------------------------------+ -static double CAlglib::PoissonComplDistribution(const int k,const double m) - { -//--- return result - return(CPoissonDistr::PoissonComplDistribution(k,m)); - } -//+------------------------------------------------------------------+ -//| Inverse Poisson distribution | -//| Finds the Poisson variable x such that the integral | -//| from 0 to x of the Poisson density is equal to the | -//| given probability y. | -//| This is accomplished using the inverse gamma integral | -//| function and the relation | -//| m = igami( k+1, y ). | -//| ACCURACY: | -//| See inverse incomplete gamma function | -//+------------------------------------------------------------------+ -static double CAlglib::InvPoissonDistribution(const int k,const double y) - { -//--- return result - return(CPoissonDistr::InvPoissonDistribution(k,y)); - } -//+------------------------------------------------------------------+ -//| Psi (digamma) function | -//| d - | -//| psi(x) = -- ln | (x) | -//| dx | -//| is the logarithmic derivative of the gamma function. | -//| For integer x, | -//| n-1 | -//| - | -//| psi(n) = -EUL + > 1/k. | -//| - | -//| k=1 | -//| This formula is used for 0 < n <= 10. If x is negative, it | -//| is transformed to a positive argument by the reflection | -//| formula psi(1-x) = psi(x) + pi cot(pi x). | -//| For general positive x, the argument is made greater than 10 | -//| using the recurrence psi(x+1) = psi(x) + 1/x. | -//| Then the following asymptotic expansion is applied: | -//| inf. B | -//| - 2k | -//| psi(x) = log(x) - 1/2x - > ------- | -//| - 2k | -//| k=1 2k x | -//| where the B2k are Bernoulli numbers. | -//| ACCURACY: | -//| Relative error (except absolute when |psi| < 1): | -//| arithmetic domain # trials peak rms | -//| IEEE 0,30 30000 1.3e-15 1.4e-16 | -//| IEEE -30,0 40000 1.5e-15 2.2e-16 | -//+------------------------------------------------------------------+ -static double CAlglib::Psi(const double x) - { -//--- return result - return(CPsiF::Psi(x)); - } -//+------------------------------------------------------------------+ -//| Student's t distribution | -//| Computes the integral from minus infinity to t of the Student | -//| t distribution with integer k > 0 degrees of freedom: | -//| t | -//| - | -//| | | | -//| - | 2 -(k+1)/2 | -//| | ( (k+1)/2 ) | ( x ) | -//| ---------------------- | ( 1 + --- ) dx | -//| - | ( k ) | -//| sqrt( k pi ) | ( k/2 ) | | -//| | | | -//| - | -//| -inf. | -//| Relation to incomplete beta integral: | -//| 1 - stdtr(k,t) = 0.5 * incbet( k/2, 1/2, z ) | -//| where | -//| z = k/(k + t**2). | -//| For t < -2, this is the method of computation. For higher t, | -//| a direct method is derived from integration by parts. | -//| Since the function is symmetric about t=0, the area under the | -//| right tail of the density is found by calling the function | -//| with -t instead of t. | -//| ACCURACY: | -//| Tested at random 1 <= k <= 25. The "domain" refers to t. | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE -100,-2 50000 5.9e-15 1.4e-15 | -//| IEEE -2,100 500000 2.7e-15 4.9e-17 | -//+------------------------------------------------------------------+ -static double CAlglib::StudenttDistribution(const int k,const double t) - { -//--- return result - return(CStudenttDistr::StudenttDistribution(k,t)); - } -//+------------------------------------------------------------------+ -//| Functional inverse of Student's t distribution | -//| Given probability p, finds the argument t such that stdtr(k,t) | -//| is equal to p. | -//| ACCURACY: | -//| Tested at random 1 <= k <= 100. The "domain" refers to p: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE .001,.999 25000 5.7e-15 8.0e-16 | -//| IEEE 10^-6,.001 25000 2.0e-12 2.9e-14 | -//+------------------------------------------------------------------+ -static double CAlglib::InvStudenttDistribution(const int k,const double p) - { -//--- return result - return(CStudenttDistr::InvStudenttDistribution(k,p)); - } -//+------------------------------------------------------------------+ -//| Sine and cosine integrals | -//| Evaluates the integrals | -//| x | -//| - | -//| | cos t - 1 | -//| Ci(x) = eul + ln x + | --------- dt, | -//| | t | -//| - | -//| 0 | -//| x | -//| - | -//| | sin t | -//| Si(x) = | ----- dt | -//| | t | -//| - | -//| 0 | -//| where eul = 0.57721566490153286061 is Euler's constant. | -//| The integrals are approximated by rational functions. | -//| For x > 8 auxiliary functions f(x) and g(x) are employed | -//| such that | -//| Ci(x) = f(x) sin(x) - g(x) cos(x) | -//| Si(x) = pi/2 - f(x) cos(x) - g(x) sin(x) | -//| ACCURACY: | -//| Test interval = [0,50]. | -//| Absolute error, except relative when > 1: | -//| arithmetic function # trials peak rms | -//| IEEE Si 30000 4.4e-16 7.3e-17 | -//| IEEE Ci 30000 6.9e-16 5.1e-17 | -//+------------------------------------------------------------------+ -static void CAlglib::SineCosineIntegrals(const double x,double &si,double &ci) - { -//--- initialization - si=0; - ci=0; -//--- function call - CTrigIntegrals::SineCosineIntegrals(x,si,ci); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Hyperbolic sine and cosine integrals | -//| Approximates the integrals | -//| x | -//| - | -//| | | cosh t - 1 | -//| Chi(x) = eul + ln x + | ----------- dt, | -//| | | t | -//| - | -//| 0 | -//| x | -//| - | -//| | | sinh t | -//| Shi(x) = | ------ dt | -//| | | t | -//| - | -//| 0 | -//| where eul = 0.57721566490153286061 is Euler's constant. | -//| The integrals are evaluated by power series for x < 8 | -//| and by Chebyshev expansions for x between 8 and 88. | -//| For large x, both functions approach exp(x)/2x. | -//| Arguments greater than 88 in magnitude return MAXNUM. | -//| ACCURACY: | -//| Test interval 0 to 88. | -//| Relative error: | -//| arithmetic function # trials peak rms | -//| IEEE Shi 30000 6.9e-16 1.6e-16 | -//| Absolute error, except relative when |Chi| > 1: | -//| IEEE Chi 30000 8.4e-16 1.4e-16 | -//+------------------------------------------------------------------+ -static void CAlglib::HyperbolicSineCosineIntegrals(const double x,double &shi,double &chi) - { -//--- initialization - shi=0; - chi=0; -//--- function call - CTrigIntegrals::HyperbolicSineCosineIntegrals(x,shi,chi); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Calculation of the distribution moments: mean, variance, | -//| skewness, kurtosis. | -//| INPUT PARAMETERS: | -//| X - sample | -//| N - N>=0, sample size: | -//| * if given, only leading N elements of X are | -//| processed | -//| * if not given, automatically determined from | -//| size of X | -//| OUTPUT PARAMETERS | -//| Mean - mean. | -//| Variance- variance. | -//| Skewness- skewness (if variance<>0; zero otherwise). | -//| Kurtosis- kurtosis (if variance<>0; zero otherwise). | -//+------------------------------------------------------------------+ -static void CAlglib::SampleMoments(const double &x[],const int n,double &mean, - double &variance,double &skewness, - double &kurtosis) - { -//--- initialization - mean=0; - variance=0; - skewness=0; - kurtosis=0; -//--- function call - CBaseStat::SampleMoments(x,n,mean,variance,skewness,kurtosis); - } -//+------------------------------------------------------------------+ -//| Calculation of the distribution moments: mean, variance, | -//| skewness, kurtosis. | -//| INPUT PARAMETERS: | -//| X - sample | -//| N - N>=0, sample size: | -//| * if given, only leading N elements of X are | -//| processed | -//| * if not given, automatically determined from | -//| size of X | -//| OUTPUT PARAMETERS | -//| Mean - mean. | -//| Variance- variance. | -//| Skewness- skewness (if variance<>0; zero otherwise). | -//| Kurtosis- kurtosis (if variance<>0; zero otherwise). | -//+------------------------------------------------------------------+ -static void CAlglib::SampleMoments(const double &x[],double &mean, - double &variance,double &skewness, - double &kurtosis) - { -//--- create a variable - int n; -//--- initialization - mean=0; - variance=0; - skewness=0; - kurtosis=0; -//--- get lenght - n=CAp::Len(x); -//--- function call - CBaseStat::SampleMoments(x,n,mean,variance,skewness,kurtosis); - } -//+------------------------------------------------------------------+ -//| ADev | -//| Input parameters: | -//| X - sample | -//| N - N>=0, sample size: | -//| * if given, only leading N elements of X are | -//| processed | -//| * if not given, automatically determined from size | -//| of X | -//| Output parameters: | -//| ADev- ADev | -//+------------------------------------------------------------------+ -static void CAlglib::SampleAdev(const double &x[],const int n,double &adev) - { -//--- initialization - adev=0; -//--- function call - CBaseStat::SampleAdev(x,n,adev); - } -//+------------------------------------------------------------------+ -//| ADev | -//| Input parameters: | -//| X - sample | -//| N - N>=0, sample size: | -//| * if given, only leading N elements of X are | -//| processed | -//| * if not given, automatically determined from size | -//| of X | -//| Output parameters: | -//| ADev- ADev | -//+------------------------------------------------------------------+ -static void CAlglib::SampleAdev(const double &x[],double &adev) - { -//--- create a variable - int n=CAp::Len(x); -//--- initialization - adev=0; -//--- function call - CBaseStat::SampleAdev(x,n,adev); - } -//+------------------------------------------------------------------+ -//| Median calculation. | -//| Input parameters: | -//| X - sample (array indexes: [0..N-1]) | -//| N - N>=0, sample size: | -//| * if given, only leading N elements of X are | -//| processed | -//| * if not given, automatically determined from size | -//| of X | -//| Output parameters: | -//| Median | -//+------------------------------------------------------------------+ -static void CAlglib::SampleMedian(const double &x[],const int n,double &median) - { -//--- initialization - median=0; -//--- function call - CBaseStat::SampleMedian(x,n,median); - } -//+------------------------------------------------------------------+ -//| Median calculation. | -//| Input parameters: | -//| X - sample (array indexes: [0..N-1]) | -//| N - N>=0, sample size: | -//| * if given, only leading N elements of X are | -//| processed | -//| * if not given, automatically determined from size | -//| of X | -//| Output parameters: | -//| Median | -//+------------------------------------------------------------------+ -static void CAlglib::SampleMedian(const double &x[],double &median) - { -//--- create a variable - int n=CAp::Len(x); -//--- initialization - median=0; -//--- function call - CBaseStat::SampleMedian(x,n,median); - } -//+------------------------------------------------------------------+ -//| Percentile calculation. | -//| Input parameters: | -//| X - sample (array indexes: [0..N-1]) | -//| N - N>=0, sample size: | -//| * if given, only leading N elements of X are | -//| processed | -//| * if not given, automatically determined from size | -//| of X | -//| P - percentile (0<=P<=1) | -//| Output parameters: | -//| V - percentile | -//+------------------------------------------------------------------+ -static void CAlglib::SamplePercentile(const double &x[],const int n, - const double p,double &v) - { -//--- initialization - v=0; -//--- function call - CBaseStat::SamplePercentile(x,n,p,v); - } -//+------------------------------------------------------------------+ -//| Percentile calculation. | -//| Input parameters: | -//| X - sample (array indexes: [0..N-1]) | -//| N - N>=0, sample size: | -//| * if given, only leading N elements of X are | -//| processed | -//| * if not given, automatically determined from size | -//| of X | -//| P - percentile (0<=P<=1) | -//| Output parameters: | -//| V - percentile | -//+------------------------------------------------------------------+ -static void CAlglib::SamplePercentile(const double &x[],const double p, - double &v) - { -//--- create a variable - int n=CAp::Len(x); -//--- initialization - v=0; -//--- function call - CBaseStat::SamplePercentile(x,n,p,v); - } -//+------------------------------------------------------------------+ -//| 2-sample covariance | -//| Input parameters: | -//| X - sample 1 (array indexes: [0..N-1]) | -//| Y - sample 2 (array indexes: [0..N-1]) | -//| N - N>=0, sample size: | -//| * if given, only N leading elements of X/Y are | -//| processed | -//| * if not given, automatically determined from | -//| input sizes | -//| Result: | -//| covariance (zero for N=0 or N=1) | -//+------------------------------------------------------------------+ -static double CAlglib::Cov2(const double &x[],const double &y[],const int n) - { -//--- return result - return(CBaseStat::Cov2(x,y,n)); - } -//+------------------------------------------------------------------+ -//| 2-sample covariance | -//| Input parameters: | -//| X - sample 1 (array indexes: [0..N-1]) | -//| Y - sample 2 (array indexes: [0..N-1]) | -//| N - N>=0, sample size: | -//| * if given, only N leading elements of X/Y are | -//| processed | -//| * if not given, automatically determined from | -//| input sizes | -//| Result: | -//| covariance (zero for N=0 or N=1) | -//+------------------------------------------------------------------+ -static double CAlglib::Cov2(const double &x[],const double &y[]) - { -//--- check - if(CAp::Len(x)!=CAp::Len(y)) - { - Print(__FUNCTION__+": arrays size are not equal"); - CAp::exception_happened=true; - return(EMPTY_VALUE); - } -//--- create a variable - int n=CAp::Len(x); -//--- return result - return(CBaseStat::Cov2(x,y,n)); - } -//+------------------------------------------------------------------+ -//| Pearson product-moment correlation coefficient | -//| Input parameters: | -//| X - sample 1 (array indexes: [0..N-1]) | -//| Y - sample 2 (array indexes: [0..N-1]) | -//| N - N>=0, sample size: | -//| * if given, only N leading elements of X/Y are | -//| processed | -//| * if not given, automatically determined from | -//| input sizes | -//| Result: | -//| Pearson product-moment correlation coefficient | -//| (zero for N=0 or N=1) | -//+------------------------------------------------------------------+ -static double CAlglib::PearsonCorr2(const double &x[],const double &y[], - const int n) - { -//--- return result - return(CBaseStat::PearsonCorr2(x,y,n)); - } -//+------------------------------------------------------------------+ -//| Pearson product-moment correlation coefficient | -//| Input parameters: | -//| X - sample 1 (array indexes: [0..N-1]) | -//| Y - sample 2 (array indexes: [0..N-1]) | -//| N - N>=0, sample size: | -//| * if given, only N leading elements of X/Y are | -//| processed | -//| * if not given, automatically determined from | -//| input sizes | -//| Result: | -//| Pearson product-moment correlation coefficient | -//| (zero for N=0 or N=1) | -//+------------------------------------------------------------------+ -static double CAlglib::PearsonCorr2(const double &x[],const double &y[]) - { -//--- check - if(CAp::Len(x)!=CAp::Len(y)) - { - Print(__FUNCTION__+": arrays size are not equal"); - CAp::exception_happened=true; - return(EMPTY_VALUE); - } -//--- create a variable - int n=CAp::Len(x); -//--- return result - return(CBaseStat::PearsonCorr2(x,y,n)); - } -//+------------------------------------------------------------------+ -//| Spearman's rank correlation coefficient | -//| Input parameters: | -//| X - sample 1 (array indexes: [0..N-1]) | -//| Y - sample 2 (array indexes: [0..N-1]) | -//| N - N>=0, sample size: | -//| * if given, only N leading elements of X/Y are | -//| processed | -//| * if not given, automatically determined from | -//| input sizes | -//| Result: | -//| Spearman's rank correlation coefficient | -//| (zero for N=0 or N=1) | -//+------------------------------------------------------------------+ -static double CAlglib::SpearmanCorr2(const double &x[],const double &y[], - const int n) - { -//--- return result - return(CBaseStat::SpearmanCorr2(x,y,n)); - } -//+------------------------------------------------------------------+ -//| Spearman's rank correlation coefficient | -//| Input parameters: | -//| X - sample 1 (array indexes: [0..N-1]) | -//| Y - sample 2 (array indexes: [0..N-1]) | -//| N - N>=0, sample size: | -//| * if given, only N leading elements of X/Y are | -//| processed | -//| * if not given, automatically determined from | -//| input sizes | -//| Result: | -//| Spearman's rank correlation coefficient | -//| (zero for N=0 or N=1) | -//+------------------------------------------------------------------+ -static double CAlglib::SpearmanCorr2(const double &x[],const double &y[]) - { -//--- check - if(CAp::Len(x)!=CAp::Len(y)) - { - Print(__FUNCTION__+": arrays size are not equal"); - CAp::exception_happened=true; - return(EMPTY_VALUE); - } -//--- create a variable - int n=CAp::Len(x); -//--- return result - return(CBaseStat::SpearmanCorr2(x,y,n)); - } -//+------------------------------------------------------------------+ -//| Covariance matrix | -//| INPUT PARAMETERS: | -//| X - array[N,M], sample matrix: | -//| * J-th column corresponds to J-th variable | -//| * I-th row corresponds to I-th observation | -//| N - N>=0, number of observations: | -//| * if given, only leading N rows of X are used | -//| * if not given, automatically determined from input | -//| size | -//| M - M>0, number of variables: | -//| * if given, only leading M columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| OUTPUT PARAMETERS: | -//| C - array[M,M], covariance matrix (zero if N=0 or N=1) | -//+------------------------------------------------------------------+ -static void CAlglib::CovM(const CMatrixDouble &x,const int n,const int m, - CMatrixDouble &c) - { -//--- function call - CBaseStat::CovM(x,n,m,c); - } -//+------------------------------------------------------------------+ -//| Covariance matrix | -//| INPUT PARAMETERS: | -//| X - array[N,M], sample matrix: | -//| * J-th column corresponds to J-th variable | -//| * I-th row corresponds to I-th observation | -//| N - N>=0, number of observations: | -//| * if given, only leading N rows of X are used | -//| * if not given, automatically determined from input | -//| size | -//| M - M>0, number of variables: | -//| * if given, only leading M columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| OUTPUT PARAMETERS: | -//| C - array[M,M], covariance matrix (zero if N=0 or N=1) | -//+------------------------------------------------------------------+ -static void CAlglib::CovM(const CMatrixDouble &x,CMatrixDouble &c) - { -//--- create variables - int n=CAp::Rows(x); - int m=CAp::Cols(x); -//--- function call - CBaseStat::CovM(x,n,m,c); - } -//+------------------------------------------------------------------+ -//| Pearson product-moment correlation matrix | -//| INPUT PARAMETERS: | -//| X - array[N,M], sample matrix: | -//| * J-th column corresponds to J-th variable | -//| * I-th row corresponds to I-th observation | -//| N - N>=0, number of observations: | -//| * if given, only leading N rows of X are used | -//| * if not given, automatically determined from input | -//| size | -//| M - M>0, number of variables: | -//| * if given, only leading M columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| OUTPUT PARAMETERS: | -//| C - array[M,M], correlation matrix (zero if N=0 or N=1) | -//+------------------------------------------------------------------+ -static void CAlglib::PearsonCorrM(const CMatrixDouble &x,const int n, - const int m,CMatrixDouble &c) - { -//--- function call - CBaseStat::PearsonCorrM(x,n,m,c); - } -//+------------------------------------------------------------------+ -//| Pearson product-moment correlation matrix | -//| INPUT PARAMETERS: | -//| X - array[N,M], sample matrix: | -//| * J-th column corresponds to J-th variable | -//| * I-th row corresponds to I-th observation | -//| N - N>=0, number of observations: | -//| * if given, only leading N rows of X are used | -//| * if not given, automatically determined from input | -//| size | -//| M - M>0, number of variables: | -//| * if given, only leading M columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| OUTPUT PARAMETERS: | -//| C - array[M,M], correlation matrix (zero if N=0 or N=1) | -//+------------------------------------------------------------------+ -static void CAlglib::PearsonCorrM(CMatrixDouble &x,CMatrixDouble &c) - { -//--- create variables - int n=CAp::Rows(x); - int m=CAp::Cols(x); -//--- function call - CBaseStat::PearsonCorrM(x,n,m,c); - } -//+------------------------------------------------------------------+ -//| Spearman's rank correlation matrix | -//| INPUT PARAMETERS: | -//| X - array[N,M], sample matrix: | -//| * J-th column corresponds to J-th variable | -//| * I-th row corresponds to I-th observation | -//| N - N>=0, number of observations: | -//| * if given, only leading N rows of X are used | -//| * if not given, automatically determined from input | -//| size | -//| M - M>0, number of variables: | -//| * if given, only leading M columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| OUTPUT PARAMETERS: | -//| C - array[M,M], correlation matrix (zero if N=0 or N=1) | -//+------------------------------------------------------------------+ -static void CAlglib::SpearmanCorrM(const CMatrixDouble &x,const int n, - const int m,CMatrixDouble &c) - { -//--- function call - CBaseStat::SpearmanCorrM(x,n,m,c); - } -//+------------------------------------------------------------------+ -//| Spearman's rank correlation matrix | -//| INPUT PARAMETERS: | -//| X - array[N,M], sample matrix: | -//| * J-th column corresponds to J-th variable | -//| * I-th row corresponds to I-th observation | -//| N - N>=0, number of observations: | -//| * if given, only leading N rows of X are used | -//| * if not given, automatically determined from input | -//| size | -//| M - M>0, number of variables: | -//| * if given, only leading M columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| OUTPUT PARAMETERS: | -//| C - array[M,M], correlation matrix (zero if N=0 or N=1) | -//+------------------------------------------------------------------+ -static void CAlglib::SpearmanCorrM(const CMatrixDouble &x,CMatrixDouble &c) - { -//--- create variables - int n=CAp::Rows(x); - int m=CAp::Cols(x); -//--- function call - CBaseStat::SpearmanCorrM(x,n,m,c); - } -//+------------------------------------------------------------------+ -//| Cross-covariance matrix | -//| INPUT PARAMETERS: | -//| X - array[N,M1], sample matrix: | -//| * J-th column corresponds to J-th variable | -//| * I-th row corresponds to I-th observation | -//| Y - array[N,M2], sample matrix: | -//| * J-th column corresponds to J-th variable | -//| * I-th row corresponds to I-th observation | -//| N - N>=0, number of observations: | -//| * if given, only leading N rows of X/Y are used | -//| * if not given, automatically determined from input | -//| sizes | -//| M1 - M1>0, number of variables in X: | -//| * if given, only leading M1 columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| M2 - M2>0, number of variables in Y: | -//| * if given, only leading M1 columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| OUTPUT PARAMETERS: | -//| C - array[M1,M2], cross-covariance matrix (zero if N=0 or| -//| N=1) | -//+------------------------------------------------------------------+ -static void CAlglib::CovM2(const CMatrixDouble &x,const CMatrixDouble &y, - const int n,const int m1,const int m2, - CMatrixDouble &c) - { -//--- function call - CBaseStat::CovM2(x,y,n,m1,m2,c); - } -//+------------------------------------------------------------------+ -//| Cross-covariance matrix | -//| INPUT PARAMETERS: | -//| X - array[N,M1], sample matrix: | -//| * J-th column corresponds to J-th variable | -//| * I-th row corresponds to I-th observation | -//| Y - array[N,M2], sample matrix: | -//| * J-th column corresponds to J-th variable | -//| * I-th row corresponds to I-th observation | -//| N - N>=0, number of observations: | -//| * if given, only leading N rows of X/Y are used | -//| * if not given, automatically determined from input | -//| sizes | -//| M1 - M1>0, number of variables in X: | -//| * if given, only leading M1 columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| M2 - M2>0, number of variables in Y: | -//| * if given, only leading M1 columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| OUTPUT PARAMETERS: | -//| C - array[M1,M2], cross-covariance matrix (zero if N=0 or| -//| N=1) | -//+------------------------------------------------------------------+ -static void CAlglib::CovM2(const CMatrixDouble &x,const CMatrixDouble &y, - CMatrixDouble &c) - { -//--- create variables - int n=CAp::Rows(x); - int m1=CAp::Cols(x); - int m2=CAp::Cols(y); -//--- check - if(CAp::Rows(x)!=CAp::Rows(y)) - { - Print(__FUNCTION__+": rows size are not equal"); - CAp::exception_happened=true; - return; - } -//--- function call - CBaseStat::CovM2(x,y,n,m1,m2,c); - } -//+------------------------------------------------------------------+ -//| Pearson product-moment cross-correlation matrix | -//| INPUT PARAMETERS: | -//| X - array[N,M1], sample matrix: | -//| * J-th column corresponds to J-th variable | -//| * I-th row corresponds to I-th observation | -//| Y - array[N,M2], sample matrix: | -//| * J-th column corresponds to J-th variable | -//| * I-th row corresponds to I-th observation | -//| N - N>=0, number of observations: | -//| * if given, only leading N rows of X/Y are used | -//| * if not given, automatically determined from input | -//| sizes | -//| M1 - M1>0, number of variables in X: | -//| * if given, only leading M1 columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| M2 - M2>0, number of variables in Y: | -//| * if given, only leading M1 columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| OUTPUT PARAMETERS: | -//| C - array[M1,M2], cross-correlation matrix (zero if N=0 | -//| or N=1) | -//+------------------------------------------------------------------+ -static void CAlglib::PearsonCorrM2(const CMatrixDouble &x,const CMatrixDouble &y, - const int n,const int m1,const int m2, - CMatrixDouble &c) - { -//--- function call - CBaseStat::PearsonCorrM2(x,y,n,m1,m2,c); - } -//+------------------------------------------------------------------+ -//| Pearson product-moment cross-correlation matrix | -//| INPUT PARAMETERS: | -//| X - array[N,M1], sample matrix: | -//| * J-th column corresponds to J-th variable | -//| * I-th row corresponds to I-th observation | -//| Y - array[N,M2], sample matrix: | -//| * J-th column corresponds to J-th variable | -//| * I-th row corresponds to I-th observation | -//| N - N>=0, number of observations: | -//| * if given, only leading N rows of X/Y are used | -//| * if not given, automatically determined from input | -//| sizes | -//| M1 - M1>0, number of variables in X: | -//| * if given, only leading M1 columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| M2 - M2>0, number of variables in Y: | -//| * if given, only leading M1 columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| OUTPUT PARAMETERS: | -//| C - array[M1,M2], cross-correlation matrix (zero if N=0 | -//| or N=1) | -//+------------------------------------------------------------------+ -static void CAlglib::PearsonCorrM2(const CMatrixDouble &x,const CMatrixDouble &y, - CMatrixDouble &c) - { -//--- create variables - int n=CAp::Rows(x); - int m1=CAp::Cols(x); - int m2=CAp::Cols(y); -//--- check - if(CAp::Rows(x)!=CAp::Rows(y)) - { - Print(__FUNCTION__+": rows size are not equal"); - CAp::exception_happened=true; - return; - } -//--- function call - CBaseStat::PearsonCorrM2(x,y,n,m1,m2,c); - } -//+------------------------------------------------------------------+ -//| Spearman's rank cross-correlation matrix | -//| INPUT PARAMETERS: | -//| X - array[N,M1], sample matrix: | -//| * J-th column corresponds to J-th variable | -//| * I-th row corresponds to I-th observation | -//| Y - array[N,M2], sample matrix: | -//| * J-th column corresponds to J-th variable | -//| * I-th row corresponds to I-th observation | -//| N - N>=0, number of observations: | -//| * if given, only leading N rows of X/Y are used | -//| * if not given, automatically determined from input | -//| sizes | -//| M1 - M1>0, number of variables in X: | -//| * if given, only leading M1 columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| M2 - M2>0, number of variables in Y: | -//| * if given, only leading M1 columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| OUTPUT PARAMETERS: | -//| C - array[M1,M2], cross-correlation matrix (zero if N=0 | -//| or N=1) | -//+------------------------------------------------------------------+ -static void CAlglib::SpearmanCorrM2(const CMatrixDouble &x,const CMatrixDouble &y, - const int n,const int m1,const int m2, - CMatrixDouble &c) - { -//--- function call - CBaseStat::SpearmanCorrM2(x,y,n,m1,m2,c); - } -//+------------------------------------------------------------------+ -//| Spearman's rank cross-correlation matrix | -//| INPUT PARAMETERS: | -//| X - array[N,M1], sample matrix: | -//| * J-th column corresponds to J-th variable | -//| * I-th row corresponds to I-th observation | -//| Y - array[N,M2], sample matrix: | -//| * J-th column corresponds to J-th variable | -//| * I-th row corresponds to I-th observation | -//| N - N>=0, number of observations: | -//| * if given, only leading N rows of X/Y are used | -//| * if not given, automatically determined from input | -//| sizes | -//| M1 - M1>0, number of variables in X: | -//| * if given, only leading M1 columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| M2 - M2>0, number of variables in Y: | -//| * if given, only leading M1 columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| OUTPUT PARAMETERS: | -//| C - array[M1,M2], cross-correlation matrix (zero if N=0 | -//| or N=1) | -//+------------------------------------------------------------------+ -static void CAlglib::SpearmanCorrM2(const CMatrixDouble &x,const CMatrixDouble &y, - CMatrixDouble &c) - { -//--- create variables - int n=CAp::Rows(x); - int m1=CAp::Cols(x); - int m2=CAp::Cols(y); -//--- check - if(CAp::Rows(x)!=CAp::Rows(y)) - { - Print(__FUNCTION__+": rows size are not equal"); - CAp::exception_happened=true; - return; - } -//--- function call - CBaseStat::SpearmanCorrM2(x,y,n,m1,m2,c); - } -//+------------------------------------------------------------------+ -//| Pearson's correlation coefficient significance test | -//| This test checks hypotheses about whether X and Y are samples of| -//| two continuous distributions having zero correlation or whether | -//| their correlation is non-zero. | -//| The following tests are performed: | -//| * two-tailed test (null hypothesis - X and Y have zero | -//| correlation) | -//| * left-tailed test (null hypothesis - the correlation | -//| coefficient is greater than or equal to 0) | -//| * right-tailed test (null hypothesis - the correlation | -//| coefficient is less than or equal to 0). | -//| Requirements: | -//| * the number of elements in each sample is not less than 5 | -//| * normality of distributions of X and Y. | -//| Input parameters: | -//| R - Pearson's correlation coefficient for X and Y | -//| N - number of elements in samples, N>=5. | -//| Output parameters: | -//| BothTails - p-value for two-tailed test. | -//| If BothTails is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| LeftTail - p-value for left-tailed test. | -//| If LeftTail is less than the given | -//| significance level, the null hypothesis is | -//| rejected. | -//| RightTail - p-value for right-tailed test. | -//| If RightTail is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//+------------------------------------------------------------------+ -static void CAlglib::PearsonCorrelationSignificance(const double r,const int n, - double &bothTails,double &leftTail, - double &rightTail) - { -//--- function call - CCorrTests::PearsonCorrSignific(r,n,bothTails,leftTail,rightTail); - } -//+------------------------------------------------------------------+ -//| Spearman's rank correlation coefficient significance test | -//| This test checks hypotheses about whether X and Y are samples of | -//| two continuous distributions having zero correlation or whether | -//| their correlation is non-zero. | -//| The following tests are performed: | -//| * two-tailed test (null hypothesis - X and Y have zero | -//| correlation) | -//| * left-tailed test (null hypothesis - the correlation | -//| coefficient is greater than or equal to 0) | -//| * right-tailed test (null hypothesis - the correlation | -//| coefficient is less than or equal to 0). | -//| Requirements: | -//| * the number of elements in each sample is not less than 5. | -//| The test is non-parametric and doesn't require distributions X | -//| and Y to be normal. | -//| Input parameters: | -//| R - Spearman's rank correlation coefficient for X and Y | -//| N - number of elements in samples, N>=5. | -//| Output parameters: | -//| BothTails - p-value for two-tailed test. | -//| If BothTails is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| LeftTail - p-value for left-tailed test. | -//| If LeftTail is less than the given | -//| significance level, the null hypothesis is | -//| rejected. | -//| RightTail - p-value for right-tailed test. | -//| If RightTail is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//+------------------------------------------------------------------+ -static void CAlglib::SpearmanRankCorrelationSignificance(const double r, - const int n, - double &bothTails, - double &leftTail, - double &rightTail) - { -//--- function call - CCorrTests::SpearmanRankCorrSignific(r,n,bothTails,leftTail,rightTail); - } -//+------------------------------------------------------------------+ -//| Jarque-Bera test | -//| This test checks hypotheses about the fact that a given sample X | -//| is a sample of normal random variable. | -//| Requirements: | -//| * the number of elements in the sample is not less than 5. | -//| Input parameters: | -//| X - sample. Array whose index goes from 0 to N-1. | -//| N - size of the sample. N>=5 | -//| Output parameters: | -//| BothTails - p-value for two-tailed test. | -//| If BothTails is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| LeftTail - p-value for left-tailed test. | -//| If LeftTail is less than the given | -//| significance level, the null hypothesis is | -//| rejected. | -//| RightTail - p-value for right-tailed test. | -//| If RightTail is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| Accuracy of the approximation used (5<=N<=1951): | -//| p-value relative error (5<=N<=1951) | -//| [1, 0.1] < 1% | -//| [0.1, 0.01] < 2% | -//| [0.01, 0.001] < 6% | -//| [0.001, 0] wasn't measured | -//| For N>1951 accuracy wasn't measured but it shouldn't be sharply | -//| different from table values. | -//+------------------------------------------------------------------+ -static void CAlglib::JarqueBeraTest(const double &x[],const int n,double &p) - { -//--- create a variable - p=0; -//--- function call - CJarqueBera::JarqueBeraTest(x,n,p); - } -//+------------------------------------------------------------------+ -//| Mann-Whitney U-test | -//| This test checks hypotheses about whether X and Y are samples of | -//| two continuous distributions of the same shape and same median or| -//| whether their medians are different. | -//| The following tests are performed: | -//| * two-tailed test (null hypothesis - the medians are equal) | -//| * left-tailed test (null hypothesis - the median of the first| -//| sample is greater than or equal to the median of the second| -//| sample) | -//| * right-tailed test (null hypothesis - the median of the | -//| first sample is less than or equal to the median of the | -//| second sample). | -//| Requirements: | -//| * the samples are independent | -//| * X and Y are continuous distributions (or discrete | -//| distributions well- approximating continuous distributions)| -//| * distributions of X and Y have the same shape. The only | -//| possible difference is their position (i.e. the value of | -//| the median) | -//| * the number of elements in each sample is not less than 5 | -//| * the scale of measurement should be ordinal, interval or | -//| ratio (i.e. the test could not be applied to nominal | -//| variables). | -//| The test is non-parametric and doesn't require distributions to | -//| be normal. | -//| Input parameters: | -//| X - sample 1. Array whose index goes from 0 to N-1. | -//| N - size of the sample. N>=5 | -//| Y - sample 2. Array whose index goes from 0 to M-1. | -//| M - size of the sample. M>=5 | -//| Output parameters: | -//| BothTails - p-value for two-tailed test. | -//| If BothTails is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| LeftTail - p-value for left-tailed test. | -//| If LeftTail is less than the given | -//| significance level, the null hypothesis is | -//| rejected. | -//| RightTail - p-value for right-tailed test. | -//| If RightTail is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| To calculate p-values, special approximation is used. This | -//| method lets us calculate p-values with satisfactory accuracy in | -//| interval [0.0001, 1]. There is no approximation outside the | -//| [0.0001, 1] interval. Therefore, if the significance level | -//| outlies this interval, the test returns 0.0001. | -//| Relative precision of approximation of p-value: | -//| N M Max.err. Rms.err. | -//| 5..10 N..10 1.4e-02 6.0e-04 | -//| 5..10 N..100 2.2e-02 5.3e-06 | -//| 10..15 N..15 1.0e-02 3.2e-04 | -//| 10..15 N..100 1.0e-02 2.2e-05 | -//| 15..100 N..100 6.1e-03 2.7e-06 | -//| For N,M>100 accuracy checks weren't put into practice, but taking| -//| into account characteristics of asymptotic approximation used, | -//| precision should not be sharply different from the values for | -//| interval [5, 100]. | -//+------------------------------------------------------------------+ -static void CAlglib::MannWhitneyUTest(const double &x[],const int n, - const double &y[],const int m, - double &bothTails,double &leftTail, - double &rightTail) - { -//--- function call - CMannWhitneyU::CMannWhitneyUTest(x,n,y,m,bothTails,leftTail,rightTail); - } -//+------------------------------------------------------------------+ -//| Sign test | -//| This test checks three hypotheses about the median of the given | -//| sample. | -//| The following tests are performed: | -//| * two-tailed test (null hypothesis - the median is equal to | -//| the given value) | -//| * left-tailed test (null hypothesis - the median is greater | -//| than or equal to the given value) | -//| * right-tailed test (null hypothesis - the median is less | -//| than or equal to the given value) | -//| Requirements: | -//| * the scale of measurement should be ordinal, interval or | -//| ratio (i.e. the test could not be applied to nominal | -//| variables). | -//| The test is non-parametric and doesn't require distribution X to | -//| be normal | -//| Input parameters: | -//| X - sample. Array whose index goes from 0 to N-1. | -//| N - size of the sample. | -//| Median - assumed median value. | -//| Output parameters: | -//| BothTails - p-value for two-tailed test. | -//| If BothTails is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| LeftTail - p-value for left-tailed test. | -//| If LeftTail is less than the given | -//| significance level, the null hypothesis is | -//| rejected. | -//| RightTail - p-value for right-tailed test. | -//| If RightTail is less than the given | -//| significance levelthe null hypothesis is | -//| rejected. | -//| While calculating p-values high-precision binomial distribution | -//| approximation is used, so significance levels have about 15 exact| -//| digits. | -//+------------------------------------------------------------------+ -static void CAlglib::OneSampleSignTest(const double &x[],const int n, - const double median,double &bothTails, - double &leftTail,double &rightTail) - { -//--- function call - CSignTest::OneSampleSignTest(x,n,median,bothTails,leftTail,rightTail); - } -//+------------------------------------------------------------------+ -//| One-sample t-test | -//| This test checks three hypotheses about the mean of the given | -//| sample. The following tests are performed: | -//| * two-tailed test (null hypothesis - the mean is equal to the| -//| given value) | -//| * left-tailed test (null hypothesis - the mean is greater | -//| than or equal to the given value) | -//| * right-tailed test (null hypothesis - the mean is less than | -//| or equal to the given value). | -//| The test is based on the assumption that a given sample has a | -//| normal distribution and an unknown dispersion. If the | -//| distribution sharply differs from normal, the test will work | -//| incorrectly. | -//| Input parameters: | -//| X - sample. Array whose index goes from 0 to N-1. | -//| N - size of sample. | -//| Mean - assumed value of the mean. | -//| Output parameters: | -//| BothTails - p-value for two-tailed test. | -//| If BothTails is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| LeftTail - p-value for left-tailed test. | -//| If LeftTail is less than the given | -//| significance level, the null hypothesis is | -//| rejected. | -//| RightTail - p-value for right-tailed test. | -//| If RightTail is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//+------------------------------------------------------------------+ -static void CAlglib::StudentTest1(const double &x[],const int n,const double mean, - double &bothTails,double &leftTail, - double &rightTail) - { -//--- function call - CStudentTests::StudentTest1(x,n,mean,bothTails,leftTail,rightTail); - } -//+------------------------------------------------------------------+ -//| Two-sample pooled test | -//| This test checks three hypotheses about the mean of the given | -//| samples. The following tests are performed: | -//| * two-tailed test (null hypothesis - the means are equal) | -//| * left-tailed test (null hypothesis - the mean of the first | -//| sample is greater than or equal to the mean of the second | -//| sample) | -//| * right-tailed test (null hypothesis - the mean of the first | -//| sample is less than or equal to the mean of the second | -//| sample). | -//| Test is based on the following assumptions: | -//| * given samples have normal distributions | -//| * dispersions are equal | -//| * samples are independent. | -//| Input parameters: | -//| X - sample 1. Array whose index goes from 0 to N-1. | -//| N - size of sample. | -//| Y - sample 2. Array whose index goes from 0 to M-1. | -//| M - size of sample. | -//| Output parameters: | -//| BothTails - p-value for two-tailed test. | -//| If BothTails is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| LeftTail - p-value for left-tailed test. | -//| If LeftTail is less than the given | -//| significance level, the null hypothesis is | -//| rejected. | -//| RightTail - p-value for right-tailed test. | -//| If RightTail is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//+------------------------------------------------------------------+ -static void CAlglib::StudentTest2(const double &x[],const int n,const double &y[], - const int m,double &bothTails, - double &leftTail,double &rightTail) - { -//--- function call - CStudentTests::StudentTest2(x,n,y,m,bothTails,leftTail,rightTail); - } -//+------------------------------------------------------------------+ -//| Two-sample unpooled test | -//| This test checks three hypotheses about the mean of the given | -//| samples. The following tests are performed: | -//| * two-tailed test (null hypothesis - the means are equal) | -//| * left-tailed test (null hypothesis - the mean of the first | -//| sample is greater than or equal to the mean of the second | -//| sample) | -//| * right-tailed test (null hypothesis - the mean of the first | -//| sample is less than or equal to the mean of the second | -//| sample). | -//| Test is based on the following assumptions: | -//| * given samples have normal distributions | -//| * samples are independent. | -//| Dispersion equality is not required | -//| Input parameters: | -//| X - sample 1. Array whose index goes from 0 to N-1. | -//| N - size of the sample. | -//| Y - sample 2. Array whose index goes from 0 to M-1. | -//| M - size of the sample. | -//| Output parameters: | -//| BothTails - p-value for two-tailed test. | -//| If BothTails is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| LeftTail - p-value for left-tailed test. | -//| If LeftTail is less than the given | -//| significance level, the null hypothesis is | -//| rejected. | -//| RightTail - p-value for right-tailed test. | -//| If RightTail is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//+------------------------------------------------------------------+ -static void CAlglib::UnequalVarianceTest(const double &x[],const int n, - const double &y[],const int m, - double &bothTails,double &leftTail, - double &rightTail) - { -//--- function call - CStudentTests::UnequalVarianceTest(x,n,y,m,bothTails,leftTail,rightTail); - } -//+------------------------------------------------------------------+ -//| Two-sample F-test | -//| This test checks three hypotheses about dispersions of the given | -//| samples. The following tests are performed: | -//| * two-tailed test (null hypothesis - the dispersions are | -//| equal) | -//| * left-tailed test (null hypothesis - the dispersion of the | -//| first sample is greater than or equal to the dispersion of | -//| the second sample). | -//| * right-tailed test (null hypothesis - the dispersion of the | -//| first sample is less than or equal to the dispersion of | -//| the second sample) | -//| The test is based on the following assumptions: | -//| * the given samples have normal distributions | -//| * the samples are independent. | -//| Input parameters: | -//| X - sample 1. Array whose index goes from 0 to N-1. | -//| N - sample size. | -//| Y - sample 2. Array whose index goes from 0 to M-1. | -//| M - sample size. | -//| Output parameters: | -//| BothTails - p-value for two-tailed test. | -//| If BothTails is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| LeftTail - p-value for left-tailed test. | -//| If LeftTail is less than the given | -//| significance level, the null hypothesis is | -//| rejected. | -//| RightTail - p-value for right-tailed test. | -//| If RightTail is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//+------------------------------------------------------------------+ -static void CAlglib::FTest(const double &x[],const int n,const double &y[], - const int m,double &bothTails,double &leftTail, - double &rightTail) - { -//--- function call - CVarianceTests::FTest(x,n,y,m,bothTails,leftTail,rightTail); - } -//+------------------------------------------------------------------+ -//| One-sample chi-square test | -//| This test checks three hypotheses about the dispersion of the | -//| given sample The following tests are performed: | -//| * two-tailed test (null hypothesis - the dispersion equals | -//| the given number) | -//| * left-tailed test (null hypothesis - the dispersion is | -//| greater than or equal to the given number) | -//| * right-tailed test (null hypothesis - dispersion is less | -//| than or equal to the given number). | -//| Test is based on the following assumptions: | -//| * the given sample has a normal distribution. | -//| Input parameters: | -//| X - sample 1. Array whose index goes from 0 to | -//| N-1. | -//| N - size of the sample. | -//| Variance - dispersion value to compare with. | -//| Output parameters: | -//| BothTails - p-value for two-tailed test. | -//| If BothTails is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| LeftTail - p-value for left-tailed test. | -//| If LeftTail is less than the given | -//| significance level, the null hypothesis is | -//| rejected. | -//| RightTail - p-value for right-tailed test. | -//| If RightTail is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//+------------------------------------------------------------------+ -static void CAlglib::OneSampleVarianceTest(double &x[],int n,double variance, - double &bothTails,double &leftTail, - double &rightTail) - { -//--- function call - CVarianceTests::OneSampleVarianceTest(x,n,variance,bothTails,leftTail,rightTail); - } -//+------------------------------------------------------------------+ -//| Wilcoxon signed-rank test | -//| This test checks three hypotheses about the median of the given | -//| sample. The following tests are performed: | -//| * two-tailed test (null hypothesis - the median is equal to | -//| the given value) | -//| * left-tailed test (null hypothesis - the median is greater | -//| than or equal to the given value) | -//| * right-tailed test (null hypothesis - the median is less | -//| than or equal to the given value) | -//| Requirements: | -//| * the scale of measurement should be ordinal, interval or | -//| ratio (i.e. the test could not be applied to nominal | -//| variables). | -//| * the distribution should be continuous and symmetric | -//| relative to its median. | -//| * number of distinct values in the X array should be greater | -//| than 4 | -//| The test is non-parametric and doesn't require distribution X to | -//| be normal | -//| Input parameters: | -//| X - sample. Array whose index goes from 0 to N-1. | -//| N - size of the sample. | -//| Median - assumed median value. | -//| Output parameters: | -//| BothTails - p-value for two-tailed test. | -//| If BothTails is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| LeftTail - p-value for left-tailed test. | -//| If LeftTail is less than the given | -//| significance level, the null hypothesis is | -//| rejected. | -//| RightTail - p-value for right-tailed test. | -//| If RightTail is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| To calculate p-values, special approximation is used. This method| -//| lets us calculate p-values with two decimal places in interval | -//| [0.0001, 1]. | -//| "Two decimal places" does not sound very impressive, but in | -//| practice the relative error of less than 1% is enough to make a | -//| decision. | -//| There is no approximation outside the [0.0001, 1] interval. | -//| Therefore, if the significance level outlies this interval, the | -//| test returns 0.0001. | -//+------------------------------------------------------------------+ -static void CAlglib::WilcoxonSignedRankTest(const double &x[],const int n, - const double e,double &bothTails, - double &leftTail,double &rightTail) - { -//--- function call - CWilcoxonSignedRank::WilcoxonSignedRankTest(x,n,e,bothTails,leftTail,rightTail); - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Alglib/alglibinternal.mqh b/Include/Math/Alglib/alglibinternal.mqh deleted file mode 100644 index 81031a5..0000000 --- a/Include/Math/Alglib/alglibinternal.mqh +++ /dev/null @@ -1,9732 +0,0 @@ -//+------------------------------------------------------------------+ -//| alglibinternal.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 "ap.mqh" -//+------------------------------------------------------------------+ -//| Class stores serialized codes | -//+------------------------------------------------------------------+ -class CSCodes - { -public: - CSCodes(void); - ~CSCodes(void); - - static int GetRDFSerializationCode(void) { return(1); } - static int GetKDTreeSerializationCode(void) { return(2); } - static int GetMLPSerializationCode(void) { return(3); } - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CSCodes::CSCodes(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSCodes::~CSCodes(void) - { - - } -//+------------------------------------------------------------------+ -//| Buffers for internal functions which need buffers: | -//| * check for size of the buffer you want to use. | -//| * if buffer is too small, resize it; leave unchanged, if it is | -//| larger than needed. | -//| * use it. | -//| We can pass this structure to multiple functions; after first | -//| run through functions buffer sizes will be finally determined, | -//| and on a next run no allocation will be required. | -//+------------------------------------------------------------------+ -class CApBuff - { -public: - //--- arrays - int m_ia0[]; - int m_ia1[]; - int m_ia2[]; - int m_ia3[]; - double m_ra0[]; - double m_ra1[]; - double m_ra2[]; - double m_ra3[]; - //--- constructor, destructor - CApBuff(void); - ~CApBuff(void); - //--- copy - void Copy(CApBuff &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CApBuff::CApBuff(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CApBuff::~CApBuff(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CApBuff::Copy(CApBuff &obj) - { -//--- copy arrays - ArrayCopy(m_ia0,obj.m_ia0); - ArrayCopy(m_ia1,obj.m_ia1); - ArrayCopy(m_ia2,obj.m_ia2); - ArrayCopy(m_ia3,obj.m_ia3); - ArrayCopy(m_ra0,obj.m_ra0); - ArrayCopy(m_ra1,obj.m_ra1); - ArrayCopy(m_ra2,obj.m_ra2); - ArrayCopy(m_ra3,obj.m_ra3); - } -//+------------------------------------------------------------------+ -//| Basic functions | -//+------------------------------------------------------------------+ -class CApServ - { -public: - CApServ(void); - ~CApServ(void); - //--- generate interpolation - static void TaskGenInt1D(const double a,const double b,const int n,double &x[],double &y[]); - static void TaskGenInt1DEquidist(const double a,const double b,const int n,double &x[],double &y[]); - static void TaskGenInt1DCheb1(const double a,const double b,const int n,double &x[],double &y[]); - static void TaskGenInt1DCheb2(const double a,const double b,const int n,double &x[],double &y[]); - //--- distinct - static bool AreDistinct(double &x[],const int n); - //--- resize arrays - static void BVectorSetLengthAtLeast(bool &x[],const int n); - static void IVectorSetLengthAtLeast(int &x[],const int n); - static void RVectorSetLengthAtLeast(double &x[],const int n); - static void RMatrixSetLengthAtLeast(CMatrixDouble &x,const int m,const int n); - //--- resize matrix - static void RMatrixResize(CMatrixDouble &x,const int m,const int n); - //--- check to infinity - static bool IsFiniteVector(const double &x[],const int n); - static bool IsFiniteComplexVector(al_complex &z[],const int n); - static bool IsFiniteMatrix(const CMatrixDouble &x,const int m,const int n); - static bool IsFiniteComplexMatrix(CMatrixComplex &x,const int m,const int n); - static bool IsFiniteRTrMatrix(CMatrixDouble &x,const int n,const bool isupper); - static bool IsFiniteCTrMatrix(CMatrixComplex &x,const int n,const bool isupper); - static bool IsFiniteOrNaNMatrix(CMatrixDouble &x,const int m,const int n); - //--- safe methods - static double SafePythag2(const double x,const double y); - static double SafePythag3(double x,double y,double z); - static int SafeRDiv(double x,double y,double &r); - static double SafeMinPosRV(const double x,const double y,const double v); - static void ApPeriodicMap(double &x,const double a,const double b,double &k); - static double BoundVal(const double x,const double b1,const double b2); - //--- serialization/unserialization - static void AllocComplex(CSerializer &s,al_complex &v); - static void SerializeComplex(CSerializer &s,al_complex &v); - static al_complex UnserializeComplex(CSerializer &s); - static void AllocRealArray(CSerializer &s,double &v[],int n); - static void SerializeRealArray(CSerializer &s,double &v[],int n); - static void UnserializeRealArray(CSerializer &s,double &v[]); - static void AllocIntegerArray(CSerializer &s,int &v[],int n); - static void SerializeIntegerArray(CSerializer &s,int &v[],int n); - static void UnserializeIntegerArray(CSerializer &s,int &v[]); - static void AllocRealMatrix(CSerializer &s,CMatrixDouble &v,int n0,int n1); - static void SerializeRealMatrix(CSerializer &s,CMatrixDouble &v,int n0,int n1); - static void UnserializeRealMatrix(CSerializer &s,CMatrixDouble &v); - //--- copy - static void CopyIntegerArray(int &src[],int &dst[]); - static void CopyRealArray(double &src[],double &dst[]); - static void CopyRealMatrix(CMatrixDouble &src,CMatrixDouble &dst); - //--- check array - static int RecSearch(int &a[],const int nrec,const int nheader,int i0,int i1,int &b[]); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CApServ::CApServ(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CApServ::~CApServ(void) - { - - } -//+------------------------------------------------------------------+ -//| This function generates 1-dimensional general interpolation | -//| task with moderate Lipshitz constant (close to 1.0) | -//| If N=1 then suborutine generates only one point at the middle | -//| of [A,B] | -//+------------------------------------------------------------------+ -static void CApServ::TaskGenInt1D(const double a,const double b,const int n, - double &x[],double &y[]) - { -//--- create variables - int i=0; - double h=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- allocation - ArrayResizeAL(x,n); - ArrayResizeAL(y,n); -//--- check - if(n>1) - { - //--- change values - x[0]=a; - y[0]=2*CMath::RandomReal()-1; - h=(b-a)/(n-1); - for(i=1;i<=n-1;i++) - { - //--- check - if(i!=n-1) - x[i]=a+(i+0.2*(2*CMath::RandomReal()-1))*h; - else - x[i]=b; - y[i]=y[i-1]+(2*CMath::RandomReal()-1)*(x[i]-x[i-1]); - } - } - else - { - //--- change values - x[0]=0.5*(a+b); - y[0]=2*CMath::RandomReal()-1; - } - } -//+------------------------------------------------------------------+ -//| This function generates 1-dimensional equidistant interpolation | -//| task withmoderate Lipshitz constant(close to 1.0) | -//| If N=1 then suborutine generates only one point at the middle | -//| of[A,B] | -//+------------------------------------------------------------------+ -static void CApServ::TaskGenInt1DEquidist(const double a,const double b, - const int n,double &x[],double &y[]) - { -//--- create variables - int i=0; - double h=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- allocation - ArrayResizeAL(x,n); - ArrayResizeAL(y,n); -//--- check - if(n>1) - { - //--- change values - x[0]=a; - y[0]=2*CMath::RandomReal()-1; - h=(b-a)/(n-1); - for(i=1;i<=n-1;i++) - { - x[i]=a+i*h; - y[i]=y[i-1]+(2*CMath::RandomReal()-1)*h; - } - } - else - { - //--- change values - x[0]=0.5*(a+b); - y[0]=2*CMath::RandomReal()-1; - } - } -//+------------------------------------------------------------------+ -//| This function generates 1-dimensional Chebyshev-1 interpolation | -//| task with moderate Lipshitz constant(close to 1.0) | -//| If N=1 then suborutine generates only one point at the middle | -//| of[A,B] | -//+------------------------------------------------------------------+ -static void CApServ::TaskGenInt1DCheb1(const double a,const double b, - const int n,double &x[],double &y[]) - { -//--- create a variable - int i=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- allocation - ArrayResizeAL(x,n); - ArrayResizeAL(y,n); -//--- check - if(n>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) - y[i]=2*CMath::RandomReal()-1; - else - y[i]=y[i-1]+(2*CMath::RandomReal()-1)*(x[i]-x[i-1]); - } - } - else - { - //--- change values - x[0]=0.5*(a+b); - y[0]=2*CMath::RandomReal()-1; - } - } -//+------------------------------------------------------------------+ -//| This function generates 1-dimensional Chebyshev-2 interpolation | -//| task with moderate Lipshitz constant(close to 1.0) | -//| If N=1 then suborutine generates only one point at the middle | -//| of[A,B] | -//+------------------------------------------------------------------+ -static void CApServ::TaskGenInt1DCheb2(const double a,const double b, - const int n,double &x[],double &y[]) - { -//--- create a variable - int i=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- allocation - ArrayResizeAL(x,n); - ArrayResizeAL(y,n); -//--- check - if(n>1) - { - for(i=0;i<=n-1;i++) - { - x[i]=0.5*(b+a)+0.5*(b-a)*MathCos(M_PI*i/(n-1)); - //--- check - if(i==0) - y[i]=2*CMath::RandomReal()-1; - else - y[i]=y[i-1]+(2*CMath::RandomReal()-1)*(x[i]-x[i-1]); - } - } - else - { - //--- change values - x[0]=0.5*(a+b); - y[0]=2*CMath::RandomReal()-1; - } - } -//+------------------------------------------------------------------+ -//| This function checks that all values from X[] are distinct. | -//| It does more than just usual floating point comparison: | -//| * first, it calculates max(X) and min(X) | -//| * second, it maps X[] from [min,max] to [1,2] | -//| * only at this stage actual comparison is done | -//| The meaning of such check is to ensure that all values are | -//| "distinct enough" and will not cause interpolation subroutine | -//| to fail. | -//| NOTE: | -//| X[] must be sorted by ascending (subroutine ASSERT's it) | -//+------------------------------------------------------------------+ -static bool CApServ::AreDistinct(double &x[],const int n) - { -//--- create variables - double a=0; - double b=0; - int i=0; - bool nonsorted; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": internal error (N<1)")) - return(false); -//--- check - if(n==1) - { - //--- everything is alright, it is up to caller to decide whether it - //--- can interpolate something with just one point - return(true); - } -//--- initialization - a=x[0]; - b=x[0]; - nonsorted=false; - for(i=1;i<=n-1;i++) - { - a=MathMin(a,x[i]); - b=MathMax(b,x[i]); - nonsorted=nonsorted || x[i-1]>=x[i]; - } -//--- check - if(!CAp::Assert(!nonsorted,__FUNCTION__+": internal error (not sorted)")) - return(false); - for(i=1;i<=n-1;i++) - { - //--- check - if((x[i]-a)/(b-a)+1==(x[i-1]-a)/(b-a)+1) - return(false); - } -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| If Length(X)=0,__FUNCTION__+": internal error (N<0)")) - return(false); - for(i=0;i<=n-1;i++) - { - //--- check - if(!CMath::IsFinite(z[i].re) || !CMath::IsFinite(z[i].im)) - return(false); - } -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| This function checks that all values from X[] are finite | -//+------------------------------------------------------------------+ -static bool CApServ::IsFiniteVector(const double &x[],const int n) - { -//--- check - if(!CAp::Assert(n>=0,__FUNCTION__+": the error variable")) - return(false); -//--- is finite? - for(int i=0;i=0,__FUNCTION__+": the error variable")) - return(false); -//--- check - if(!CAp::Assert(m>=0,__FUNCTION__+": the error variable")) - return(false); -//--- is finite? - for(int i=0;i=0,__FUNCTION__+": internal error (N<0)")) - return(false); -//--- check - if(!CAp::Assert(m>=0,__FUNCTION__+": internal error (M<0)")) - return(false); -//--- is finite? - for(i=0;i=0,__FUNCTION__+": internal error (N<0)")) - return(false); - for(i=0;i<=n-1;i++) - { - //--- check - if(isupper) - { - j1=i; - j2=n-1; - } - else - { - j1=0; - j2=i; - } - for(j=j1;j<=j2;j++) - { - //--- check - if(!CMath::IsFinite(x[i][j])) - return(false); - } - } -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| This function checks that all values from upper/lower triangle of| -//| X[0..N-1,0..N-1] are finite | -//+------------------------------------------------------------------+ -static bool CApServ::IsFiniteCTrMatrix(CMatrixComplex &x,const int n, - const bool isupper) - { -//--- create variables - int i=0; - int j1=0; - int j2=0; - int j=0; -//--- check - if(!CAp::Assert(n>=0,__FUNCTION__+": internal error (N<0)")) - return(false); - for(i=0;i<=n-1;i++) - { - //--- check - if(isupper) - { - j1=i; - j2=n-1; - } - else - { - j1=0; - j2=i; - } - for(j=j1; j<=j2; j++) - { - //--- check - if(!CMath::IsFinite(x[i][j].re) || !CMath::IsFinite(x[i][j].im)) - return(false); - } - } -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| This function checks that all values from X[0..M-1,0..N-1] are | -//| finite or NaN's. | -//+------------------------------------------------------------------+ -static bool CApServ::IsFiniteOrNaNMatrix(CMatrixDouble &x,const int m, - const int n) - { -//--- create variables - int i=0; - int j=0; -//--- check - if(!CAp::Assert(n>=0,__FUNCTION__+": internal error (N<0)")) - return(false); -//--- check - if(!CAp::Assert(m>=0,__FUNCTION__+": internal error (M<0)")) - return(false); - for(i=0;i<=m-1;i++) - { - for(j=0;j<=n-1;j++) - { - //--- check - if(!(CMath::IsFinite(x[i][j]) || CInfOrNaN::IsNaN(x[i][j]))) - return(false); - } - } -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Safe sqrt(x^2+y^2) | -//+------------------------------------------------------------------+ -static double CApServ::SafePythag2(const double x,const double y) - { -//--- create variables - double result=0; - double w=0; - double xabs=0; - double yabs=0; - double z=0; -//--- initialization - xabs=MathAbs(x); - yabs=MathAbs(y); - w=MathMax(xabs,yabs); - z=MathMin(xabs,yabs); -//--- check - if(z==0.0) - result=w; - else - result=w*MathSqrt(1+CMath::Sqr(z/w)); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Safe sqrt(x^2+y^2) | -//+------------------------------------------------------------------+ -static double CApServ::SafePythag3(double x,double y,double z) - { -//--- create a variable - double w=0; -//--- initialization - w=MathMax(MathAbs(x),MathMax(MathAbs(y),MathAbs(z))); -//--- check - if(w==0.0) - return(0); -//--- change values - x=x/w; - y=y/w; - z=z/w; -//--- return result - return(w*MathSqrt(CMath::Sqr(x)+CMath::Sqr(y)+CMath::Sqr(z))); - } -//+------------------------------------------------------------------+ -//| Safe division. | -//| This function attempts to calculate R=X/Y without overflow. | -//| It returns: | -//| * +1, if abs(X/Y)>=MaxRealNumber or undefined - overflow-like | -//| situation (no overlfow is generated, R is either NAN, | -//| PosINF, NegINF) | -//| * 0, if MinRealNumber0 | -//| (R contains result, may be zero) | -//| * -1, if 00 - if(y==0.0) - { - result=1; - //--- check - if(x==0.0) - r=CInfOrNaN::NaN(); - //--- check - if(x>0.0) - r=CInfOrNaN::PositiveInfinity(); - //--- check - if(x<0.0) - r=CInfOrNaN::NegativeInfinity(); - //--- return result - return(result); - } -//--- check - if(x==0.0) - { - r=0; - result=0; - //--- return result - return(result); - } -//--- make Y>0 - if(y<0.0) - { - x=-x; - y=-y; - } -//--- check - if(y>=1.0) - { - r=x/y; - //--- check - if(MathAbs(r)<=CMath::m_minrealnumber) - { - result=-1; - r=0; - } - else - result=0; - } - else - { - //--- check - if(MathAbs(x)>=CMath::m_maxrealnumber*y) - { - //--- check - if(x>0.0) - r=CInfOrNaN::PositiveInfinity(); - else - r=CInfOrNaN::NegativeInfinity(); - result=1; - } - else - { - r=x/y; - result=0; - } - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| This function calculates "safe" min(X/Y,V) for positive finite X,| -//| Y, V. No overflow is generated in any case. | -//+------------------------------------------------------------------+ -static double CApServ::SafeMinPosRV(const double x,const double y,const double v) - { -//--- create variables - double result=0; - double r=0; -//--- check - if(y>=1.0) - { - //--- Y>=1, we can safely divide by Y - r=x/y; - result=v; - //--- check - if(v>r) - result=r; - else - result=v; - } - else - { - //--- Y<1, we can safely multiply by Y - if(xB). It returns T which lies in [A,B] and | -//| integer K, such that X = T + K*(B-A). | -//| NOTES: | -//| * K is represented as real value, although actually it is integer| -//| * T is guaranteed to be in [A,B] | -//| * T replaces X | -//+------------------------------------------------------------------+ -static void CApServ::ApPeriodicMap(double &x,const double a,const double b, - double &k) - { -//--- initialization - k=0; -//--- check - if(!CAp::Assert(ab) - { - x=x-(b-a); - k=k+1; - } -//--- change values - x=MathMax(x,a); - x=MathMin(x,b); - } -//+------------------------------------------------------------------+ -//| 'bounds' value: maps X to [B1,B2] | -//+------------------------------------------------------------------+ -static double CApServ::BoundVal(const double x,const double b1,const double b2) - { -//--- check - if(x<=b1) - return(b1); -//--- check - if(x>=b2) - return(b2); -//--- return result - return(x); - } -//+------------------------------------------------------------------+ -//| Allocation of serializer: complex value | -//+------------------------------------------------------------------+ -static void CApServ::AllocComplex(CSerializer &s,al_complex &v) - { -//--- entry - s.Alloc_Entry(); - s.Alloc_Entry(); - } -//+------------------------------------------------------------------+ -//| Serialization: complex value | -//+------------------------------------------------------------------+ -static void CApServ::SerializeComplex(CSerializer &s,al_complex &v) - { -//--- serialization - s.Serialize_Double(v.re); - s.Serialize_Double(v.im); - } -//+------------------------------------------------------------------+ -//| Unserialization: complex value | -//+------------------------------------------------------------------+ -static al_complex CApServ::UnserializeComplex(CSerializer &s) - { -//--- create a variable - al_complex result; -//--- unserialization - result.re=s.Unserialize_Double(); - result.im=s.Unserialize_Double(); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Allocation of serializer: real array | -//+------------------------------------------------------------------+ -static void CApServ::AllocRealArray(CSerializer &s,double &v[],int n) - { -//--- create a variable - int i=0; -//--- check - if(n<0) - n=CAp::Len(v); -//--- entry - s.Alloc_Entry(); - for(i=0;i<=n-1;i++) - s.Alloc_Entry(); - } -//+------------------------------------------------------------------+ -//| Serialization: real array | -//+------------------------------------------------------------------+ -static void CApServ::SerializeRealArray(CSerializer &s,double &v[],int n) - { -//--- create a variable - int i=0; -//--- check - if(n<0) - n=CAp::Len(v); -//--- serialization - s.Serialize_Int(n); - for(i=0;i<=n-1;i++) - s.Serialize_Double(v[i]); - } -//+------------------------------------------------------------------+ -//| Unserialization: real array | -//+------------------------------------------------------------------+ -static void CApServ::UnserializeRealArray(CSerializer &s,double &v[]) - { -//--- create variables - int n=0; - int i=0; - double t=0; -//--- unserialization - n=s.Unserialize_Int(); -//--- check - if(n==0) - return; -//--- allocation - ArrayResizeAL(v,n); -//--- unserialization - for(i=0;i<=n-1;i++) - { - t=s.Unserialize_Double(); - v[i]=t; - } - } -//+------------------------------------------------------------------+ -//| Allocation of serializer: Integer array | -//+------------------------------------------------------------------+ -static void CApServ::AllocIntegerArray(CSerializer &s,int &v[],int n) - { -//--- create a variable - int i=0; -//--- check - if(n<0) - n=CAp::Len(v); -//--- entry - s.Alloc_Entry(); - for(i=0;i<=n-1;i++) - s.Alloc_Entry(); - } -//+------------------------------------------------------------------+ -//| Serialization: Integer array | -//+------------------------------------------------------------------+ -static void CApServ::SerializeIntegerArray(CSerializer &s,int &v[],int n) - { -//--- create a variable - int i=0; -//--- check - if(n<0) - n=CAp::Len(v); -//--- serialization - s.Serialize_Int(n); - for(i=0;i<=n-1;i++) - s.Serialize_Int(v[i]); - } -//+------------------------------------------------------------------+ -//| Unserialization: Integer array | -//+------------------------------------------------------------------+ -static void CApServ::UnserializeIntegerArray(CSerializer &s,int &v[]) - { -//--- create variables - int n=0; - int i=0; - int t=0; -//--- unserialization - n=s.Unserialize_Int(); -//--- check - if(n==0) - return; -//--- allocation - ArrayResizeAL(v,n); - for(i=0;i<=n-1;i++) - { - t=s.Unserialize_Int(); - v[i]=t; - } - } -//+------------------------------------------------------------------+ -//| Allocation of serializer: real matrix | -//+------------------------------------------------------------------+ -static void CApServ::AllocRealMatrix(CSerializer &s,CMatrixDouble &v,int n0,int n1) - { -//--- create variables - int i=0; - int j=0; -//--- check - if(n0<0) - n0=CAp::Rows(v); -//--- check - if(n1<0) - n1=CAp::Cols(v); -//--- entry - s.Alloc_Entry(); - s.Alloc_Entry(); - for(i=0;i<=n0-1;i++) - { - for(j=0;j<=n1-1;j++) - s.Alloc_Entry(); - } - } -//+------------------------------------------------------------------+ -//| Serialization: real matrix | -//+------------------------------------------------------------------+ -static void CApServ::SerializeRealMatrix(CSerializer &s,CMatrixDouble &v,int n0,int n1) - { -//--- create variables - int i=0; - int j=0; -//--- check - if(n0<0) - n0=CAp::Rows(v); -//--- check - if(n1<0) - n1=CAp::Cols(v); -//--- serialization - s.Serialize_Int(n0); -//--- serialization - s.Serialize_Int(n1); - for(i=0;i<=n0-1;i++) - for(j=0;j<=n1-1;j++) - s.Serialize_Double(v[i][j]); - } -//+------------------------------------------------------------------+ -//| Unserialization: real matrix | -//+------------------------------------------------------------------+ -static void CApServ::UnserializeRealMatrix(CSerializer &s,CMatrixDouble &v) - { -//--- create variables - int i=0; - int j=0; - int n0=0; - int n1=0; - double t=0; -//--- unserialization - n0=s.Unserialize_Int(); - n1=s.Unserialize_Int(); -//--- check - if(n0==0 || n1==0) - return; -//--- resize - v.Resize(n0,n1); -//--- unserialization - for(i=0;i<=n0-1;i++) - for(j=0;j<=n1-1;j++) - { - t=s.Unserialize_Double(); - v[i].Set(j,t); - } - } -//+------------------------------------------------------------------+ -//| Copy integer array | -//+------------------------------------------------------------------+ -static void CApServ::CopyIntegerArray(int &src[],int &dst[]) - { - int i=0; -//--- check - if(CAp::Len(src)>0) - { - //--- allocation - ArrayResizeAL(dst,CAp::Len(src)); - //--- copy - for(i=0;i<=CAp::Len(src)-1;i++) - dst[i]=src[i]; - } - } -//+------------------------------------------------------------------+ -//| Copy real array | -//+------------------------------------------------------------------+ -static void CApServ::CopyRealArray(double &src[],double &dst[]) - { - int i=0; -//--- check - if(CAp::Len(src)>0) - { - ArrayResizeAL(dst,CAp::Len(src)); - for(i=0;i<=CAp::Len(src)-1;i++) - dst[i]=src[i]; - } - } -//+------------------------------------------------------------------+ -//| Copy real matrix | -//+------------------------------------------------------------------+ -static void CApServ::CopyRealMatrix(CMatrixDouble &src,CMatrixDouble &dst) - { -//--- create variables - int i=0; - int j=0; -//--- check - if(CAp::Rows(src)>0 && CAp::Cols(src)>0) - { - dst.Resize(CAp::Rows(src),CAp::Cols(src)); - //--- copy - for(i=0;i<=CAp::Rows(src)-1;i++) - for(j=0;j<=CAp::Cols(src)-1;j++) - dst[i].Set(j,src[i][j]); - } - } -//+------------------------------------------------------------------+ -//| This function searches integer array. Elements in this array are | -//| actually records, each NRec elements wide. Each record has unique| -//| header - NHeader integer values, which identify it. Records are | -//| lexicographically sorted by header. | -//| Records are identified by their index, not offset | -//| (offset = NRec*index). | -//| This function searches A (records with indices [I0,I1)) for a | -//| record with header B. It returns index of this record | -//| (not offset!), or -1 on failure. | -//+------------------------------------------------------------------+ -static int CApServ::RecSearch(int &a[],const int nrec,const int nheader,int i0,int i1,int &b[]) - { -//--- create variables - int mididx=0; - int cflag=0; - int k=0; - int offs=0; -//--- cycle - while(true) - { - //--- check - if(i0>=i1) - break; - //--- change values - mididx=(i0+i1)/2; - offs=nrec*mididx; - cflag=0; - for(k=0;k<=nheader-1;k++) - { - //--- check - if(a[offs+k]b[k]) - { - cflag=1; - break; - } - } - //--- check - if(cflag==0) - { - return(mididx); - } - //--- check - if(cflag<0) - i0=mididx+1; - else - i1=mididx; - } -//--- return result - return(-1); - } -//+------------------------------------------------------------------+ -//| Tag Sort | -//+------------------------------------------------------------------+ -class CTSort - { -private: - //--- private methods - static void TagSortFastIRec(double &a[],int &b[],double &bufa[],int &bufb[],const int i1,const int i2); - static void TagSortFastRRec(double &a[],double &b[],double &bufa[],double &bufb[],const int i1,const int i2); - static void TagSortFastRec(double &a[],double &bufa[],const int i1,const int i2); -public: - CTSort(void); - ~CTSort(void); - //--- public methods - static void TagSort(double &a[],const int n,int &p1[],int &p2[]); - static void TagSortBuf(double &a[],const int n,int &p1[],int &p2[],CApBuff &buf); - static void TagSortFastI(double &a[],int &b[],double &bufa[],int &bufb[],const int n); - static void TagSortFastR(double &a[],double &b[],double &bufa[],double &bufb[],const int n); - static void TagSortFast(double &a[],double &bufa[],const int n); - static void TagHeapPushI(double &a[],int &b[],int &n,const double va,const int vb); - static void TagHeapReplaceTopI(double &a[],int &b[],const int n,const double va,const int vb); - static void TagHeapPopI(double &a[],int &b[],int &n); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CTSort::CTSort(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CTSort::~CTSort(void) - { - - } -//+------------------------------------------------------------------+ -//| This function sorts array of real keys by ascending. | -//| Its results are: | -//| * sorted array A | -//| * permutation tables P1, P2 | -//| Algorithm outputs permutation tables using two formats: | -//| * as usual permutation of [0..N-1]. If P1[i]=j, then sorted A[i] | -//| contains value which was moved there from J-th position. | -//| * as a sequence of pairwise permutations. Sorted A[] may be | -//| obtained byswaping A[i] and A[P2[i]] for all i from 0 to N-1. | -//| INPUT PARAMETERS: | -//| A - unsorted array | -//| N - array size | -//| OUPUT PARAMETERS: | -//| A - sorted array | -//| P1, P2 - permutation tables, array[N] | -//| NOTES: | -//| this function assumes that A[] is finite; it doesn't checks | -//| that condition. All other conditions (size of input arrays, | -//| etc.) are not checked too. | -//+------------------------------------------------------------------+ -static void CTSort::TagSort(double &a[],const int n,int &p1[],int &p2[]) - { -//--- create a variable - CApBuff buf; -//--- function call - TagSortBuf(a,n,p1,p2,buf); - } -//+------------------------------------------------------------------+ -//| Buffered variant of TagSort, which accepts preallocated output | -//| arrays as well as special structure for buffered allocations. If | -//| arrays are too short, they are reallocated. If they are large | -//| enough, no memoryallocation is done. | -//| It is intended to be used in the performance-critical parts of | -//| code, where additional allocations can lead to severe performance| -//| degradation | -//+------------------------------------------------------------------+ -static void CTSort::TagSortBuf(double &a[],const int n,int &p1[],int &p2[], - CApBuff &buf) - { -//--- create variables - int i=0; - int lv=0; - int lp=0; - int rv=0; - int rp=0; -//--- Special cases - if(n<=0) - return; -//--- check - if(n==1) - { - //--- function call - CApServ::IVectorSetLengthAtLeast(p1,1); - //--- function call - CApServ::IVectorSetLengthAtLeast(p2,1); - p1[0]=0; - p2[0]=0; - //--- exit the function - return; - } -//--- General case, N>1: prepare permutations table P1 - CApServ::IVectorSetLengthAtLeast(p1,n); - for(i=0;i<=n-1;i++) - p1[i]=i; -//--- General case, N>1: sort, update P1 - CApServ::RVectorSetLengthAtLeast(buf.m_ra0,n); -//--- function call - CApServ::IVectorSetLengthAtLeast(buf.m_ia0,n); - TagSortFastI(a,p1,buf.m_ra0,buf.m_ia0,n); -//--- General case, N>1: fill permutations table P2 -//--- To fill P2 we maintain two arrays: -//--- * PV (Buf.IA0), Position(Value). PV[i] contains position of I-th key at the moment -//--- * VP (Buf.IA1), Value(Position). VP[i] contains key which has position I at the moment -//--- At each step we making permutation of two items: -//--- Left,which is given by position/value pair LP/LV -//--- and Right,which is given by RP/RV -//--- and updating PV[] and VP[] correspondingly. - CApServ::IVectorSetLengthAtLeast(buf.m_ia0,n); -//--- function call - CApServ::IVectorSetLengthAtLeast(buf.m_ia1,n); -//--- function call - CApServ::IVectorSetLengthAtLeast(p2,n); - for(i=0;i<=n-1;i++) - { - buf.m_ia0[i]=i; - buf.m_ia1[i]=i; - } - for(i=0;i<=n-1;i++) - { - //--- calculate LP, LV, RP, RV - lp=i; - lv=buf.m_ia1[lp]; - rv=p1[i]; - rp=buf.m_ia0[rv]; - //--- Fill P2 - p2[i]=rp; - //--- update PV and VP - buf.m_ia1[lp]=rv; - buf.m_ia1[rp]=lv; - buf.m_ia0[lv]=rp; - buf.m_ia0[rv]=lp; - } - } -//+------------------------------------------------------------------+ -//| Same as TagSort, but optimized for real keys and integer labels. | -//| A is sorted, and same permutations are applied to B. | -//| NOTES: | -//| 1. this function assumes that A[] is finite; it doesn't checks | -//| that condition. All other conditions (size of input arrays, | -//| etc.) are not checked too. | -//| 2. this function uses two buffers, BufA and BufB, each is N | -//| elements large. They may be preallocated (which will save | -//| some time) or not, in which case function will automatically | -//| allocate memory. | -//+------------------------------------------------------------------+ -static void CTSort::TagSortFastI(double &a[],int &b[],double &bufa[], - int &bufb[],const int n) - { -//--- create variables - int i=0; - int j=0; - bool isascending; - bool isdescending; - double tmpr=0; - int tmpi=0; -//--- Special case - if(n<=1) - return; -//--- Test for already sorted set - isascending=true; - isdescending=true; - for(i=1;i<=n-1;i++) - { - isascending=isascending && a[i]>=a[i-1]; - isdescending=isdescending && a[i]<=a[i-1]; - } -//--- check - if(isascending) - return; -//--- check - if(isdescending) - { - for(i=0;i<=n-1;i++) - { - j=n-1-i; - //--- check - if(j<=i) - break; - //--- swap - tmpr=a[i]; - a[i]=a[j]; - a[j]=tmpr; - tmpi=b[i]; - b[i]=b[j]; - b[j]=tmpi; - } - //--- exit the function - return; - } -//--- General case - if(CAp::Len(bufa)=a[i-1]; - isdescending=isdescending && a[i]<=a[i-1]; - } -//--- check - if(isascending) - return; -//--- check - if(isdescending) - { - for(i=0;i<=n-1;i++) - { - j=n-1-i; - //--- check - if(j<=i) - break; - //--- swap - tmpr=a[i]; - a[i]=a[j]; - a[j]=tmpr; - tmpr=b[i]; - b[i]=b[j]; - b[j]=tmpr; - } - //--- exit the function - return; - } -//--- General case - if(CAp::Len(bufa)=a[i-1]; - isDesCending=isDesCending && a[i]<=a[i-1]; - } -//--- check - if(isAsCending) - return; -//--- check - if(isDesCending) - { - for(i=0;i0) - { - k=(j-1)/2; - v=a[k]; - //--- check - if(v=n) - { - //--- only one child. - //--- swap and terminate (because this child - //--- have no siblings due to heap structure) - v=a[k1]; - //--- check - if(v>va) - { - a[j]=v; - b[j]=b[k1]; - j=k1; - } - break; - } - else - { - //--- two childs - v1=a[k1]; - v2=a[k2]; - //--- check - if(v1>v2) - { - //--- check - if(va=1 | -//| On output top element is moved to A[N-1], B[N-1], heap is | -//| reordered, N is decreased by 1. | -//+------------------------------------------------------------------+ -static void CTSort::TagHeapPopI(double &a[],int &b[],int &n) - { -//--- create variables - double va=0; - int vb=0; -//--- check - if(n<1) - return; -//--- N=1 is a special case - if(n==1) - { - n=0; - return; - } -//--- swap top element and last element, -//--- then reorder heap - va=a[n-1]; - vb=b[n-1]; - a[n-1]=a[0]; - b[n-1]=b[0]; - n=n-1; -//--- function call - TagHeapReplaceTopI(a,b,n,va,vb); - } -//+------------------------------------------------------------------+ -//| Internal TagSortFastI: sorts A[I1...I2] (both bounds are | -//| included), applies same permutations to B. | -//+------------------------------------------------------------------+ -static void CTSort::TagSortFastIRec(double &a[],int &b[],double &bufa[], - int &bufb[],const int i1,const int i2) - { -//--- create variables - int i=0; - int j=0; - int k=0; - int cntless=0; - int cnteq=0; - int cntgreater=0; - double tmpr=0; - int tmpi=0; - double v0=0; - double v1=0; - double v2=0; - double vp=0; -//--- Fast exit - if(i2<=i1) - return; -//--- Non-recursive sort for small arrays - if(i2-i1<=16) - { - for(j=i1+1;j<=i2;j++) - { - //--- Search elements [I1..J-1] for place to insert Jth element. - //--- This code stops immediately if we can leave A[J] at J-th position - //--- (all elements have same value of A[J] larger than any of them) - tmpr=a[j]; - tmpi=j; - for(k=j-1;k>=i1;k--) - { - //--- check - if(a[k]<=tmpr) - break; - tmpi=k; - } - k=tmpi; - //--- Insert Jth element into Kth position - if(k!=j) - { - //--- change values - tmpr=a[j]; - tmpi=b[j]; - for(i=j-1;i>=k;i--) - { - a[i+1]=a[i]; - b[i+1]=b[i]; - } - a[k]=tmpr; - b[k]=tmpi; - } - } - //--- exit the function - return; - } -//--- Quicksort: choose pivot -//--- Here we assume that I2-I1>=2 - v0=a[i1]; - v1=a[i1+(i2-i1)/2]; - v2=a[i2]; -//--- check - if(v0>v1) - { - tmpr=v1; - v1=v0; - v0=tmpr; - } -//--- check - if(v1>v2) - { - tmpr=v2; - v2=v1; - v1=tmpr; - } -//--- check - if(v0>v1) - { - tmpr=v1; - v1=v0; - v0=tmpr; - } - vp=v1; -//--- now pass through A/B and: -//--- * move elements that are LESS than VP to the left of A/B -//--- * move elements that are EQUAL to VP to the right of BufA/BufB (in the reverse order) -//--- * move elements that are GREATER than VP to the left of BufA/BufB (in the normal order -//--- * move elements from the tail of BufA/BufB to the middle of A/B (restoring normal order) -//--- * move elements from the left of BufA/BufB to the end of A/B - cntless=0; - cnteq=0; - cntgreater=0; - for(i=i1;i<=i2;i++) - { - v0=a[i]; - //--- check - if(v0=i1;k--) - { - //--- check - if(a[k]<=tmpr) - break; - tmpi=k; - } - k=tmpi; - //--- Insert Jth element into Kth position - if(k!=j) - { - //--- change values - tmpr=a[j]; - tmpr2=b[j]; - for(i=j-1;i>=k;i--) - { - a[i+1]=a[i]; - b[i+1]=b[i]; - } - a[k]=tmpr; - b[k]=tmpr2; - } - } - //--- exit the function - return; - } -//--- Quicksort: choose pivot -//--- Here we assume that I2-I1>=16 - v0=a[i1]; - v1=a[i1+(i2-i1)/2]; - v2=a[i2]; -//--- check - if(v0>v1) - { - tmpr=v1; - v1=v0; - v0=tmpr; - } -//--- check - if(v1>v2) - { - tmpr=v2; - v2=v1; - v1=tmpr; - } -//--- check - if(v0>v1) - { - tmpr=v1; - v1=v0; - v0=tmpr; - } - vp=v1; -//--- now pass through A/B and: -//--- * move elements that are LESS than VP to the left of A/B -//--- * move elements that are EQUAL to VP to the right of BufA/BufB (in the reverse order) -//--- * move elements that are GREATER than VP to the left of BufA/BufB (in the normal order -//--- * move elements from the tail of BufA/BufB to the middle of A/B (restoring normal order) -//--- * move elements from the left of BufA/BufB to the end of A/B - cntless=0; - cnteq=0; - cntgreater=0; - for(i=i1;i<=i2;i++) - { - v0=a[i]; - //--- check - if(v0=i1;k--) - { - //--- check - if(a[k]<=tmpr) - break; - tmpi=k; - } - k=tmpi; - //--- Insert Jth element into Kth position - if(k!=j) - { - tmpr=a[j]; - for(i=j-1;i>=k;i--) - a[i+1]=a[i]; - a[k]=tmpr; - } - } - return; - } -//--- Quicksort: choose pivot -//--- Here we assume that I2-I1>=16 - v0=a[i1]; - v1=a[i1+(i2-i1)/2]; - v2=a[i2]; -//--- check - if(v0>v1) - { - tmpr=v1; - v1=v0; - v0=tmpr; - } -//--- check - if(v1>v2) - { - tmpr=v2; - v2=v1; - v1=tmpr; - } -//--- check - if(v0>v1) - { - tmpr=v1; - v1=v0; - v0=tmpr; - } - vp=v1; -//--- now pass through A/B and: -//--- * move elements that are LESS than VP to the left of A/B -//--- * move elements that are EQUAL to VP to the right of BufA/BufB (in the reverse order) -//--- * move elements that are GREATER than VP to the left of BufA/BufB (in the normal order -//--- * move elements from the tail of BufA/BufB to the middle of A/B (restoring normal order) -//--- * move elements from the left of BufA/BufB to the end of A/B - cntLess=0; - cntEq=0; - cntGreat=0; - for(i=i1;i<=i2;i++) - { - v0=a[i]; - //--- check - if(v0=buf.m_ra1[t-1]) - t=1; - else - { - //--- swap - tmp=buf.m_ra1[k-1]; - buf.m_ra1[k-1]=buf.m_ra1[t-1]; - buf.m_ra1[t-1]=tmp; - tmpi=buf.m_ia1[k-1]; - buf.m_ia1[k-1]=buf.m_ia1[t-1]; - buf.m_ia1[t-1]=tmpi; - //--- set value - t=k; - } - } - //--- next iteration - i=i+1; - } - while(i<=n); - //--- set value - i=n-1; - //--- cycle - do - { - //--- swap - tmp=buf.m_ra1[i]; - buf.m_ra1[i]=buf.m_ra1[0]; - buf.m_ra1[0]=tmp; - tmpi=buf.m_ia1[i]; - buf.m_ia1[i]=buf.m_ia1[0]; - buf.m_ia1[0]=tmpi; - //--- set value - t=1; - while(t!=0) - { - k=2*t; - if(k>i) - t=0; - else - { - //--- check - if(kbuf.m_ra1[k-1]) - k++; - //--- check - if(buf.m_ra1[t-1]>=buf.m_ra1[k-1]) - t=0; - else - { - //--- swap - tmp=buf.m_ra1[k-1]; - buf.m_ra1[k-1]=buf.m_ra1[t-1]; - buf.m_ra1[t-1]=tmp; - tmpi=buf.m_ia1[k-1]; - buf.m_ia1[k-1]=buf.m_ia1[t-1]; - buf.m_ia1[t-1]=tmpi; - //--- set value - t=k; - } - } - } - i=i-1; - } - while(i>=1); - } -//--- compute tied ranks - i=0; - while(iMathAbs(x[result])) - result=i; - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static int CBlas::ColumnIdxAbsMax(CMatrixDouble &x,const int i1,const int i2,const int j) - { -//--- create variables - int result=i1; - int i=0; - double a=0; -//--- calculation - a=MathAbs(x[result][j]); - for(i=i1+1;i<=i2;i++) - { - //--- check - if(MathAbs(x[i][j])>MathAbs(x[result][j])) - result=i; - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static int CBlas::RowIdxAbsMax(CMatrixDouble &x,const int j1,const int j2,const int i) - { -//--- create variables - int result=j1; - int j=0; - double a=0; -//--- calculation - a=MathAbs(x[i][result]); - for(j=j1+1;j<=j2;j++) - { - //--- check - if(MathAbs(x[i][j])>MathAbs(x[i][result])) - result=j; - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Upper Hessenberg norm | -//+------------------------------------------------------------------+ -static double CBlas::UpperHessenberg1Norm(CMatrixDouble &a,const int i1, - const int i2,const int j1, - const int j2,double &work[]) - { -//--- create variables - double result=0; - int i=0; - int j=0; -//--- check - if(!CAp::Assert(i2-i1==j2-j1,__FUNCTION__+": I2-I1!=J2-J1!")) - return(EMPTY_VALUE); - for(j=j1;j<=j2;j++) - work[j]=0; - for(i=i1;i<=i2;i++) - { - for(j=MathMax(j1,j1+i-i1-1);j<=j2;j++) - work[j]=work[j]+MathAbs(a[i][j]); - } -//--- get result - result=0; - for(j=j1;j<=j2;j++) - result=MathMax(result,work[j]); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Copy matrix | -//+------------------------------------------------------------------+ -static void CBlas::CopyMatrix(CMatrixDouble &a,const int is1,const int is2, - const int js1,const int js2,CMatrixDouble &b, - const int id1,const int id2,const int jd1,const int jd2) - { -//--- create variables - int isrc=0; - int idst=0; - int i_=0; - int i1_=0; -//--- check - if(is1>is2 || js1>js2) - return; -//--- check - if(!CAp::Assert(is2-is1==id2-id1,__FUNCTION__+": different sizes!")) - return; -//--- check - if(!CAp::Assert(js2-js1==jd2-jd1,__FUNCTION__+": different sizes!")) - return; -//--- copy - for(isrc=is1;isrc<=is2;isrc++) - { - idst=isrc-is1+id1; - i1_=js1-jd1; - for(i_=jd1;i_<=jd2;i_++) - b[idst].Set(i_,a[isrc][i_+i1_]); - } - } -//+------------------------------------------------------------------+ -//| Matrix transpose | -//+------------------------------------------------------------------+ -static void CBlas::InplaceTranspose(CMatrixDouble &a,const int i1,const int i2, - const int j1,const int j2,double &work[]) - { -//--- create variables - int i=0; - int j=0; - int ips=0; - int jps=0; - int l=0; - int i_=0; - int i1_=0; -//--- check - if(i1>i2 || j1>j2) - return; -//--- check - if(!CAp::Assert(i1-i2==j1-j2,__FUNCTION__+": incorrect array size!")) - return; - for(i=i1;i<=i2-1;i++) - { - //--- change values - j=j1+i-i1; - ips=i+1; - jps=j1+ips-i1; - l=i2-i; - i1_=ips-1; - //--- transpose - for(i_=1;i_<=l;i_++) - work[i_]=a[i_+i1_][j]; - i1_=jps-ips; - for(i_=ips;i_<=i2;i_++) - a[i_].Set(j,a[i][i_+i1_]); - i1_=1-jps; - for(i_=jps;i_<=j2;i_++) - a[i].Set(i_,work[i_+i1_]); - } - } -//+------------------------------------------------------------------+ -//| Copy and transpose matrix | -//+------------------------------------------------------------------+ -static void CBlas::CopyAndTranspose(CMatrixDouble &a,const int is1,const int is2, - const int js1,const int js2,CMatrixDouble &b, - const int id1,const int id2,const int jd1,const int jd2) - { -//--- create variables - int isrc=0; - int jdst=0; - int i_=0; - int i1_=0; -//--- check - if(is1>is2 || js1>js2) - return; -//--- check - if(!CAp::Assert(is2-is1==jd2-jd1,__FUNCTION__+": different sizes!")) - return; -//--- check - if(!CAp::Assert(js2-js1==id2-id1,__FUNCTION__+": different sizes!")) - return; -//--- copy and transpose - for(isrc=is1;isrc<=is2;isrc++) - { - jdst=isrc-is1+jd1; - i1_=js1-id1; - for(i_=id1;i_<=id2;i_++) - b[i_].Set(jdst,a[isrc][i_+i1_]); - } - } -//+------------------------------------------------------------------+ -//| Matrix vector multiply | -//+------------------------------------------------------------------+ -static void CBlas::MatrixVectorMultiply(CMatrixDouble &a,const int i1,const int i2, - const int j1,const int j2,const bool trans, - double &x[],const int ix1,const int ix2, - const double alpha,double &y[],const int iy1, - const int iy2,const double beta) - { -//--- create variables - int i=0; - double v=0; - int i_=0; - int i1_=0; -//--- check - if(!trans) - { - //--- y := alpha*A*x + beta*y; - if(i1>i2 || j1>j2) - return; - //--- check - if(!CAp::Assert(j2-j1==ix2-ix1,__FUNCTION__+": A and X dont match!")) - return; - //--- check - if(!CAp::Assert(i2-i1==iy2-iy1,__FUNCTION__+": A and Y dont match!")) - return; - //--- beta*y - if(beta==0.0) - { - for(i=iy1;i<=iy2;i++) - y[i]=0; - } - else - { - for(i_=iy1;i_<=iy2;i_++) - y[i_]=beta*y[i_]; - } - //--- alpha*A*x - for(i=i1;i<=i2;i++) - { - i1_=ix1-j1; - v=0.0; - for(i_=j1;i_<=j2;i_++) - v+=a[i][i_]*x[i_+i1_]; - y[iy1+i-i1]=y[iy1+i-i1]+alpha*v; - } - } - else - { - //--- y := alpha*A'*x + beta*y; - if(i1>i2 || j1>j2) - return; - //--- check - if(!CAp::Assert(i2-i1==ix2-ix1,"MatrixVectorMultiply: A and X dont match!")) - return; - //--- check - if(!CAp::Assert(j2-j1==iy2-iy1,"MatrixVectorMultiply: A and Y dont match!")) - return; - //--- beta*y - if(beta==0.0) - { - for(i=iy1;i<=iy2;i++) - y[i]=0; - } - else - { - for(i_=iy1;i_<=iy2;i_++) - y[i_]=beta*y[i_]; - } - //--- alpha*A'*x - for(i=i1;i<=i2;i++) - { - v=alpha*x[ix1+i-i1]; - i1_=j1-iy1; - for(i_=iy1;i_<=iy2;i_++) - y[i_]=y[i_]+v*a[i][i_+i1_]; - } - } - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static double CBlas::PyThag2(double x,double y) - { -//--- create variables - double result=0; - double w=0; - double xabs=0; - double yabs=0; - double z=0; -//--- initialization - xabs=MathAbs(x); - yabs=MathAbs(y); - w=MathMax(xabs,yabs); - z=MathMin(xabs,yabs); -//--- check - if(z==0.0) - result=w; - else - result=w*MathSqrt(1+CMath::Sqr(z/w)); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Matrix matrix multiply | -//+------------------------------------------------------------------+ -static void CBlas::MatrixMatrixMultiply(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,double &work[]) - { -//--- 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; - int i_=0; - int i1_=0; -//--- 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,__FUNCTION__+": incorrect matrix sizes!")) - return; -//--- check - if(arows<=0 || acols<=0 || brows<=0 || bcols<=0) - return; - 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; - for(i_=cj1;i_<=cj2;i_++) - c[k].Set(i_,c[k][i_]+v*b[r][i_+i1_]); - } - } - //--- exit the function - return; - } -//--- A*B' - if(!transa && transb) - { - //--- check - if(arows*acols=CMath::m_maxrealnumber*CMath::m_machineepsilon) - { - //--- change parameters - s=CMath::m_maxrealnumber*CMath::m_machineepsilon; - v=1/s; - //--- change x - for(i_=1;i_<=n;i_++) - x[i_]=v*x[i_]; - mx=mx*v; - } - } - } -//--- XNORM = DNRM2( N-1, X, INCX ) - alpha=x[1]; - xnorm=0; -//--- check - if(mx!=0.0) - { - for(j=2;j<=n;j++) - xnorm=xnorm+CMath::Sqr(x[j]/mx); - xnorm=MathSqrt(xnorm)*mx; - } -//--- check - if(xnorm==0.0) - { - //--- H = I - tau=0; - x[1]=x[1]*s; - //--- exit the function - return; - } -//--- general case - mx=MathMax(MathAbs(alpha),MathAbs(xnorm)); - beta=-(mx*MathSqrt(CMath::Sqr(alpha/mx)+CMath::Sqr(xnorm/mx))); -//--- check - if(alpha<0.0) - beta=-beta; -//--- change parameters - tau=(beta-alpha)/beta; - v=1/(alpha-beta); -//--- change x - for(i_=2;i_<=n;i_++) - x[i_]=v*x[i_]; - x[1]=beta; -//--- Scale back outputs - x[1]=x[1]*s; - } -//+------------------------------------------------------------------+ -//| Application of an elementary reflection to a rectangular matrix | -//| of size MxN | -//| The algorithm pre-multiplies the matrix by an elementary | -//| reflection transformation which is given by column V and scalar | -//| Tau (see the description of the GenerateReflection procedure). | -//| Not the whole matrix but only a part of it is transformed (rows | -//| from M1 to M2, columns from N1 to N2). Only the elements of this | -//| submatrix are changed. | -//| Input parameters: | -//| C - matrix to be transformed. | -//| Tau - scalar defining the transformation. | -//| V - column defining the transformation. | -//| Array whose index ranges within [1..M2-M1+1]. | -//| M1, M2 - range of rows to be transformed. | -//| N1, N2 - range of columns to be transformed. | -//| WORK - working array whose indexes goes from N1 to N2. | -//| Output parameters: | -//| C - the result of multiplying the input matrix C by | -//| the transformation matrix which is given by Tau | -//| and V. If N1>N2 or M1>M2, C is not modified. | -//| -- LAPACK auxiliary routine (version 3.0) -- | -//| Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., | -//| Courant Institute, Argonne National Lab, and Rice University| -//| September 30, 1994 | -//+------------------------------------------------------------------+ -static void CReflections::ApplyReflectionFromTheLeft(CMatrixDouble &c,const double tau, - const double &v[],const int m1, - const int m2,const int n1, - const int n2,double &work[]) - { -//--- check - if(tau==0.0 || n1>n2 || m1>m2) - return; -//--- create variables - double t=0; - int i=0; - int vm=0; - int i_=0; -//--- w := C' * v - vm=m2-m1+1; - for(i=n1;i<=n2;i++) - work[i]=0; - for(i=m1;i<=m2;i++) - { - t=v[i+1-m1]; - //--- change array - for(i_=n1;i_<=n2;i_++) - work[i_]+=t*c[i][i_]; - } -//--- C := C - tau * v * w' - for(i=m1;i<=m2;i++) - { - t=v[i-m1+1]*tau; - for(i_=n1;i_<=n2;i_++) - c[i].Set(i_,c[i][i_]-t*work[i_]); - } - } -//+------------------------------------------------------------------+ -//| Application of an elementary reflection to a rectangular matrix | -//| of size MxN | -//| The algorithm post-multiplies the matrix by an elementary | -//| reflection transformation which is given by column V and scalar | -//| Tau (see the description of the GenerateReflection procedure). | -//| Not the whole matrix but only a part of it is transformed (rows | -//| from M1 to M2, columns from N1 to N2). Only the elements of this | -//| submatrix are changed. | -//| Input parameters: | -//| C - matrix to be transformed. | -//| Tau - scalar defining the transformation. | -//| V - column defining the transformation. | -//| Array whose index ranges within [1..N2-N1+1]. | -//| M1, M2 - range of rows to be transformed. | -//| N1, N2 - range of columns to be transformed. | -//| WORK - working array whose indexes goes from M1 to M2. | -//| Output parameters: | -//| C - the result of multiplying the input matrix C by | -//| the transformation matrix which is given by Tau | -//| and V. If N1>N2 or M1>M2, C is not modified. | -//| -- LAPACK auxiliary routine (version 3.0) -- | -//| Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., | -//| Courant Institute, Argonne National Lab, and Rice University| -//| September 30, 1994 | -//+------------------------------------------------------------------+ -static void CReflections::ApplyReflectionFromTheRight(CMatrixDouble &c,const double tau, - const double &v[],const int m1, - const int m2,const int n1, - const int n2,double &work[]) - { -//--- check - if(tau==0.0 || n1>n2 || m1>m2) - return; -//--- create variables - double t=0; - int i=0; - int vm=n2-n1+1; - int i_=0; - int i1_=0; -//--- change matrix - for(i=m1;i<=m2;i++) - { - i1_=1-n1; - t=0.0; - //--- calculation parameters - for(i_=n1;i_<=n2;i_++) - t+=c[i][i_]*v[i_+i1_]; - t=t*tau; - i1_=1-n1; - for(i_=n1;i_<=n2;i_++) - c[i].Set(i_,c[i][i_]-t*v[i_+i1_]); - } - } -//+------------------------------------------------------------------+ -//| Complex reflections | -//+------------------------------------------------------------------+ -class CComplexReflections - { -public: - //--- constructor, destructor - void CComplexReflections(void); - void ~CComplexReflections(void); - //--- methods - static void ComplexGenerateReflection(al_complex &x[],const int n,al_complex &tau); - static void ComplexApplyReflectionFromTheLeft(CMatrixComplex &c,al_complex &tau,al_complex &v[],const int m1,const int m2,const int n1,const int n2,al_complex &work[]); - static void ComplexApplyReflectionFromTheRight(CMatrixComplex &c,al_complex &tau,al_complex &v[],const int m1,const int m2,const int n1,const int n2,al_complex &work[]); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CComplexReflections::CComplexReflections(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CComplexReflections::~CComplexReflections(void) - { - - } -//+------------------------------------------------------------------+ -//| Generation of an elementary complex reflection transformation | -//| The subroutine generates elementary complex reflection H of | -//| order N, so that, for a given X, the following equality holds | -//| true: | -//| ( X(1) ) ( Beta ) | -//| H' * ( .. ) = ( 0 ), H'*H = I, Beta is a real number | -//| ( X(n) ) ( 0 ) | -//| where | -//| ( V(1) ) | -//| H = 1 - Tau * ( .. ) * ( conj(V(1)), ..., conj(V(n)) ) | -//| ( V(n) ) | -//| where the first component of vector V equals 1. | -//| Input parameters: | -//| X - vector. Array with elements [1..N]. | -//| N - reflection order. | -//| Output parameters: | -//| X - components from 2 to N are replaced by vector V. | -//| The first component is replaced with parameter Beta. | -//| Tau - scalar value Tau. | -//| This subroutine is the modification of CLARFG subroutines from | -//| the LAPACK library. It has similar functionality except for the | -//| fact that it doesn?t handle errors when intermediate results | -//| cause an overflow. | -//| -- LAPACK auxiliary routine (version 3.0) -- | -//| Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., | -//| Courant Institute, Argonne National Lab, and Rice University| -//| September 30, 1994 | -//+------------------------------------------------------------------+ -static void CComplexReflections::ComplexGenerateReflection(al_complex &x[], - const int n, - al_complex &tau) - { -//--- check - if(n<=0) - { - tau=0; - //--- exit the function - return; - } -//--- create variables - int j=0; - al_complex alpha=0; - double alphi=0; - double alphr=0; - double beta=0; - double xnorm=0; - double mx=0; - al_complex t=0; - double s=1; - al_complex v=0; - int i_=0; - al_complex One(1,0); -//--- Scale if needed (to avoid overflow/underflow during intermediate -//--- calculations). - for(j=1;j<=n;j++) - mx=MathMax(CMath::AbsComplex(x[j]),mx); -//--- check - if(mx!=0) - { - //--- check - if(mx<1) - { - s=MathSqrt(CMath::m_minrealnumber); - v=1/s; - //--- change x - for(i_=1;i_<=n;i_++) - x[i_]=v*x[i_]; - } - else - { - s=MathSqrt(CMath::m_maxrealnumber); - v=1/s; - //--- change x - for(i_=1;i_<=n;i_++) - x[i_]=v*x[i_]; - } - } -//--- calculate - alpha=x[1]; - mx=0; - for(j=2;j<=n;j++) - mx=MathMax(CMath::AbsComplex(x[j]),mx); - xnorm=0; -//--- check - if(mx!=0) - { - for(j=2;j<=n;j++) - { - t=x[j]/mx; - xnorm=xnorm+(t*CMath::Conj(t)).re; - } - xnorm=MathSqrt(xnorm)*mx; - } -//--- change parameters - alphr=alpha.re; - alphi=alpha.im; -//--- check - if((xnorm==0) && (alphi==0)) - { - tau=0; - x[1]=x[1]*s; - //--- exit the function - return; - } -//--- change parameters - mx=MathMax(MathAbs(alphr),MathAbs(alphi)); - mx=MathMax(mx,MathAbs(xnorm)); - beta=-(mx*MathSqrt(CMath::Sqr(alphr/mx)+CMath::Sqr(alphi/mx)+CMath::Sqr(xnorm/mx))); -//--- check - if(alphr<0) - beta=-beta; -//--- change parameters - tau.re=(beta-alphr)/beta; - tau.im=-(alphi/beta); - alpha=One/(alpha-beta); -//--- check - if(n>1) - { - //--- change x - for(i_=2;i_<=n;i_++) - x[i_]=alpha*x[i_]; - } - alpha=beta; - x[1]=alpha; -//--- Scale back - x[1]=x[1]*s; - } -//+------------------------------------------------------------------+ -//| Application of an elementary reflection to a rectangular matrix | -//| of size MxN | -//| The algorithm pre-multiplies the matrix by an elementary | -//| reflection transformation which is given by column V and | -//| scalar Tau (see the description of the GenerateReflection). Not | -//| the whole matrix but only a part of it is transformed (rows | -//| from M1 to M2, columns from N1 to N2). Only the elements of this | -//| submatrix are changed. | -//| Note: the matrix is multiplied by H, not by H'. If it is | -//| required to multiply the matrix by H', it is necessary to pass | -//| Conj(Tau) instead of Tau. | -//| Input parameters: | -//| C - matrix to be transformed. | -//| Tau - scalar defining transformation. | -//| V - column defining transformation. | -//| Array whose index ranges within [1..M2-M1+1] | -//| M1, M2 - range of rows to be transformed. | -//| N1, N2 - range of columns to be transformed. | -//| WORK - working array whose index goes from N1 to N2. | -//| Output parameters: | -//| C - the result of multiplying the input matrix C by | -//| the transformation matrix which is given by Tau | -//| and V. If N1>N2 or M1>M2, C is not modified. | -//| -- LAPACK auxiliary routine (version 3.0) -- | -//| Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., | -//| Courant Institute, Argonne National Lab, and Rice University| -//| September 30, 1994 | -//+------------------------------------------------------------------+ -static void CComplexReflections::ComplexApplyReflectionFromTheLeft(CMatrixComplex &c, - al_complex &tau, - al_complex &v[], - const int m1, - const int m2, - const int n1, - const int n2, - al_complex &work[]) - { - al_complex Zero(0,0); -//--- check - if(tau==Zero || n1>n2 || m1>m2) - return; -//--- create variables - al_complex t=0; - int i=0; - int vm=0; - int i_=0; -//--- w := C^T * conj(v) - vm=m2-m1+1; - for(i=n1;i<=n2;i++) - work[i]=0; - for(i=m1;i<=m2;i++) - { - t=CMath::Conj(v[i+1-m1]); - for(i_=n1;i_<=n2;i_++) - work[i_]=work[i_]+t*c[i][i_]; - } -//--- C := C - tau * v * w^T - for(i=m1;i<=m2;i++) - { - t=v[i-m1+1]*tau; - for(i_=n1;i_<=n2;i_++) - c[i].Set(i_,c[i][i_]-t*work[i_]); - } - } -//+------------------------------------------------------------------+ -//| Application of an elementary reflection to a rectangular matrix | -//| of size MxN | -//| The algorithm post-multiplies the matrix by an elementary | -//| reflection transformation which is given by column V and | -//| scalar Tau (see the description of the GenerateReflection). | -//| Not the whole matrix but only a part of it is transformed | -//| (rows from M1 to M2, columns from N1 to N2). Only the elements | -//| of this submatrix are changed. | -//| Input parameters: | -//| C - matrix to be transformed. | -//| Tau - scalar defining transformation. | -//| V - column defining transformation. | -//| Array whose index ranges within [1..N2-N1+1] | -//| M1, M2 - range of rows to be transformed. | -//| N1, N2 - range of columns to be transformed. | -//| WORK - working array whose index goes from M1 to M2. | -//| Output parameters: | -//| C - the result of multiplying the input matrix C by | -//| the transformation matrix which is given by Tau | -//| and V. If N1>N2 or M1>M2, C is not modified. | -//| -- LAPACK auxiliary routine (version 3.0) -- | -//| Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., | -//| Courant Institute, Argonne National Lab, and Rice University| -//| September 30, 1994 | -//+------------------------------------------------------------------+ -static void CComplexReflections::ComplexApplyReflectionFromTheRight(CMatrixComplex &c, - al_complex &tau, - al_complex &v[], - const int m1, - const int m2, - const int n1, - const int n2, - al_complex &work[]) - { - al_complex Zero(0,0); -//--- check - if(tau==Zero || n1>n2 || m1>m2) - return; -//--- create variables - al_complex t=0; - int i=0; - int vm=0; - int i_=0; - int i1_=0; -//--- w := C * v - vm=n2-n1+1; - for(i=m1;i<=m2;i++) - { - i1_=1-n1; - t=0.0; - //--- change values - for(i_=n1;i_<=n2;i_++) - t+=c[i][i_]*v[i_+i1_]; - work[i]=t; - } -//--- C := C - w * conj(v^T) - for(i_=1;i_<=vm;i_++) - v[i_]=CMath::Conj(v[i_]); -//--- get result - for(i=m1;i<=m2;i++) - { - t=work[i]*tau; - i1_=1-n1; - for(i_=n1;i_<=n2;i_++) - c[i].Set(i_,c[i][i_]-t*v[i_+i1_]); - } - for(i_=1;i_<=vm;i_++) - v[i_]=CMath::Conj(v[i_]); - } -//+------------------------------------------------------------------+ -//| Work with the symmetric matrix | -//+------------------------------------------------------------------+ -class CSblas - { -public: - //--- constructor, destructor - CSblas(void); - ~CSblas(void); - //--- methods - static void SymmetricMatrixVectorMultiply(const CMatrixDouble &a,const bool isupper,const int i1,const int i2,const double &x[],const double alpha,double &y[]); - static void SymmetricRank2Update(CMatrixDouble &a,const bool isupper,const int i1,const int i2,const double &x[],const double &y[],double &t[],const double alpha); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CSblas::CSblas(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSblas::~CSblas(void) - { - - } -//+------------------------------------------------------------------+ -//| Multiply | -//+------------------------------------------------------------------+ -static void CSblas::SymmetricMatrixVectorMultiply(const CMatrixDouble &a, - const bool isupper, - const int i1,const int i2, - const double &x[], - const double alpha, - double &y[]) - { -//--- create variables - int i=0; - int ba1=0; - int ba2=0; - int by1=0; - int by2=0; - int bx1=0; - int bx2=0; - int n=i2-i1+1; - double v=0; - int i_=0; - int i1_=0; -//--- check - if(n<=0) - return; -//--- Let A = L + D + U, where -//--- L is strictly lower triangular (main diagonal is zero) -//--- D is diagonal -//--- U is strictly upper triangular (main diagonal is zero) -//--- A*x = L*x + D*x + U*x -//--- Calculate D*x first - for(i=i1;i<=i2;i++) - y[i-i1+1]=a[i][i]*x[i-i1+1]; -//--- Add L*x + U*x - if(isupper) - { - for(i=i1;im2 || n1>n2) - return; -//--- Form P * A - if(isforward) - { - //--- check - if(n1!=n2) - { - //--- Common case: N1<>N2 - for(j=m1;jN2 - for(j=m2-1;j>=m1;j--) - { - ctemp=c[j-m1+1]; - stemp=s[j-m1+1]; - //--- check - if(ctemp!=1.0 || stemp!=0.0) - { - jp1=j+1; - //--- prepare array - for(i_=n1;i_<=n2;i_++) - work[i_]=ctemp*a[jp1][i_]; - for(i_=n1;i_<=n2;i_++) - work[i_]=work[i_]-stemp*a[j][i_]; - for(i_=n1;i_<=n2;i_++) - a[j].Set(i_,ctemp*a[j][i_]); - //--- get result - for(i_=n1;i_<=n2;i_++) - a[j].Set(i_,a[j][i_]+stemp*a[jp1][i_]); - for(i_=n1;i_<=n2;i_++) - a[jp1].Set(i_,work[i_]); - } - } - } - else - { - //--- Special case: N1=N2 - for(j=m2-1;j>=m1;j--) - { - ctemp=c[j-m1+1]; - stemp=s[j-m1+1]; - //--- check - if(ctemp!=1.0 || stemp!=0.0) - { - temp=a[j+1][n1]; - //--- get result - a[j+1].Set(n1,ctemp*temp-stemp*a[j][n1]); - a[j].Set(n1,stemp*temp+ctemp*a[j][n1]); - } - } - } - } - } -//+------------------------------------------------------------------+ -//| Application of a sequence of elementary rotations to a matrix | -//| The algorithm post-multiplies the matrix by a sequence of | -//| rotation transformations which is given by arrays C and S. | -//| Depending on the value of the IsForward parameter either 1 and 2,| -//| 3 and 4 and so on (if IsForward=true) rows are rotated, or the | -//| rows N and N-1, N-2 and N-3 and so on are rotated. | -//| Not the whole matrix but only a part of it is transformed (rows | -//| from M1 to M2, columns from N1 to N2). Only the elements of this | -//| submatrix are changed. | -//| Input parameters: | -//| IsForward - the sequence of the rotation application. | -//| M1,M2 - the range of rows to be transformed. | -//| N1, N2 - the range of columns to be transformed. | -//| C,S - transformation coefficients. | -//| Array whose index ranges within [1..N2-N1]. | -//| A - processed matrix. | -//| WORK - working array whose index ranges within | -//| [M1..M2]. | -//| Output parameters: | -//| A - transformed matrix. | -//| Utility subroutine. | -//+------------------------------------------------------------------+ -static void CRotations::ApplyRotationsFromTheRight(const bool isforward, - const int m1,const int m2, - const int n1,const int n2, - double &c[],double &s[], - CMatrixDouble &a, - double &work[]) - { -//--- create variables - int j=0; - int jp1=0; - double ctemp=0; - double stemp=0; - double temp=0; - int i_=0; -//--- Form A * P' - if(isforward) - { - //--- check - if(m1!=m2) - { - //--- Common case: M1<>M2 - for(j=n1;j<=n2-1;j++) - { - ctemp=c[j-n1+1]; - stemp=s[j-n1+1]; - //--- check - if(ctemp!=1.0 || stemp!=0.0) - { - jp1=j+1; - //--- prepare array - for(i_=m1;i_<=m2;i_++) - work[i_]=ctemp*a[i_][jp1]; - for(i_=m1;i_<=m2;i_++) - work[i_]=work[i_]-stemp*a[i_][j]; - //--- get result - for(i_=m1;i_<=m2;i_++) - a[i_].Set(j,ctemp*a[i_][j]); - for(i_=m1;i_<=m2;i_++) - a[i_].Set(j,a[i_][j]+stemp*a[i_][jp1]); - for(i_=m1;i_<=m2;i_++) - a[i_].Set(jp1,work[i_]); - } - } - } - else - { - //--- Special case: M1=M2 - for(j=n1;j<=n2-1;j++) - { - ctemp=c[j-n1+1]; - stemp=s[j-n1+1]; - //--- check - if(ctemp!=1.0 || stemp!=0.0) - { - temp=a[m1][j+1]; - //--- get result - a[m1].Set(j+1,ctemp*temp-stemp*a[m1][j]); - a[m1].Set(j,stemp*temp+ctemp*a[m1][j]); - } - } - } - } - else - { - //--- check - if(m1!=m2) - { - //--- Common case: M1<>M2 - for(j=n2-1;j>=n1;j--) - { - ctemp=c[j-n1+1]; - stemp=s[j-n1+1]; - //--- check - if(ctemp!=1.0 || stemp!=0.0) - { - jp1=j+1; - //--- prepare array - for(i_=m1;i_<=m2;i_++) - work[i_]=ctemp*a[i_][jp1]; - for(i_=m1;i_<=m2;i_++) - work[i_]=work[i_]-stemp*a[i_][j]; - //--- get result - for(i_=m1;i_<=m2;i_++) - a[i_].Set(j,ctemp*a[i_][j]); - for(i_=m1;i_<=m2;i_++) - a[i_].Set(j,a[i_][j]+stemp*a[i_][jp1]); - for(i_=m1;i_<=m2;i_++) - a[i_].Set(jp1,work[i_]); - } - } - } - else - { - //--- Special case: M1=M2 - for(j=n2-1;j>=n1;j--) - { - ctemp=c[j-n1+1]; - stemp=s[j-n1+1]; - //--- check - if(ctemp!=1.0 || stemp!=0.0) - { - temp=a[m1][j+1]; - //--- get result - a[m1].Set(j+1,ctemp*temp-stemp*a[m1][j]); - a[m1].Set(j,stemp*temp+ctemp*a[m1][j]); - } - } - } - } - } -//+------------------------------------------------------------------+ -//| The subroutine generates the elementary rotation, so that: | -//| [ CS SN ] . [ F ] = [ R ] | -//| [ -SN CS ] [ G ] [ 0 ] | -//| CS**2 + SN**2 = 1 | -//+------------------------------------------------------------------+ -static void CRotations::GenerateRotation(const double f,const double g, - double &cs,double &sn,double &r) - { -//--- create variables - double f1=0; - double g1=0; -//--- check - if(g==0.0) - { - //--- get result - cs=1; - sn=0; - r=f; - } - else - { - //--- check - if(f==0.0) - { - //--- get result - cs=0; - sn=1; - r=g; - } - else - { - f1=f; - g1=g; - //--- check - if(MathAbs(f1)>MathAbs(g1)) - r=MathAbs(f1)*MathSqrt(1+CMath::Sqr(g1/f1)); - else - r=MathAbs(g1)*MathSqrt(1+CMath::Sqr(f1/g1)); - cs=f1/r; - sn=g1/r; - //--- check - if(MathAbs(f)>MathAbs(g) && cs<0.0) - { - //--- get result - cs=-cs; - sn=-sn; - r=-r; - } - } - } - } -//+------------------------------------------------------------------+ -//| Schur decomposition of Hessenberg matrix | -//+------------------------------------------------------------------+ -class CHsSchur - { -private: - //--- private methods - static void InternalAuxSchur(const bool wantt,const bool wantz,const int n,const int ilo,const int ihi,CMatrixDouble &h,double &wr[],double &wi[],const int iloz,const int ihiz,CMatrixDouble &z,double &work[],double &workv3[],double &workc1[],double &works1[],int &info); - static void Aux2x2Schur(double &a,double &b,double &c,double &d,double &rt1r,double &rt1i,double &rt2r,double &rt2i,double &cs,double &sn); - static double ExtSchurSign(const double a,const double b); - static int ExtSchurSignToone(const double b); -public: - //--- constructor, destructor - CHsSchur(void); - ~CHsSchur(void); - //--- public methods - static bool UpperHessenbergSchurDecomposition(CMatrixDouble &h,const int n,CMatrixDouble &s); - static void InternalSchurDecomposition(CMatrixDouble &h,const int n,const int tneeded,const int zneeded,double &wr[],double &wi[],CMatrixDouble &z,int &info); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CHsSchur::CHsSchur(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CHsSchur::~CHsSchur(void) - { - - } -//+------------------------------------------------------------------+ -//| Subroutine performing the Schur decomposition of a matrix in | -//| upper Hessenberg form using the QR algorithm with multiple | -//| shifts. | -//| The source matrix H is represented as S'*H*S = T, where H - | -//| matrix in upper Hessenberg form, S - orthogonal matrix (Schur | -//| vectors), T - upper quasi-triangular matrix (with blocks of sizes| -//| 1x1 and 2x2 on the main diagonal). | -//| Input parameters: | -//| H - matrix to be decomposed. | -//| Array whose indexes range within [1..N, 1..N]. | -//| N - size of H, N>=0. | -//| Output parameters: | -//| H ? contains the matrix T. | -//| Array whose indexes range within [1..N, 1..N]. | -//| All elements below the blocks on the main diagonal | -//| are equal to 0. | -//| S - contains Schur vectors. | -//| Array whose indexes range within [1..N, 1..N]. | -//| Note 1: | -//| The block structure of matrix T could be easily recognized: | -//| since all the elements below the blocks are zeros, the | -//| elements a[i+1,i] which are equal to 0 show the block border.| -//| Note 2: | -//| the algorithm performance depends on the value of the | -//| internal parameter NS of InternalSchurDecomposition | -//| subroutine which defines the number of shifts in the QR | -//| algorithm (analog of the block width in block matrix | -//| algorithms in linear algebra). If you require maximum | -//| performance on your machine, it is recommended to | -//| adjust thisparameter manually. | -//| Result: | -//| True, if the algorithm has converged and the parameters H and| -//| S contain the result. | -//| False, if the algorithm has not converged. | -//| Algorithm implemented on the basis of subroutine DHSEQR | -//| (LAPACK 3.0 library). | -//+------------------------------------------------------------------+ -static bool CHsSchur::UpperHessenbergSchurDecomposition(CMatrixDouble &h, - const int n, - CMatrixDouble &s) - { -//--- create variables - bool result; - int info=0; -//--- create arrays - double wi[]; - double wr[]; -//--- function call - InternalSchurDecomposition(h,n,1,2,wr,wi,s,info); - result=info==0; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static void CHsSchur::InternalSchurDecomposition(CMatrixDouble &h,const int n, - const int tneeded, - const int zneeded, - double &wr[],double &wi[], - CMatrixDouble &z,int &info) - { -//--- create variables - int i=0; - int i1=0; - int i2=0; - int ierr=0; - int ii=0; - int itemp=0; - int itn=0; - int its=0; - int j=0; - int k=0; - int l=0; - int maxb=0; - int nr=0; - int ns=0; - int nv=0; - double absw=0; - double ovfl=0; - double smlnum=0; - double tau=0; - double temp=0; - double tst1=0; - double ulp=0; - double unfl=0; - bool initz; - bool wantt; - bool wantz; - double cnst=0; - bool failflag; - int p1=0; - int p2=0; - double vt=0; - int i_=0; - int i1_=0; -//--- create arrays - double v[]; - double vv[]; - double work[]; - double workc1[]; - double works1[]; - double workv3[]; - double tmpwr[]; - double tmpwi[]; - CMatrixDouble s; -//--- initialization - info=0; -//--- Set the order of the multi-shift QR algorithm to be used. -//--- If you want to tune algorithm, change this values - ns=12; - maxb=50; -//--- Now 2 < NS <= MAXB < NH. - maxb=(int)MathMax(3,maxb); - ns=MathMin(maxb,ns); -//--- Initialize - cnst=1.5; -//--- allocation - ArrayResizeAL(work,(int)MathMax(n,1)+1); - s.Resize(ns+1,ns+1); - ArrayResizeAL(v,ns+2); - ArrayResizeAL(vv,ns+2); - ArrayResizeAL(wr,(int)MathMax(n,1)+1); - ArrayResizeAL(wi,(int)MathMax(n,1)+1); - ArrayResizeAL(workc1,2); - ArrayResizeAL(works1,2); - ArrayResizeAL(workv3,4); - ArrayResizeAL(tmpwr,(int)MathMax(n,1)+1); - ArrayResizeAL(tmpwi,(int)MathMax(n,1)+1); -//--- check - if(!CAp::Assert(n>=0,"InternalSchurDecomposition: incorrect N!")) - return; -//--- check - if(!CAp::Assert(tneeded==0 || tneeded==1,"InternalSchurDecomposition: incorrect TNeeded!")) - return; -//--- check - if(!CAp::Assert((zneeded==0 || zneeded==1) || zneeded==2,"InternalSchurDecomposition: incorrect ZNeeded!")) - return; -//--- initialization - wantt=tneeded==1; - initz=zneeded==2; - wantz=zneeded!=0; - info=0; -//--- Initialize Z, if necessary - if(initz) - { - z.Resize(n+1,n+1); - for(i=1;i<=n;i++) - { - for(j=1;j<=n;j++) - { - //--- check - if(i==j) - z[i].Set(j,1); - else - z[i].Set(j,0); - } - } - } -//--- Quick return if possible - if(n==0) - return; -//--- check - if(n==1) - { - wr[1]=h[1][1]; - wi[1]=0; - //--- exit the function - return; - } -//--- Set rows and columns 1 to N to zero below the first -//--- subdiagonal. - for(j=1;j<=n-2;j++) - for(i=j+2;i<=n;i++) - h[i].Set(j,0); -//--- Test if N is sufficiently small - if((ns<=2 || ns>n) || maxb>=n) - { - //--- Use the standard double-shift algorithm - InternalAuxSchur(wantt,wantz,n,1,n,h,wr,wi,1,n,z,work,workv3,workc1,works1,info); - //--- fill entries under diagonal blocks of T with zeros - if(wantt) - { - j=1; - while(j<=n) - { - //--- check - if(wi[j]==0.0) - { - for(i=j+1;i<=n;i++) - h[i].Set(j,0); - j=j+1; - } - else - { - for(i=j+2;i<=n;i++) - { - h[i].Set(j,0); - h[i].Set(j+1,0); - } - j=j+2; - } - } - } - //--- exit the function - return; - } -//--- change values - unfl=CMath::m_minrealnumber; - ovfl=1/unfl; - ulp=2*CMath::m_machineepsilon; - smlnum=unfl*(n/ulp); -//--- I1 and I2 are the indices of the first row and last column of H -//--- to which transformations must be applied. If eigenvalues only are -//--- being computed, I1 and I2 are set inside the main loop. - i1=1; - i2=n; -//--- ITN is the total number of multiple-shift QR iterations allowed. - itn=30*n; -//--- main block - i=n; - while(true) - { - l=1; - //--- check - if(i<1) - { - //--- fill entries under diagonal blocks of T with zeros - if(wantt) - { - j=1; - while(j<=n) - { - //--- check - if(wi[j]==0.0) - { - for(i=j+1;i<=n;i++) - h[i].Set(j,0); - j=j+1; - } - else - { - for(i=j+2;i<=n;i++) - { - h[i].Set(j,0); - h[i].Set(j+1,0); - } - j=j+2; - } - } - } - //--- Exit - return; - } - //--- Perform multiple-shift QR iterations on rows and columns ILO to I - //--- until a submatrix of order at most MAXB splits off at the bottom - //--- because a subdiagonal element has become negligible. - failflag=true; - for(its=0;its<=itn;its++) - { - //--- Look for a single small subdiagonal element. - for(k=i;k>=l+1;k--) - { - tst1=MathAbs(h[k-1][k-1])+MathAbs(h[k][k]); - //--- check - if(tst1==0.0) - tst1=CBlas::UpperHessenberg1Norm(h,l,i,l,i,work); - //--- check - if(MathAbs(h[k][k-1])<=MathMax(ulp*tst1,smlnum)) - break; - } - l=k; - //--- check - if(l>1) - //--- H(L,L-1) is negligible. - h[l].Set(l-1,0); - //--- Exit from loop if a submatrix of order <= MAXB has split off. - if(l>=i-maxb+1) - { - failflag=false; - break; - } - //--- Now the active submatrix is in rows and columns L to I. If - //--- eigenvalues only are being computed, only the active submatrix - //--- need be transformed. - if(its==20 || its==30) - { - //--- Exceptional shifts. - for(ii=i-ns+1;ii<=i;ii++) - { - wr[ii]=cnst*(MathAbs(h[ii][ii-1])+MathAbs(h[ii][ii])); - wi[ii]=0; - } - } - else - { - //--- Use eigenvalues of trailing submatrix of order NS as shifts. - CBlas::CopyMatrix(h,i-ns+1,i,i-ns+1,i,s,1,ns,1,ns); - //--- function call - InternalAuxSchur(false,false,ns,1,ns,s,tmpwr,tmpwi,1,ns,z,work,workv3,workc1,works1,ierr); - for(p1=1;p1<=ns;p1++) - { - wr[i-ns+p1]=tmpwr[p1]; - wi[i-ns+p1]=tmpwi[p1]; - } - //--- check - if(ierr>0) - { - //--- If DLAHQR failed to compute all NS eigenvalues, use the - //--- unconverged diagonal elements as the remaining shifts. - for(ii=1;ii<=ierr;ii++) - { - wr[i-ns+ii]=s[ii][ii]; - wi[i-ns+ii]=0; - } - } - } - //--- Form the first column of (G-w(1)) (G-w(2)) . . . (G-w(ns)) - //--- where G is the Hessenberg submatrix H(L:I,L:I) and w is - //--- the vector of shifts (stored in WR and WI). The result is - //--- stored in the local array V. - v[1]=1; - for(ii=2;ii<=ns+1;ii++) - v[ii]=0; - nv=1; - for(j=i-ns+1;j<=i;j++) - { - //--- check - if(wi[j]>=0.0) - { - //--- check - if(wi[j]==0.0) - { - //--- real shift - p1=nv+1; - for(i_=1;i_<=p1;i_++) - vv[i_]=v[i_]; - //--- function call - CBlas::MatrixVectorMultiply(h,l,l+nv,l,l+nv-1,false,vv,1,nv,1.0,v,1,nv+1,-wr[j]); - nv=nv+1; - } - else - { - //--- check - if(wi[j]>0.0) - { - //--- complex conjugate pair of shifts - p1=nv+1; - for(i_=1;i_<=p1;i_++) - vv[i_]=v[i_]; - //--- function call - CBlas::MatrixVectorMultiply(h,l,l+nv,l,l+nv-1,false,v,1,nv,1.0,vv,1,nv+1,-(2*wr[j])); - //--- function call - itemp=CBlas::VectorIdxAbsMax(vv,1,nv+1); - temp=1/MathMax(MathAbs(vv[itemp]),smlnum); - p1=nv+1; - for(i_=1;i_<=p1;i_++) - vv[i_]=temp*vv[i_]; - //--- function call - absw=CBlas::PyThag2(wr[j],wi[j]); - temp=temp*absw*absw; - //--- function call - CBlas::MatrixVectorMultiply(h,l,l+nv+1,l,l+nv,false,vv,1,nv+1,1.0,v,1,nv+2,temp); - nv=nv+2; - } - } - //--- Scale V(1:NV) so that max(abs(V(i))) = 1. If V is zero, - //--- reset it to the unit vector. - itemp=CBlas::VectorIdxAbsMax(v,1,nv); - temp=MathAbs(v[itemp]); - //--- check - if(temp==0.0) - { - v[1]=1; - for(ii=2;ii<=nv;ii++) - v[ii]=0; - } - else - { - temp=MathMax(temp,smlnum); - vt=1/temp; - for(i_=1;i_<=nv;i_++) - v[i_]=vt*v[i_]; - } - } - } - //--- Multiple-shift QR step - for(k=l;k<=i-1;k++) - { - //--- The first iteration of this loop determines a reflection G - //--- from the vector V and applies it from left and right to H, - //--- thus creating a nonzero bulge below the subdiagonal. - //--- Each subsequent iteration determines a reflection G to - //--- restore the Hessenberg form in the (K-1)th column, and thus - //--- chases the bulge one step toward the bottom of the active - //--- submatrix. NR is the order of G. - nr=MathMin(ns+1,i-k+1); - //--- check - if(k>l) - { - //--- change values - p1=k-1; - p2=k+nr-1; - i1_=k-1; - for(i_=1;i_<=nr;i_++) - v[i_]=h[i_+i1_][p1]; - } - //--- function call - CReflections::GenerateReflection(v,nr,tau); - //--- check - if(k>l) - { - h[k].Set(k-1,v[1]); - for(ii=k+1;ii<=i;ii++) - h[ii].Set(k-1,0); - } - v[1]=1; - //--- Apply G from the left to transform the rows of the matrix in - //--- columns K to I2. - CReflections::ApplyReflectionFromTheLeft(h,tau,v,k,k+nr-1,k,i2,work); - //--- Apply G from the right to transform the columns of the - //--- matrix in rows I1 to min(K+NR,I). - CReflections::ApplyReflectionFromTheRight(h,tau,v,i1,MathMin(k+nr,i),k,k+nr-1,work); - //--- check - if(wantz) - //--- Accumulate transformations in the matrix Z - CReflections::ApplyReflectionFromTheRight(z,tau,v,1,n,k,k+nr-1,work); - } - } - //--- Failure to converge in remaining number of iterations - if(failflag) - { - info=i; - //--- exit the function - return; - } - //--- A submatrix of order <= MAXB in rows and columns L to I has split - //--- off. Use the double-shift QR algorithm to handle it. - InternalAuxSchur(wantt,wantz,n,l,i,h,wr,wi,1,n,z,work,workv3,workc1,works1,info); - //--- check - if(info>0) - return; - //--- Decrement number of remaining iterations, and return to start of - //--- the main loop with a new value of I. - itn=itn-its; - i=l-1; - } - } -//+------------------------------------------------------------------+ -//| The auxiliary function -//+------------------------------------------------------------------+ -static void CHsSchur::InternalAuxSchur(const bool wantt,const bool wantz, - const int n,const int ilo,const int ihi, - CMatrixDouble &h,double &wr[],double &wi[], - const int iloz,const int ihiz,CMatrixDouble &z, - double &work[],double &workv3[], - double &workc1[],double &works1[],int &info) - { -//--- create variables - int i=0; - int i1=0; - int i2=0; - int itn=0; - int its=0; - int j=0; - int k=0; - int l=0; - int m=0; - int nh=0; - int nr=0; - int nz=0; - double ave=0; - double cs=0; - double disc=0; - double h00=0; - double h10=0; - double h11=0; - double h12=0; - double h21=0; - double h22=0; - double h33=0; - double h33s=0; - double h43h34=0; - double h44=0; - double h44s=0; - double ovfl=0; - double s=0; - double smlnum=0; - double sn=0; - double sum=0; - double t1=0; - double t2=0; - double t3=0; - double tst1=0; - double unfl=0; - double v1=0; - double v2=0; - double v3=0; - bool failflag; - double dat1=0; - double dat2=0; - int p1=0; - double him1im1=0; - double him1i=0; - double hiim1=0; - double hii=0; - double wrim1=0; - double wri=0; - double wiim1=0; - double wii=0; - double ulp=0; -//--- initialization - info=0; - dat1=0.75; - dat2=-0.4375; - ulp=CMath::m_machineepsilon; -//--- Quick return if possible - if(n==0) - return; -//--- check - if(ilo==ihi) - { - wr[ilo]=h[ilo][ilo]; - wi[ilo]=0; - //--- exit the function - return; - } -//--- initialization - nh=ihi-ilo+1; - nz=ihiz-iloz+1; -//--- Set machine-dependent constants for the stopping criterion. -//--- If norm(H) <= sqrt(OVFL), overflow should not occur. - unfl=CMath::m_minrealnumber; - ovfl=1/unfl; - smlnum=unfl*(nh/ulp); -//--- I1 and I2 are the indices of the first row and last column of H -//--- to which transformations must be applied. If eigenvalues only are -//--- being computed, I1 and I2 are set inside the main loop. - i1=1; - i2=n; -//--- ITN is the total number of QR iterations allowed. - itn=30*nh; -//--- The main loop begins here. I is the loop index and decreases from -//--- IHI to ILO in steps of 1 or 2. Each iteration of the loop works -//--- with the active submatrix in rows and columns L to I. -//--- Eigenvalues I+1 to IHI have already converged. Either L = ILO or -//--- H(L,L-1) is negligible so that the matrix splits. - i=ihi; - while(true) - { - l=ilo; - //--- check - if(i=l+1;k--) - { - tst1=MathAbs(h[k-1][k-1])+MathAbs(h[k][k]); - //--- check - if(tst1==0.0) - tst1=CBlas::UpperHessenberg1Norm(h,l,i,l,i,work); - //--- check - if(MathAbs(h[k][k-1])<=MathMax(ulp*tst1,smlnum)) - break; - } - l=k; - //--- check - if(l>ilo) - //--- H(L,L-1) is negligible - h[l].Set(l-1,0); - //--- Exit from loop if a submatrix of order 1 or 2 has split off. - if(l>=i-1) - { - failflag=false; - break; - } - //--- Now the active submatrix is in rows and columns L to I. If - //--- eigenvalues only are being computed, only the active submatrix - //--- need be transformed. - if(its==10 || its==20) - { - //--- Exceptional shift. - s=MathAbs(h[i][i-1])+MathAbs(h[i-1][i-2]); - h44=dat1*s+h[i][i]; - h33=h44; - h43h34=dat2*s*s; - } - else - { - //--- Prepare to use Francis' double shift - //--- (i.e. 2nd degree generalized Rayleigh quotient) - h44=h[i][i]; - h33=h[i-1][i-1]; - h43h34=h[i][i-1]*h[i-1][i]; - s=h[i-1][i-2]*h[i-1][i-2]; - disc=(h33-h44)*0.5; - disc=disc*disc+h43h34; - //--- check - if(disc>0.0) - { - //--- Real roots: use Wilkinson's shift twice - disc=MathSqrt(disc); - ave=0.5*(h33+h44); - //--- check - if(MathAbs(h33)-MathAbs(h44)>0.0) - { - h33=h33*h44-h43h34; - h44=h33/(ExtSchurSign(disc,ave)+ave); - } - else - h44=ExtSchurSign(disc,ave)+ave; - h33=h44; - h43h34=0; - } - } - //--- Look for two consecutive small subdiagonal elements. - for(m=i-2;m>=l;m--) - { - //--- Determine the effect of starting the double-shift QR - //--- iteration at row M, and see if this would make H(M,M-1) - //--- negligible. - h11=h[m][m]; - h22=h[m+1][m+1]; - h21=h[m+1][m]; - h12=h[m][m+1]; - h44s=h44-h11; - h33s=h33-h11; - v1=(h33s*h44s-h43h34)/h21+h12; - v2=h22-h11-h33s-h44s; - v3=h[m+2][m+1]; - s=MathAbs(v1)+MathAbs(v2)+MathAbs(v3); - v1=v1/s; - v2=v2/s; - v3=v3/s; - workv3[1]=v1; - workv3[2]=v2; - workv3[3]=v3; - //--- check - if(m==l) - break; - h00=h[m-1][m-1]; - h10=h[m][m-1]; - tst1=MathAbs(v1)*(MathAbs(h00)+MathAbs(h11)+MathAbs(h22)); - //--- check - if(MathAbs(h10)*(MathAbs(v2)+MathAbs(v3))<=ulp*tst1) - break; - } - //--- Double-shift QR step - for(k=m;k<=i-1;k++) - { - //--- The first iteration of this loop determines a reflection G - //--- from the vector V and applies it from left and right to H, - //--- thus creating a nonzero bulge below the subdiagonal. - //--- Each subsequent iteration determines a reflection G to - //--- restore the Hessenberg form in the (K-1)th column, and thus - //--- chases the bulge one step toward the bottom of the active - //--- submatrix. NR is the order of G. - nr=(int)MathMin(3,i-k+1); - //--- check - if(k>m) - { - for(p1=1;p1<=nr;p1++) - workv3[p1]=h[k+p1-1][k-1]; - } - //--- function call - CReflections::GenerateReflection(workv3,nr,t1); - //--- check - if(k>m) - { - h[k].Set(k-1,workv3[1]); - h[k+1].Set(k-1,0); - //--- check - if(kl) - h[k].Set(k-1,-h[k][k-1]); - } - v2=workv3[2]; - t2=t1*v2; - //--- check - if(nr==3) - { - v3=workv3[3]; - t3=t1*v3; - //--- Apply G from the left to transform the rows of the matrix - //--- in columns K to I2. - for(j=k;j<=i2;j++) - { - sum=h[k][j]+v2*h[k+1][j]+v3*h[k+2][j]; - h[k].Set(j,h[k][j]-sum*t1); - h[k+1].Set(j,h[k+1][j]-sum*t2); - h[k+2].Set(j,h[k+2][j]-sum*t3); - } - //--- Apply G from the right to transform the columns of the - //--- matrix in rows I1 to min(K+3,I). - for(j=i1;j<=MathMin(k+3,i);j++) - { - sum=h[j][k]+v2*h[j][k+1]+v3*h[j][k+2]; - h[j].Set(k,h[j][k]-sum*t1); - h[j].Set(k+1,h[j][k+1]-sum*t2); - h[j].Set(k+2,h[j][k+2]-sum*t3); - } - //--- check - if(wantz) - { - //--- Accumulate transformations in the matrix Z - for(j=iloz;j<=ihiz;j++) - { - sum=z[j][k]+v2*z[j][k+1]+v3*z[j][k+2]; - z[j].Set(k,z[j][k]-sum*t1); - z[j].Set(k+1,z[j][k+1]-sum*t2); - z[j].Set(k+2,z[j][k+2]-sum*t3); - } - } - } - else - { - //--- check - if(nr==2) - { - //--- Apply G from the left to transform the rows of the matrix - //--- in columns K to I2. - for(j=k;j<=i2;j++) - { - sum=h[k][j]+v2*h[k+1][j]; - h[k].Set(j,h[k][j]-sum*t1); - h[k+1].Set(j,h[k+1][j]-sum*t2); - } - //--- Apply G from the right to transform the columns of the - //--- matrix in rows I1 to min(K+3,I). - for(j=i1;j<=i;j++) - { - sum=h[j][k]+v2*h[j][k+1]; - h[j].Set(k,h[j][k]-sum*t1); - h[j].Set(k+1,h[j][k+1]-sum*t2); - } - //--- check - if(wantz) - { - //--- Accumulate transformations in the matrix Z - for(j=iloz;j<=ihiz;j++) - { - sum=z[j][k]+v2*z[j][k+1]; - z[j].Set(k,z[j][k]-sum*t1); - z[j].Set(k+1,z[j][k+1]-sum*t2); - } - } - } - } - } - } - //--- check - if(failflag) - { - //--- Failure to converge in remaining number of iterations - info=i; - //--- exit the function - return; - } - //--- check - if(l==i) - { - //--- H(I,I-1) is negligible: one eigenvalue has converged. - wr[i]=h[i][i]; - wi[i]=0; - } - else - { - //--- check - if(l==i-1) - { - //--- H(I-1,I-2) is negligible: a pair of eigenvalues have converged. - //--- Transform the 2-by-2 submatrix to standard Schur form, - //--- and compute and store the eigenvalues. - him1im1=h[i-1][i-1]; - him1i=h[i-1][i]; - hiim1=h[i][i-1]; - hii=h[i][i]; - //--- function call - Aux2x2Schur(him1im1,him1i,hiim1,hii,wrim1,wiim1,wri,wii,cs,sn); - //--- change values - wr[i-1]=wrim1; - wi[i-1]=wiim1; - wr[i]=wri; - wi[i]=wii; - h[i-1].Set(i-1,him1im1); - h[i-1].Set(i,him1i); - h[i].Set(i-1,hiim1); - h[i].Set(i,hii); - //--- check - if(wantt) - { - //--- Apply the transformation to the rest of H. - if(i2>i) - { - workc1[1]=cs; - works1[1]=sn; - //--- function call - CRotations::ApplyRotationsFromTheLeft(true,i-1,i,i+1,i2,workc1,works1,h,work); - } - workc1[1]=cs; - works1[1]=sn; - //--- function call - CRotations::ApplyRotationsFromTheRight(true,i1,i-2,i-1,i,workc1,works1,h,work); - } - //--- check - if(wantz) - { - //--- Apply the transformation to Z. - workc1[1]=cs; - works1[1]=sn; - //--- function call - CRotations::ApplyRotationsFromTheRight(true,iloz,iloz+nz-1,i-1,i,workc1,works1,z,work); - } - } - } - //--- Decrement number of remaining iterations, and return to start of - //--- the main loop with new value of I. - itn=itn-its; - i=l-1; - } - } -//+------------------------------------------------------------------+ -//| 2x2 | -//+------------------------------------------------------------------+ -static void CHsSchur::Aux2x2Schur(double &a,double &b,double &c,double &d, - double &rt1r,double &rt1i,double &rt2r, - double &rt2i,double &cs,double &sn) - { -//--- create variables - double multpl=0; - double aa=0; - double bb=0; - double bcmax=0; - double bcmis=0; - double cc=0; - double cs1=0; - double dd=0; - double eps=0; - double p=0; - double sab=0; - double sac=0; - double scl=0; - double sigma=0; - double sn1=0; - double tau=0; - double temp=0; - double z=0; -//--- initialization - rt1r=0; - rt1i=0; - rt2r=0; - rt2i=0; - cs=0; - sn=0; - multpl=4.0; - eps=CMath::m_machineepsilon; -//--- check - if(c==0.0) - { - cs=1; - sn=0; - } - else - { - //--- check - if(b==0.0) - { - //--- Swap rows and columns - cs=0; - sn=1; - temp=d; - d=a; - a=temp; - b=-c; - c=0; - } - else - { - //--- check - if(a-d==0.0 && ExtSchurSignToone(b)!=ExtSchurSignToone(c)) - { - cs=1; - sn=0; - } - else - { - //--- change values - temp=a-d; - p=0.5*temp; - bcmax=MathMax(MathAbs(b),MathAbs(c)); - bcmis=MathMin(MathAbs(b),MathAbs(c))*ExtSchurSignToone(b)*ExtSchurSignToone(c); - scl=MathMax(MathAbs(p),bcmax); - z=p/scl*p+bcmax/scl*bcmis; - //--- If Z is of the order of the machine accuracy, postpone the - //--- decision on the nature of eigenvalues - if(z>=multpl*eps) - { - //--- Real eigenvalues. Compute A and D. - z=p+ExtSchurSign(MathSqrt(scl)*MathSqrt(z),p); - a=d+z; - d=d-bcmax/z*bcmis; - //--- Compute B and the rotation matrix - tau=CBlas::PyThag2(c,z); - cs=z/tau; - sn=c/tau; - b=b-c; - c=0; - } - else - { - //--- Complex eigenvalues, or real (almost) equal eigenvalues. - //--- Make diagonal elements equal. - sigma=b+c; - tau=CBlas::PyThag2(sigma,temp); - cs=MathSqrt(0.5*(1+MathAbs(sigma)/tau)); - sn=-(p/(tau*cs)*ExtSchurSign(1,sigma)); - //--- Compute [ AA BB ] = [ A B ] [ CS -SN ] - //--- [ CC DD ] [ C D ] [ SN CS ] - aa=a*cs+b*sn; - bb=-(a*sn)+b*cs; - cc=c*cs+d*sn; - dd=-(c*sn)+d*cs; - //--- Compute [ A B ] = [ CS SN ] [ AA BB ] - //--- [ C D ] [-SN CS ] [ CC DD ] - a=aa*cs+cc*sn; - b=bb*cs+dd*sn; - c=-(aa*sn)+cc*cs; - d=-(bb*sn)+dd*cs; - temp=0.5*(a+d); - a=temp; - d=temp; - //--- check - if(c!=0.0) - { - //--- check - if(b!=0.0) - { - //--- check - if(ExtSchurSignToone(b)==ExtSchurSignToone(c)) - { - //--- Real eigenvalues: reduce to upper triangular form - sab=MathSqrt(MathAbs(b)); - sac=MathSqrt(MathAbs(c)); - //--- function call - p=ExtSchurSign(sab*sac,c); - tau=1/MathSqrt(MathAbs(b+c)); - a=temp+p; - d=temp-p; - b=b-c; - c=0; - cs1=sab*tau; - sn1=sac*tau; - temp=cs*cs1-sn*sn1; - sn=cs*sn1+sn*cs1; - cs=temp; - } - } - else - { - //--- change values - b=-c; - c=0; - temp=cs; - cs=-sn; - sn=temp; - } - } - } - } - } - } -//--- Store eigenvalues in (RT1R,RT1I) and (RT2R,RT2I). - rt1r=a; - rt2r=d; -//--- check - if(c==0.0) - { - rt1i=0; - rt2i=0; - } - else - { - rt1i=MathSqrt(MathAbs(b))*MathSqrt(MathAbs(c)); - rt2i=-rt1i; - } - } -//+------------------------------------------------------------------+ -//| Schur sign | -//+------------------------------------------------------------------+ -static double CHsSchur::ExtSchurSign(const double a,const double b) - { -//--- create variables - double result=0; -//--- check - if(b>=0.0) - result=MathAbs(a); - else - result=-MathAbs(a); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Schur sign (1 or -1) | -//+------------------------------------------------------------------+ -static int CHsSchur::ExtSchurSignToone(const double b) - { -//--- create variables - int result=0; -//--- check - if(b>=0.0) - result=1; - else - result=-1; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Safe solutions for tridiagonal linear matrix | -//+------------------------------------------------------------------+ -class CTrLinSolve - { -public: - //--- constructor, destructor - CTrLinSolve(void); - ~CTrLinSolve(void); - //--- methods - static void RMatrixTrSafeSolve(CMatrixDouble &a,const int n,double &x[],double &s,const bool isupper,const bool istrans,const bool isunit); - static void SafeSolveTriangular(CMatrixDouble &a,const int n,double &x[],double &s,const bool isupper,const bool istrans,const bool isunit,const bool normin,double &cnorm[]); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CTrLinSolve::CTrLinSolve(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CTrLinSolve::~CTrLinSolve(void) - { - - } -//+------------------------------------------------------------------+ -//| Utility subroutine performing the "safe" solution of system of | -//| linear equations with triangular coefficient matrices. | -//| The subroutine uses scaling and solves the scaled system A*x=s*b | -//| (where s is a scalar value) instead of A*x=b, choosing | -//| s so that x can be represented by a floating-point number. The | -//| closer the system gets to a singular, the less s is. If the | -//| system is singular, s=0 and x contains the non-trivial solution | -//| of equation A*x=0. | -//| The feature of an algorithm is that it could not cause an | -//| overflow or a division by zero regardless of the matrix used | -//| as the input. | -//| The algorithm can solve systems of equations with upper/lower | -//| triangular matrices, with/without unit diagonal, and systems of | -//| type A*x=b or A'*x=b (where A' is a transposed matrix A). | -//| Input parameters: | -//| A - system matrix. Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| X - right-hand member of a system. | -//| Array whose index ranges within [0..N-1]. | -//| IsUpper - matrix type. If it is True, the system matrix is | -//| the upper triangular and is located in the | -//| corresponding part of matrix A. | -//| Trans - problem type. If it is True, the problem to be | -//| solved is A'*x=b, otherwise it is A*x=b. | -//| Isunit - matrix type. If it is True, the system matrix has| -//| a unit diagonal (the elements on the main | -//| diagonal are not used in the calculation | -//| process), otherwise the matrix is considered to | -//| be a general triangular matrix. | -//| Output parameters: | -//| X - solution. Array whose index ranges within | -//| [0..N-1]. | -//| S - scaling factor. | -//| -- LAPACK auxiliary routine (version 3.0) -- | -//| Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., | -//| Courant Institute, Argonne National Lab, and Rice University| -//| June 30, 1992 | -//+------------------------------------------------------------------+ -static void CTrLinSolve::RMatrixTrSafeSolve(CMatrixDouble &a,const int n, - double &x[],double &s, - const bool isupper, - const bool istrans, - const bool isunit) - { -//--- create variables - bool normin; - int i=0; - int i_=0; - int i1_=0; -//--- create arrays - double cnorm[]; - double x1[]; -//--- create matrix - CMatrixDouble a1; -//--- initialization - s=0; -//--- From 0-based to 1-based - normin=false; -//--- allocation - a1.Resize(n+1,n+1); - ArrayResizeAL(x1,n+1); - for(i=1;i<=n;i++) - { - i1_=-1; - for(i_=1;i_<=n;i_++) - a1[i].Set(i_,a[i-1][i_+i1_]); - } -//--- change values - i1_=-1; - for(i_=1;i_<=n;i_++) - x1[i_]=x[i_+i1_]; -//--- Solve 1-based - SafeSolveTriangular(a1,n,x1,s,isupper,istrans,isunit,normin,cnorm); -//--- From 1-based to 0-based - i1_=1; - for(i_=0;i_<=n-1;i_++) - x[i_]=x1[i_+i1_]; - } -//+------------------------------------------------------------------+ -//| Obsolete 1-based subroutine. | -//| See RMatrixTRSafeSolve for 0-based replacement. | -//+------------------------------------------------------------------+ -static void CTrLinSolve::SafeSolveTriangular(CMatrixDouble &a,const int n, - double &x[],double &s, - const bool isupper, - const bool istrans, - const bool isunit, - const bool normin, - double &cnorm[]) - { -//--- create variables - int i=0; - int imax=0; - int j=0; - int jfirst=0; - int jinc=0; - int jlast=0; - int jm1=0; - int jp1=0; - int ip1=0; - int im1=0; - int k=0; - int flg=0; - double v=0; - double vd=0; - double bignum=0; - double grow=0; - double rec=0; - double smlnum=0; - double sumj=0; - double tjj=0; - double tjjs=0; - double tmax=0; - double tscal=0; - double uscal=0; - double xbnd=0; - double xj=0; - double xmax=0; - bool notran; - bool upper; - bool nounit; - int i_=0; -//--- initialization - s=0; - upper=isupper; - notran=!istrans; - nounit=!isunit; -//--- these initializers are not really necessary, -//--- but without them compiler complains about uninitialized locals - tjjs=0; -//--- Quick return if possible - if(n==0) - return; -//--- Determine machine dependent parameters to control overflow. - smlnum=CMath::m_minrealnumber/(CMath::m_machineepsilon*2); - bignum=1/smlnum; - s=1; -//--- check - if(!normin) - { - ArrayResizeAL(cnorm,n+1); - //--- Compute the 1-norm of each column,not including the diagonal. - if(upper) - { - //--- A is upper triangular. - for(j=1;j<=n;j++) - { - v=0; - for(k=1;k<=j-1;k++) - v=v+MathAbs(a[k][j]); - cnorm[j]=v; - } - } - else - { - //--- A is lower triangular. - for(j=1;j<=n-1;j++) - { - v=0; - for(k=j+1;k<=n;k++) - v=v+MathAbs(a[k][j]); - cnorm[j]=v; - } - cnorm[n]=0; - } - } -//--- Scale the column norms by TSCAL if the maximum element in CNORM is -//--- greater than BIGNUM. - imax=1; - for(k=2;k<=n;k++) - { - //--- check - if(cnorm[k]>cnorm[imax]) - imax=k; - } - tmax=cnorm[imax]; -//--- check - if(tmax<=bignum) - tscal=1; - else - { - tscal=1/(smlnum*tmax); - for(i_=1;i_<=n;i_++) - cnorm[i_]=tscal*cnorm[i_]; - } -//--- Compute a bound on the computed solution vector to see if the -//--- Level 2 BLAS routine DTRSV can be used. - j=1; - for(k=2;k<=n;k++) - { - //--- check - if(MathAbs(x[k])>MathAbs(x[j])) - j=k; - } -//--- change values - xmax=MathAbs(x[j]); - xbnd=xmax; -//--- check - if(notran) - { - //--- Compute the growth in A * x=b. - if(upper) - { - jfirst=n; - jlast=1; - jinc=-1; - } - else - { - jfirst=1; - jlast=n; - jinc=1; - } - //--- check - if(tscal!=1.0) - grow=0; - else - { - //--- check - if(nounit) - { - //--- A is non-unit triangular. - //--- Compute GROW=1/G(j) and XBND=1/M(j). - //--- Initially,G(0)=max{x(i),i=1,...,n}. - grow=1/MathMax(xbnd,smlnum); - xbnd=grow; - j=jfirst; - while((jinc>0 && j<=jlast) || (jinc<0 && j>=jlast)) - { - //--- Exit the loop if the growth factor is too small. - if(grow<=smlnum) - break; - //--- M(j)=G(j-1) / abs(A(j,j)) - tjj=MathAbs(a[j][j]); - xbnd=MathMin(xbnd,MathMin(1,tjj)*grow); - //--- check - if(tjj+cnorm[j]>=smlnum) - { - //--- G(j)=G(j-1)*( 1 + CNORM(j) / abs(A(j,j)) ) - grow=grow*(tjj/(tjj+cnorm[j])); - } - else - { - //--- G(j) could overflow,set GROW to 0. - grow=0; - } - //--- check - if(j==jlast) - grow=xbnd; - j=j+jinc; - } - } - else - { - //--- A is unit triangular. - //--- Compute GROW=1/G(j), where G(0)=max{x(i), i=1,...,n}. - grow=MathMin(1,1/MathMax(xbnd,smlnum)); - j=jfirst; - while((jinc>0 && j<=jlast) || (jinc<0 && j>=jlast)) - { - //--- Exit the loop if the growth factor is too small. - if(grow<=smlnum) - break; - //--- G(j) = G(j-1)*( 1 + CNORM(j) ) - grow=grow*(1/(1+cnorm[j])); - j=j+jinc; - } - } - } - } - else - { - //--- Compute the growth in A' * x = b. - if(upper) - { - jfirst=1; - jlast=n; - jinc=1; - } - else - { - jfirst=n; - jlast=1; - jinc=-1; - } - //--- check - if(tscal!=1.0) - grow=0; - else - { - //--- check - if(nounit) - { - //--- A is non-unit triangular. - //--- Compute GROW=1/G(j) and XBND=1/M(j). - //--- Initially, M(0)=max{x(i), i=1,...,n}. - grow=1/MathMax(xbnd,smlnum); - xbnd=grow; - j=jfirst; - while((jinc>0 && j<=jlast) || (jinc<0 && j>=jlast)) - { - //--- Exit the loop if the growth factor is too small. - if(grow<=smlnum) - break; - //--- G(j) = max( G(j-1), M(j-1)*( 1 + CNORM(j) ) ) - xj=1+cnorm[j]; - grow=MathMin(grow,xbnd/xj); - //--- M(j)=M(j-1)*( 1 + CNORM(j) ) / abs(A(j,j)) - tjj=MathAbs(a[j][j]); - //--- check - if(xj>tjj) - xbnd=xbnd*(tjj/xj); - //--- check - if(j==jlast) - grow=MathMin(grow,xbnd); - j=j+jinc; - } - } - else - { - //--- A is unit triangular. - //--- Compute GROW=1/G(j), where G(0)=max{x(i), i=1,...,n}. - grow=MathMin(1,1/MathMax(xbnd,smlnum)); - j=jfirst; - while((jinc>0 && j<=jlast) || (jinc<0 && j>=jlast)) - { - //--- Exit the loop if the growth factor is too small. - if(grow<=smlnum) - break; - //--- G(j)=( 1 + CNORM(j) )*G(j-1) - xj=1+cnorm[j]; - grow=grow/xj; - j=j+jinc; - } - } - } - } - if(grow*tscal>smlnum) - { - //--- Use the Level 2 BLAS solve if the reciprocal of the bound on - //--- elements of X is not too small. - if((upper && notran) || (!upper && !notran)) - { - //--- check - if(nounit) - vd=a[n][n]; - else - vd=1; - x[n]=x[n]/vd; - for(i=n-1;i>=1;i--) - { - ip1=i+1; - //--- check - if(upper) - { - v=0.0; - for(i_=ip1;i_<=n;i_++) - v+=a[i][i_]*x[i_]; - } - else - { - v=0.0; - for(i_=ip1;i_<=n;i_++) - v+=a[i_][i]*x[i_]; - } - //--- check - if(nounit) - vd=a[i][i]; - else - vd=1; - x[i]=(x[i]-v)/vd; - } - } - else - { - //--- check - if(nounit) - vd=a[1][1]; - else - vd=1; - x[1]=x[1]/vd; - for(i=2;i<=n;i++) - { - im1=i-1; - //--- check - if(upper) - { - v=0.0; - for(i_=1;i_<=im1;i_++) - v+=a[i_][i]*x[i_]; - } - else - { - v=0.0; - for(i_=1;i_<=im1;i_++) - v+=a[i][i_]*x[i_]; - } - //--- check - if(nounit) - vd=a[i][i]; - else - vd=1; - x[i]=(x[i]-v)/vd; - } - } - } - else - { - //--- Use a Level 1 BLAS solve, scaling intermediate results. - if(xmax>bignum) - { - //--- Scale X so that its components are less than or equal to - //--- BIGNUM in absolute value. - s=bignum/xmax; - for(i_=1;i_<=n;i_++) - x[i_]=s*x[i_]; - xmax=bignum; - } - //--- check - if(notran) - { - //--- Solve A * x = b - j=jfirst; - while((jinc>0 && j<=jlast) || (jinc<0 && j>=jlast)) - { - //--- Compute x(j)=b(j) / A(j,j), scaling x if necessary. - xj=MathAbs(x[j]); - flg=0; - //--- check - if(nounit) - tjjs=a[j][j]*tscal; - else - { - tjjs=tscal; - //--- check - if(tscal==1.0) - flg=100; - } - //--- check - if(flg!=100) - { - tjj=MathAbs(tjjs); - if(tjj>smlnum) - { - //--- abs(A(j,j)) > SMLNUM: - if(tjj<1.0) - { - //--- check - if(xj>(double)(tjj*bignum)) - { - //--- Scale x by 1/b(j). - rec=1/xj; - for(i_=1;i_<=n;i_++) - { - x[i_]=rec*x[i_]; - } - s=s*rec; - xmax=xmax*rec; - } - } - x[j]=x[j]/tjjs; - xj=MathAbs(x[j]); - } - else - { - //--- check - if(tjj>0.0) - { - //--- 0 < abs(A(j,j)) <=SMLNUM: - if(xj>(double)(tjj*bignum)) - { - //--- Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM - //--- to avoid overflow when dividing by A(j,j). - rec=tjj*bignum/xj; - //--- check - if(cnorm[j]>1.0) - { - //--- Scale by 1/CNORM(j) to avoid overflow when - //--- multiplying x(j) times column j. - rec=rec/cnorm[j]; - } - for(i_=1;i_<=n;i_++) - x[i_]=rec*x[i_]; - s=s*rec; - xmax=xmax*rec; - } - x[j]=x[j]/tjjs; - xj=MathAbs(x[j]); - } - else - { - //--- A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and - //--- scale = 0, and compute a solution to A*x = 0. - for(i=1;i<=n;i++) - x[i]=0; - //--- change values - x[j]=1; - xj=1; - s=0; - xmax=0; - } - } - } - //--- Scale x if necessary to avoid overflow when adding a - //--- multiple of column j of A. - if(xj>1.0) - { - rec=1/xj; - //--- check - if(cnorm[j]>(bignum-xmax)*rec) - { - //--- Scale x by 1/(2*abs(x(j))). - rec=rec*0.5; - for(i_=1;i_<=n;i_++) - x[i_]=rec*x[i_]; - s=s*rec; - } - } - else - { - //--- check - if(xj*cnorm[j]>bignum-xmax) - { - //--- Scale x by 1/2. - for(i_=1;i_<=n;i_++) - x[i_]=0.5*x[i_]; - s=s*0.5; - } - } - //--- check - if(upper) - { - //--- check - if(j>1) - { - //--- Compute the update - //--- x(1:j-1) := x(1:j-1) - x(j) * A(1:j-1,j) - v=x[j]*tscal; - jm1=j-1; - //--- change x - for(i_=1;i_<=jm1;i_++) - x[i_]=x[i_]-v*a[i_][j]; - i=1; - for(k=2;k<=j-1;k++) - { - //--- check - if(MathAbs(x[k])>MathAbs(x[i])) - i=k; - } - xmax=MathAbs(x[i]); - } - } - else - { - //--- check - if(jMathAbs(x[i])) - i=k; - } - xmax=MathAbs(x[i]); - } - } - j=j+jinc; - } - } - else - { - //--- Solve A' * x = b - j=jfirst; - while((jinc>0 && j<=jlast) || (jinc<0 && j>=jlast)) - { - //--- Compute x(j) = b(j) - sum A(k,j)*x(k). - //--- k<>j - xj=MathAbs(x[j]); - uscal=tscal; - rec=1/MathMax(xmax,1); - //--- check - if(cnorm[j]>(bignum-xj)*rec) - { - //--- If x(j) could overflow,scale x by 1/(2*XMAX). - rec=rec*0.5; - //--- check - if(nounit) - tjjs=a[j][j]*tscal; - else - tjjs=tscal; - tjj=MathAbs(tjjs); - //--- check - if(tjj>1.0) - { - //--- Divide by A(j,j) when scaling x if A(j,j) > 1. - rec=MathMin(1,rec*tjj); - uscal=uscal/tjjs; - } - //--- check - if(rec<1.0) - { - for(i_=1;i_<=n;i_++) - x[i_]=rec*x[i_]; - s=s*rec; - xmax=xmax*rec; - } - } - sumj=0; - //--- check - if(uscal==1.0) - { - //--- If the scaling needed for A in the dot product is 1, - //--- call DDOT to perform the dot product. - if(upper) - { - //--- check - if(j>1) - { - jm1=j-1; - sumj=0.0; - for(i_=1;i_<=jm1;i_++) - sumj+=a[i_][j]*x[i_]; - } - else - sumj=0; - } - else - { - //--- check - if(jsmlnum) - { - //--- abs(A(j,j)) > SMLNUM: - if(tjj<1.0) - { - //--- check - if(xj>(double)(tjj*bignum)) - { - //--- Scale X by 1/abs(x(j)). - rec=1/xj; - for(i_=1;i_<=n;i_++) - x[i_]=rec*x[i_]; - s=s*rec; - xmax=xmax*rec; - } - } - x[j]=x[j]/tjjs; - } - else - { - //--- check - if(tjj>0.0) - { - //--- 0 < abs(A(j,j)) <=SMLNUM: - if(xj>(double)(tjj*bignum)) - { - //--- Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM. - rec=tjj*bignum/xj; - for(i_=1;i_<=n;i_++) - x[i_]=rec*x[i_]; - s=s*rec; - xmax=xmax*rec; - } - x[j]=x[j]/tjjs; - } - else - { - //--- A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and - //--- scale = 0, and compute a solution to A'*x = 0. - for(i=1;i<=n;i++) - x[i]=0; - x[j]=1; - s=0; - xmax=0; - } - } - } - } - else - { - //--- Compute x(j) := x(j) / A(j,j) - sumj if the dot - //--- product has already been divided by 1/A(j,j). - x[j]=x[j]/tjjs-sumj; - } - xmax=MathMax(xmax,MathAbs(x[j])); - j=j+jinc; - } - } - s=s/tscal; - } -//--- Scale the column norms by 1/TSCAL for return. - if(tscal!=1.0) - { - v=1/tscal; - for(i_=1;i_<=n;i_++) - cnorm[i_]=v*cnorm[i_]; - } - } -//+------------------------------------------------------------------+ -//| Safe solvers | -//+------------------------------------------------------------------+ -class CSafeSolve - { -private: - //--- private method - static bool CBasicSolveAndUpdate(al_complex &alpha,al_complex &beta,const double lnmax,const double bnorm,const double maxgrowth,double &xnorm,al_complex &x); -public: - //--- constructor, destructor - CSafeSolve(void); - ~CSafeSolve(void); - //--- public methods - static bool RMatrixScaledTrSafeSolve(CMatrixDouble &a,const double sa,const int n,double &x[],const bool isupper,const int trans,const bool isunit,const double maxgrowth); - static bool CMatrixScaledTrSafeSolve(CMatrixComplex &a,const double sa,const int n,al_complex &x[],const bool isupper,const int trans,const bool isunit,const double maxgrowth); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CSafeSolve::CSafeSolve(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSafeSolve::~CSafeSolve(void) - { - - } -//+------------------------------------------------------------------+ -//| Real implementation of CMatrixScaledTRSafeSolve | -//+------------------------------------------------------------------+ -static bool CSafeSolve::RMatrixScaledTrSafeSolve(CMatrixDouble &a,const double sa, - const int n,double &x[], - const bool isupper,const int trans, - const bool isunit,const double maxgrowth) - { -//--- create variables - bool result; - double lnmax=0; - double nrmb=0; - double nrmx=0; - double vr=0; - al_complex alpha=0; - al_complex beta=0; - al_complex cx=0; - int i_=0; - int i=0; -//--- create array - double tmp[]; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": incorrect N!")) - return(false); -//--- check - if(!CAp::Assert(trans==0 || trans==1,__FUNCTION__+": incorrect Trans!")) - return(false); -//--- initialization - result=true; - lnmax=MathLog(CMath::m_maxrealnumber); -//--- Quick return if possible - if(n<=0) - return(result); -//--- Load norms: right part and X - nrmb=0; - for(i=0;i=0;i--) - { - //--- Task is reduced to alpha*x[i] = beta - if(isunit) - alpha=sa; - else - alpha=a[i][i]*sa; - //--- check - if(i0) - { - for(i_=0;i_=0;i--) - { - //--- Task is reduced to alpha*x[i] = beta - if(isunit) - alpha=sa; - else - alpha=a[i][i]*sa; - beta=x[i]; - //--- solve alpha*x[i] = beta - result=CBasicSolveAndUpdate(alpha,beta,lnmax,nrmb,maxgrowth,nrmx,cx); - //--- check - if(!result) - return(result); - //--- change values - x[i]=cx.re; - //--- update the rest of right part - if(i>0) - { - vr=cx.re; - for(i_=0;i_0,__FUNCTION__+": incorrect N!")) - return(false); -//--- check - if(!CAp::Assert((trans==0 || trans==1) || trans==2,__FUNCTION__+": incorrect Trans!")) - return(false); -//--- initialization - result=true; - lnmax=MathLog(CMath::m_maxrealnumber); -//--- Quick return if possible - if(n<=0) - return(result); -//--- Load norms: right part and X - nrmb=0; - for(i=0;i=0;i--) - { - //--- Task is reduced to alpha*x[i] = beta - if(isunit) - alpha=sa; - else - alpha=a[i][i]*sa; - //--- check - if(i0) - { - for(i_=0;i_=0;i--) - { - //--- Task is reduced to alpha*x[i] = beta - if(isunit) - alpha=sa; - else - alpha=a[i][i]*sa; - beta=x[i]; - //--- solve alpha*x[i] = beta - result=CBasicSolveAndUpdate(alpha,beta,lnmax,nrmb,maxgrowth,nrmx,vc); - //--- check - if(!result) - return(result); - x[i]=vc; - //--- update the rest of right part - if(i>0) - { - for(i_=0;i_=0;i--) - { - //--- Task is reduced to alpha*x[i] = beta - if(isunit) - alpha=sa; - else - alpha=CMath::Conj(a[i][i])*sa; - beta=x[i]; - //--- solve alpha*x[i] = beta - result=CBasicSolveAndUpdate(alpha,beta,lnmax,nrmb,maxgrowth,nrmx,vc); - //--- check - if(!result) - return(result); - x[i]=vc; - //--- update the rest of right part - if(i>0) - { - for(i_=0;i_lnmax) - return(result); - x=beta/alpha; - } - else - { - //--- alpha*x[i]=0 - x=0; - } -//--- update NrmX, test growth limit - xnorm=MathMax(xnorm,CMath::AbsComplex(x)); -//--- check - if(xnorm>maxgrowth*bnorm) - return(result); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Dot-product | -//+------------------------------------------------------------------+ -class CXblas - { -private: - //--- private methods - static void XSum(double &w[],const double mx,const int n,double &r,double &rerr); - static double XFastPow(const double r,const int n); -public: - //--- constructor, destructor - CXblas(void); - ~CXblas(void); - //--- public methods - static void XDot(double &a[],double &b[],const int n,double &temp[],double &r,double &rerr); - static void XCDot(al_complex &a[],al_complex &b[],const int n,double &temp[],al_complex &r,double &rerr); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CXblas::CXblas(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CXblas::~CXblas(void) - { - - } -//+------------------------------------------------------------------+ -//| More precise dot-product. Absolute error of subroutine result is | -//| about 1 ulp of max(MX,V), where: | -//| MX = max( |a[i]*b[i]| ) | -//| V = |(a,b)| | -//| INPUT PARAMETERS | -//| A - array[0..N-1], vector 1 | -//| B - array[0..N-1], vector 2 | -//| N - vectors length, N<2^29. | -//| Temp - array[0..N-1], pre-allocated temporary storage | -//| OUTPUT PARAMETERS | -//| R - (A,B) | -//| RErr - estimate of error. This estimate accounts for | -//| both errors during calculation of (A,B) and | -//| errors introduced by rounding of A and B to fit in| -//| double (about 1 ulp). | -//+------------------------------------------------------------------+ -static void CXblas::XDot(double &a[],double &b[],const int n,double &temp[], - double &r,double &rerr) - { -//--- create variables - int i=0; - double mx=0; - double v=0; -//--- initialization - r=0; - rerr=0; -//--- special cases: -//--- * N=0 - if(n==0) - { - r=0; - rerr=0; - //--- exit the function - return; - } - mx=0; -//--- calculations - for(i=0;i<=n-1;i++) - { - v=a[i]*b[i]; - temp[i]=v; - mx=MathMax(mx,MathAbs(v)); - } -//--- check - if(mx==0.0) - { - r=0; - rerr=0; - //--- exit the function - return; - } -//--- function call - XSum(temp,mx,n,r,rerr); - } -//+------------------------------------------------------------------+ -//| More precise complex dot-product. Absolute error of subroutine | -//| result is about 1 ulp of max(MX,V), where: | -//| MX = max( |a[i]*b[i]| ) | -//| V = |(a,b)| | -//| INPUT PARAMETERS | -//| A - array[0..N-1], vector 1 | -//| B - array[0..N-1], vector 2 | -//| N - vectors length, N<2^29. | -//| Temp - array[0..2*N-1], pre-allocated temporary storage | -//| OUTPUT PARAMETERS | -//| R - (A,B) | -//| RErr - estimate of error. This estimate accounts for | -//| both errors during calculation of (A,B) and | -//| errors introduced by rounding of A and B to fit | -//| in double (about 1 ulp). | -//+------------------------------------------------------------------+ -static void CXblas::XCDot(al_complex &a[],al_complex &b[],const int n,double &temp[], - al_complex &r,double &rerr) - { -//--- create variables - int i=0; - double mx=0; - double v=0; - double rerrx=0; - double rerry=0; -//--- initialization - r=0; - rerr=0; -//--- special cases: -//--- * N=0 - if(n==0) - { - r=0; - rerr=0; - //--- exit the function - return; - } -//--- calculate real part - mx=0; - for(i=0;i<=n-1;i++) - { - //--- change values - v=a[i].re*b[i].re; - temp[2*i+0]=v; - mx=MathMax(mx,MathAbs(v)); - v=-(a[i].im*b[i].im); - temp[2*i+1]=v; - mx=MathMax(mx,MathAbs(v)); - } -//--- check - if(mx==0.0) - { - r.re=0; - rerrx=0; - } - else - XSum(temp,mx,2*n,r.re,rerrx); -//--- calculate imaginary part - mx=0; - for(i=0;i<=n-1;i++) - { - //--- change values - v=a[i].re*b[i].im; - temp[2*i+0]=v; - mx=MathMax(mx,MathAbs(v)); - v=a[i].im*b[i].re; - temp[2*i+1]=v; - mx=MathMax(mx,MathAbs(v)); - } -//--- check - if(mx==0.0) - { - r.im=0; - rerry=0; - } - else - XSum(temp,mx,2*n,r.im,rerry); -//--- total error - if(rerrx==0.0 && rerry==0.0) - rerr=0; - else - rerr=MathMax(rerrx,rerry)*MathSqrt(1+CMath::Sqr(MathMin(rerrx,rerry)/MathMax(rerrx,rerry))); - } -//+------------------------------------------------------------------+ -//| Internal subroutine for extra-precise calculation of SUM(w[i]). | -//| INPUT PARAMETERS: | -//| W - array[0..N-1], values to be added | -//| W is modified during calculations. | -//| MX - max(W[i]) | -//| N - array size | -//| OUTPUT PARAMETERS: | -//| R - SUM(w[i]) | -//| RErr- error estimate for R | -//+------------------------------------------------------------------+ -static void CXblas::XSum(double &w[],const double mx,const int n,double &r, - double &rerr) - { -//--- create variables - int i=0; - int k=0; - int ks=0; - double v=0; - double s=0; - double ln2=0; - double chunk=0; - double invchunk=0; - bool allzeros; - int i_=0; -//--- initialization - r=0; - rerr=0; -//--- special cases: -//--- * N=0 -//--- * N is too large to use integer arithmetics - if(n==0) - { - r=0; - rerr=0; - //--- exit the function - return; - } -//--- check - if(mx==0.0) - { - r=0; - rerr=0; - //--- exit the function - return; - } -//--- check - if(!CAp::Assert(n<536870912,__FUNCTION__+": N is too large!")) - return; -//--- Prepare - ln2=MathLog(2); - rerr=mx*CMath::m_machineepsilon; -//--- 1. find S such that 0.5<=S*MX<1 -//--- 2. multiply W by S, so task is normalized in some sense -//--- 3. S:=1/S so we can obtain original vector multiplying by S - k=(int)MathRound(MathLog(mx)/ln2); - s=XFastPow(2,-k); -//--- change s - while(s*mx>=1.0) - s=0.5*s; - while(s*mx<0.5) - s=2*s; - for(i_=0;i_<=n-1;i_++) - w[i_]=s*w[i_]; - s=1/s; -//--- find Chunk=2^M such that N*Chunk<2^29 -//--- we have chosen upper limit (2^29) with enough space left -//--- to tolerate possible problems with rounding and N's close -//--- to the limit, so we don't want to be very strict here. - k=(int)(MathLog((double)536870912/(double)n)/ln2); - chunk=XFastPow(2,k); -//--- check - if(chunk<2.0) - chunk=2; - invchunk=1/chunk; -//--- calculate result - r=0; - for(i_=0;i_<=n-1;i_++) - w[i_]=chunk*w[i_]; -//--- cycle - while(true) - { - //--- change values - s=s*invchunk; - allzeros=true; - ks=0; - for(i=0;i<=n-1;i++) - { - v=w[i]; - k=(int)(v); - //--- check - if(v!=k) - allzeros=false; - w[i]=chunk*(v-k); - ks=ks+k; - } - r=r+s*ks; - v=MathAbs(r); - //--- check - if(allzeros || s*n+mx==mx) - break; - } -//--- correct error - rerr=MathMax(rerr,MathAbs(r)*CMath::m_machineepsilon); - } -//+------------------------------------------------------------------+ -//| Fast Pow | -//+------------------------------------------------------------------+ -static double CXblas::XFastPow(const double r,const int n) - { -//--- create a variable - double result=0; -//--- check - if(n>0) - { - //--- check - if(n%2==0) - result=CMath::Sqr(XFastPow(r,n/2)); - else - result=r*XFastPow(r,n-1); - //--- return result - return(result); - } -//--- check - if(n==0) - result=1; -//--- check - if(n<0) - result=XFastPow(1/r,-n); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Auxiliary class for CLinMin | -//+------------------------------------------------------------------+ -class CLinMinState - { -public: - //--- class variables - bool m_brackt; - bool m_stage1; - int m_infoc; - double m_dg; - double m_dgm; - double m_dginit; - double m_dgtest; - double m_dgx; - double m_dgxm; - double m_dgy; - double m_dgym; - double m_finit; - double m_ftest1; - double m_fm; - double m_fx; - double m_fxm; - double m_fy; - double m_fym; - double m_stx; - double m_sty; - double m_stmin; - double m_stmax; - double m_width; - double m_width1; - double m_xtrapf; - //--- constructor, destructor - CLinMinState(void); - ~CLinMinState(void); - //--- create a copy - void Copy(CLinMinState &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CLinMinState::CLinMinState(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CLinMinState::~CLinMinState(void) - { - - } -//+------------------------------------------------------------------+ -//| Create a copy | -//+------------------------------------------------------------------+ -void CLinMinState::Copy(CLinMinState &obj) - { -//--- copy variables - m_brackt=obj.m_brackt; - m_stage1=obj.m_stage1; - m_infoc=obj.m_infoc; - m_dg=obj.m_dg; - m_dgm=obj.m_dgm; - m_dginit=obj.m_dginit; - m_dgtest=obj.m_dgtest; - m_dgx=obj.m_dgx; - m_dgxm=obj.m_dgxm; - m_dgy=obj.m_dgy; - m_dgym=obj.m_dgym; - m_finit=obj.m_finit; - m_ftest1=obj.m_ftest1; - m_fm=obj.m_fm; - m_fx=obj.m_fx; - m_fxm=obj.m_fxm; - m_fy=obj.m_fy; - m_fym=obj.m_fym; - m_stx=obj.m_stx; - m_sty=obj.m_sty; - m_stmin=obj.m_stmin; - m_stmax=obj.m_stmax; - m_width=obj.m_width; - m_width1=obj.m_width1; - m_xtrapf=obj.m_xtrapf; - } -//+------------------------------------------------------------------+ -//| Auxiliary class for CLinMin | -//+------------------------------------------------------------------+ -class CArmijoState - { -public: - bool m_needf; - double m_x[]; - double m_f; - int m_n; - double m_xbase[]; - double m_s[]; - double m_stplen; - double m_fcur; - double m_stpmax; - int m_fmax; - int m_nfev; - int m_info; - RCommState m_rstate; - //--- constructor, destructor - CArmijoState(void); - ~CArmijoState(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CArmijoState::CArmijoState(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CArmijoState::~CArmijoState(void) - { - - } -//+------------------------------------------------------------------+ -//| Minimization of linear forms | -//+------------------------------------------------------------------+ -class CLinMin - { -private: - //--- private methods - static void MCStep(double &stx,double &fx,double &dx,double &sty,double &fy,double &dy,double &stp,double fp,double dp,bool &m_brackt,double stmin,double stmax,int &info); - //--- auxiliary functions for ArmijoIteration - static void Func_lbl_rcomm(CArmijoState &state,int n,double v); - static bool Func_lbl_6(CArmijoState &state,int &n,double &v); - static bool Func_lbl_10(CArmijoState &state,int &n,double &v); -public: - //--- class constants - static const double m_ftol; - static const double m_xtol; - static const int m_maxfev; - static const double m_stpmin; - static const double m_defstpmax; - static const double m_armijofactor; - //--- constructor, destructor - CLinMin(void); - ~CLinMin(void); - //--- public methods - static void LinMinNormalized(double &d[],double &stp,const int n); - static void MCSrch(const int n,double &x[],double &f,double &g[],double &s[],double &stp,double stpmax,double gtol,int &info,int &nfev,double &wa[],CLinMinState &state,int &stage); - static void ArmijoCreate(const int n,double &x[],const double f,double &s[],const double stp,const double stpmax,const int ffmax,CArmijoState &state); - static void ArmijoResults(CArmijoState &state,int &info,double &stp,double &f); - static bool ArmijoIteration(CArmijoState &state); - }; -//+------------------------------------------------------------------+ -//| Initialize constants | -//+------------------------------------------------------------------+ -const double CLinMin::m_ftol=0.001; -const double CLinMin::m_xtol=100*CMath::m_machineepsilon; -const int CLinMin::m_maxfev=20; -const double CLinMin::m_stpmin=1.0E-50; -const double CLinMin::m_defstpmax=1.0E+50; -const double CLinMin::m_armijofactor=1.3; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CLinMin::CLinMin(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CLinMin::~CLinMin(void) - { - - } -//+------------------------------------------------------------------+ -//| Normalizes direction/step pair: makes |D|=1,scales Stp. | -//| If |D|=0,it returns,leavind D/Stp unchanged. | -//+------------------------------------------------------------------+ -static void CLinMin::LinMinNormalized(double &d[],double &stp,const int n) - { -//--- create variables - double mx=0; - double s=0; - int i=0; - int i_=0; -//--- first, scale D to avoid underflow/overflow durng squaring - mx=0; - for(i=0;i<=n-1;i++) - mx=MathMax(mx,MathAbs(d[i])); -//--- check - if(mx==0.0) - return; - s=1/mx; - for(i_=0;i_<=n-1;i_++) - d[i_]=s*d[i_]; - stp=stp/s; -//--- normalize D - s=0.0; - for(i_=0;i_<=n-1;i_++) - s+=d[i_]*d[i_]; - s=1/MathSqrt(s); - for(i_=0;i_<=n-1;i_++) - d[i_]=s*d[i_]; - stp=stp/s; - } -//+------------------------------------------------------------------+ -//| The purpose of MCSrch is to find a step which satisfies a | -//| sufficient decrease condition and a curvature condition. | -//| At each stage the subroutine updates an interval of uncertainty | -//| with endpoints stx and sty. The interval of uncertainty is | -//| initially chosen so that it contains a minimizer of the modified | -//| function | -//| f(x+stp*s) - f(x) - ftol*stp*(gradf(x)'s). | -//| If a step is obtained for which the modified function has a | -//| nonpositive function value and nonnegative derivative, then the | -//| interval of uncertainty is chosen so that it contains a minimizer| -//| of f(x+stp*s). | -//| The algorithm is designed to find a step which satisfies the | -//| sufficient decrease condition | -//| f(x+stp*s) .le. f(x) + ftol*stp*(gradf(x)'s), | -//| and the curvature condition | -//| abs(gradf(x+stp*s)'s)) .le. gtol*abs(gradf(x)'s). | -//| If ftol is less than gtol and if, for example, the function is | -//| bounded below, then there is always a step which satisfies both | -//| conditions. If no step can be found which satisfies both | -//| conditions, then the algorithm usually stops when rounding errors| -//| prevent further progress. In this case stp only satisfies the | -//| sufficient decrease condition. | -//| :::::::::::::important notes::::::::::::: | -//| note 1: | -//| This routine guarantees that it will stop at the last point | -//| where function value was calculated. It won't make several | -//| additional function evaluations after finding good point. So if | -//| you store function evaluations requested by this routine, you can| -//| be sure that last one is the point where we've stopped. | -//| NOTE 2: | -//| when 0stpmax) - stp=stpmax; -//--- Main cycle - while(true) - { - //--- check - if(stage==0) - { - //--- NEXT - stage=2; - continue; - } - //--- check - if(stage==2) - { - state.m_infoc=1; - info=0; - //--- check the input parameters for errors. - if(stpmax0.0) - { - info=5; - stp=0.0; - //--- exit the function - return; - } - //--- check - if(n<=0 || stp<=0.0 || m_ftol<0.0 || gtol=0.0) - { - stage=0; - return; - } - //--- initialize local variables. - state.m_brackt=false; - state.m_stage1=true; - nfev=0; - state.m_finit=f; - state.m_dgtest=m_ftol*state.m_dginit; - state.m_width=stpmax-m_stpmin; - state.m_width1=state.m_width/p5; - for(i_=0;i_<=n-1;i_++) - wa[i_]=x[i_]; - //--- the variables stx,fx,dgx contain the values of the step, - //--- function,and directional derivative at the best step. - //--- the variables sty,fy,dgy contain the value of the step, - //--- function,and derivative at the other endpoint of - //--- the interval of uncertainty. - //--- the variables stp,f,dg contain the values of the step, - //--- function,and derivative at the current step. - state.m_stx=0; - state.m_fx=state.m_finit; - state.m_dgx=state.m_dginit; - state.m_sty=0; - state.m_fy=state.m_finit; - state.m_dgy=state.m_dginit; - //--- next - stage=3; - continue; - } - //--- check - if(stage==3) - { - //--- start of iteration. - //--- set the minimum and maximum steps to correspond - //--- to the present interval of uncertainty. - if(state.m_brackt) - { - //--- check - if(state.m_stxstpmax) - stp=stpmax; - //--- check - if(stp=state.m_stmax)) || nfev>=m_maxfev-1 || state.m_infoc==0 || - (state.m_brackt && state.m_stmax-state.m_stmin<=m_xtol*state.m_stmax)) - { - stp=state.m_stx; - } - //--- evaluate the function and gradient at stp - //--- and compute the directional derivative. - for(i_=0;i_<=n-1;i_++) - x[i_]=wa[i_]; - for(i_=0;i_<=n-1;i_++) - x[i_]=x[i_]+stp*s[i_]; - //--- NEXT - stage=4; - return; - } - //--- check - if(stage==4) - { - info=0; - nfev=nfev+1; - v=0.0; - for(i_=0;i_<=n-1;i_++) - v+=g[i_]*s[i_]; - state.m_dg=v; - state.m_ftest1=state.m_finit+stp*state.m_dgtest; - //--- test for convergence. - if((state.m_brackt && (stp<=state.m_stmin || stp>=state.m_stmax)) || state.m_infoc==0) - info=6; - //--- check - if((stp==stpmax && f<=state.m_ftest1) && state.m_dg<=state.m_dgtest) - info=5; - //--- check - if(stp==m_stpmin && (f>state.m_ftest1 || state.m_dg>=state.m_dgtest)) - info=4; - //--- check - if(nfev>=m_maxfev) - info=3; - //--- check - if(state.m_brackt && state.m_stmax-state.m_stmin<=m_xtol*state.m_stmax) - info=2; - //--- check - if(f<=state.m_ftest1 && MathAbs(state.m_dg)<=-(gtol*state.m_dginit)) - info=1; - //--- check for termination. - if(info!=0) - { - stage=0; - return; - } - //--- in the first stage we seek a step for which the modified - //--- function has a nonpositive value and nonnegative derivative. - if((state.m_stage1 && f<=state.m_ftest1) && state.m_dg>=MathMin(m_ftol,gtol)*state.m_dginit) - state.m_stage1=false; - //--- a modified function is used to predict the step only if - //--- we have not obtained a step for which the modified - //--- function has a nonpositive function value and nonnegative - //--- derivative,and if a lower function value has been - //--- obtained but the decrease is not sufficient. - if((state.m_stage1 && f<=state.m_fx) && f>state.m_ftest1) - { - //--- define the modified function and derivative values. - state.m_fm=f-stp*state.m_dgtest; - state.m_fxm=state.m_fx-state.m_stx*state.m_dgtest; - state.m_fym=state.m_fy-state.m_sty*state.m_dgtest; - state.m_dgm=state.m_dg-state.m_dgtest; - state.m_dgxm=state.m_dgx-state.m_dgtest; - state.m_dgym=state.m_dgy-state.m_dgtest; - //--- call cstep to update the interval of uncertainty - //--- and to compute the new step. - MCStep(state.m_stx,state.m_fxm,state.m_dgxm,state.m_sty,state.m_fym,state.m_dgym,stp,state.m_fm,state.m_dgm,state.m_brackt,state.m_stmin,state.m_stmax,state.m_infoc); - //--- reset the function and gradient values for f. - state.m_fx=state.m_fxm+state.m_stx*state.m_dgtest; - state.m_fy=state.m_fym+state.m_sty*state.m_dgtest; - state.m_dgx=state.m_dgxm+state.m_dgtest; - state.m_dgy=state.m_dgym+state.m_dgtest; - } - else - { - //--- call mcstep to update the interval of uncertainty - //--- and to compute the new step. - MCStep(state.m_stx,state.m_fx,state.m_dgx,state.m_sty,state.m_fy,state.m_dgy,stp,f,state.m_dg,state.m_brackt,state.m_stmin,state.m_stmax,state.m_infoc); - } - //--- force a sufficient decrease in the size of the - //--- interval of uncertainty. - if(state.m_brackt) - { - //--- check - if(MathAbs(state.m_sty-state.m_stx)>=p66*state.m_width1) - stp=state.m_stx+p5*(state.m_sty-state.m_stx); - state.m_width1=state.m_width; - state.m_width=MathAbs(state.m_sty-state.m_stx); - } - //--- next. - stage=3; - continue; - } - } - } -//+------------------------------------------------------------------+ -//| These functions perform Armijo line search using at most FMAX | -//| function evaluations. It doesn't enforce some kind of | -//| "sufficient decrease" criterion - it just tries different Armijo | -//| steps and returns optimum found so far. | -//| Optimization is done using F-rcomm interface: | -//| * ArmijoCreate initializes State structure | -//| (reusing previously allocated buffers) | -//| * ArmijoIteration is subsequently called | -//| * ArmijoResults returns results | -//| INPUT PARAMETERS: | -//| N - problem size | -//| X - array[N], starting point | -//| F - F(X+S*STP) | -//| S - step direction, S>0 | -//| STP - step length | -//| STPMAX - maximum value for STP or zero (if no limit is | -//| imposed) | -//| FMAX - maximum number of function evaluations | -//| State - optimization state | -//+------------------------------------------------------------------+ -static void CLinMin::ArmijoCreate(const int n,double &x[],const double f, - double &s[],const double stp,const double stpmax, - const int ffmax,CArmijoState &state) - { -//--- create a variable - int i_=0; -//--- check - if(CAp::Len(state.m_x)=MathMax(stx,sty))) || dx*(stp-stx)>=0.0) || stmaxfx) - { - //--- initialization - info=1; - bound=true; - theta=3*(fx-fp)/(stp-stx)+dx+dp; - s=MathMax(MathAbs(theta),MathMax(MathAbs(dx),MathAbs(dp))); - gamma=s*MathSqrt(CMath::Sqr(theta/s)-dx/s*(dp/s)); - //--- check - if(stpstx) - gamma=-gamma; - //--- initialization - p=gamma-dp+theta; - q=gamma-dp+gamma+dx; - r=p/q; - stpc=stp+r*(stx-stp); - stpq=stp+dp/(dp-dx)*(stx-stp); - //--- check - if(MathAbs(stpc-stp)>MathAbs(stpq-stp)) - stpf=stpc; - else - stpf=stpq; - m_brackt=true; - } - else - { - //--- check - if(MathAbs(dp)stx) - gamma=-gamma; - p=gamma-dp+theta; - q=gamma+(dx-dp)+gamma; - r=p/q; - //--- check - if(r<0.0 && (double)(gamma)!=0.0) - stpc=stp+r*(stx-stp); - else - { - //--- check - if(stp>stx) - stpc=stmax; - else - stpc=stmin; - } - stpq=stp+dp/(dp-dx)*(stx-stp); - //--- check - if(m_brackt) - { - //--- check - if(MathAbs(stp-stpc)MathAbs(stp-stpq)) - stpf=stpc; - else - stpf=stpq; - } - } - else - { - //--- fourth case. a lower function value,derivatives of the - //--- same sign, and the magnitude of the derivative does - //--- not decrease. if the minimum is not bracketed, the step - //--- is either stpmin or stpmax, else the cubic step is taken. - info=4; - bound=false; - //--- check - if(m_brackt) - { - theta=3*(fp-fy)/(sty-stp)+dy+dp; - s=MathMax(MathAbs(theta),MathMax(MathAbs(dy),MathAbs(dp))); - gamma=s*MathSqrt(CMath::Sqr(theta/s)-dy/s*(dp/s)); - //--- check - if(stp>sty) - gamma=-gamma; - //--- initialization - p=gamma-dp+theta; - q=gamma-dp+gamma+dy; - r=p/q; - stpc=stp+r*(sty-stp); - stpf=stpc; - } - else - { - //--- check - if(stp>stx) - stpf=stmax; - else - stpf=stmin; - } - } - } - } -//--- update the interval of uncertainty. this update does not -//--- depend on the new step or the case analysis above. - if(fp>fx) - { - //--- set value - sty=stp; - fy=fp; - dy=dp; - } - else - { - //--- check - if(sgnd<0.0) - { - //--- set value - sty=stx; - fy=fx; - dy=dx; - } - //--- set value - stx=stp; - fx=fp; - dx=dp; - } -//--- compute the new step and safeguard it. - stpf=MathMin(stmax,stpf); - stpf=MathMax(stmin,stpf); - stp=stpf; -//--- check - if(m_brackt && bound) - { - //--- check - if(sty>stx) - stp=MathMin(stx+0.66*(sty-stx),stp); - else - stp=MathMax(stx+0.66*(sty-stx),stp); - } - } -//+------------------------------------------------------------------+ -//| This is rcomm-based search function | -//+------------------------------------------------------------------+ -static bool CLinMin::ArmijoIteration(CArmijoState &state) - { -//--- create variables - double v=0; - int n=0; - int i_=0; -//--- This code initializes locals by: -//--- * random values determined during code -//--- generation - on first subroutine call -//--- * values from previous call - on subsequent calls - if(state.m_rstate.stage>=0) - { - //--- initialization - n=state.m_rstate.ia[0]; - v=state.m_rstate.ra[0]; - } - else - { - //--- initialization - n=-983; - v=-989; - } -//--- check - if(state.m_rstate.stage==0) - { - state.m_nfev=state.m_nfev+1; - //--- check - if(state.m_f>=state.m_fcur) - { - //--- Decrease length - v=state.m_stplen/m_armijofactor; - //--- copy - for(i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xbase[i_]; - for(i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_x[i_]+v*state.m_s[i_]; - state.m_rstate.stage=2; - //--- Saving state - Func_lbl_rcomm(state,n,v); - //--- return result - return(true); - } - //--- change values - state.m_stplen=v; - state.m_fcur=state.m_f; - //--- function call, return result - return(Func_lbl_6(state,n,v)); - } -//--- check - if(state.m_rstate.stage==1) - { - state.m_nfev=state.m_nfev+1; - //--- make decision - if(state.m_f=state.m_fcur) - { - //--- Nothing to be done - state.m_info=1; - //--- return result - return(false); - } - //--- change values - state.m_stplen=state.m_stplen/m_armijofactor; - state.m_fcur=state.m_f; - //--- function call, return result - return(Func_lbl_10(state,n,v)); - } -//--- check - if(state.m_rstate.stage==3) - { - state.m_nfev=state.m_nfev+1; - //--- make decision - if(state.m_fstate.m_stpmax && state.m_stpmax!=0.0) - state.m_stplen=state.m_stpmax; -//--- Increase length - v=state.m_stplen*m_armijofactor; -//--- check - if(v>state.m_stpmax && state.m_stpmax!=0.0) - v=state.m_stpmax; -//--- copy - for(i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xbase[i_]; - for(i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_x[i_]+v*state.m_s[i_]; - state.m_rstate.stage=0; -//--- Saving state - Func_lbl_rcomm(state,n,v); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for ArmijoIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static void CLinMin::Func_lbl_rcomm(CArmijoState &state,int n,double v) - { -//--- save - state.m_rstate.ia[0]=n; - state.m_rstate.ra[0]=v; - } -//+------------------------------------------------------------------+ -//| Auxiliary function for ArmijoIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CLinMin::Func_lbl_6(CArmijoState &state,int &n,double &v) - { -//--- test stopping conditions - if(state.m_nfev>=state.m_fmax) - { - state.m_info=3; - //--- return result - return(false); - } -//--- check - if(state.m_stplen>=state.m_stpmax) - { - state.m_info=5; - //--- return result - return(false); - } -//--- evaluate F - v=state.m_stplen*m_armijofactor; -//--- check - if(v>state.m_stpmax && state.m_stpmax!=0.0) - v=state.m_stpmax; -//--- copy - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xbase[i_]; - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_x[i_]+v*state.m_s[i_]; - state.m_rstate.stage=1; -//--- Saving state - Func_lbl_rcomm(state,n,v); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for ArmijoIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CLinMin::Func_lbl_10(CArmijoState &state,int &n,double &v) - { -//--- test stopping conditions - if(state.m_nfev>=state.m_fmax) - { - state.m_info=3; - //--- return result - return(false); - } -//--- check - if(state.m_stplen<=m_stpmin) - { - state.m_info=4; - //--- return result - return(false); - } -//--- evaluate F - v=state.m_stplen/m_armijofactor; -//--- copy - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xbase[i_]; - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_x[i_]+v*state.m_s[i_]; - state.m_rstate.stage=3; -//--- Saving state - Func_lbl_rcomm(state,n,v); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary functions for other classes | -//+------------------------------------------------------------------+ -class COptServ - { -public: - //--- constructor, destructor - COptServ(void); - ~COptServ(void); - //--- methods - static void TrimPrepare(const double f,double &threshold); - static void TrimFunction(double &f,double &g[],const int n,const double threshold); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -COptServ::COptServ(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -COptServ::~COptServ(void) - { - - } -//+------------------------------------------------------------------+ -//| This subroutine is used to prepare threshold value which will be | -//| used for trimming of the target function (see comments on | -//| TrimFunction() for more information). | -//| This function accepts only one parameter: function value at the | -//| starting point. It returns threshold which will be used for | -//| trimming. | -//+------------------------------------------------------------------+ -static void COptServ::TrimPrepare(const double f,double &threshold) - { -//--- calculation - threshold=10*(MathAbs(f)+1); - } -//+------------------------------------------------------------------+ -//| This subroutine is used to "trim" target function, i.e. to do | -//| following transformation: | -//| { {F,G} if F=Threshold | -//| Such transformation allows us to solve problems with | -//| singularities by redefining function in such way that it becomes | -//| bounded from above. | -//+------------------------------------------------------------------+ -static void COptServ::TrimFunction(double &f,double &g[],const int n, - const double threshold) - { -//--- create a variable - int i=0; -//--- check - if(f>=threshold) - { - f=threshold; - for(i=0;i<=n-1;i++) - g[i]=0.0; - } - } -//+------------------------------------------------------------------+ -//| Auxiliary class for CFtBase | -//+------------------------------------------------------------------+ -class CFtPlan - { -public: - //--- arrays - int m_plan[]; - double m_precomputed[]; - double m_tmpbuf[]; - double m_stackbuf[]; - //--- constructor, destructor - CFtPlan(void); - ~CFtPlan(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CFtPlan::CFtPlan(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CFtPlan::~CFtPlan(void) - { - - } -//+------------------------------------------------------------------+ -//| Generation FFT, FHT plans | -//+------------------------------------------------------------------+ -class CFtBase - { -private: - //--- private methods - static void FtBaseGeneratePlanRec(const int n,int tasktype,CFtPlan &plan,int &plansize,int &precomputedsize,int &planarraysize,int &tmpmemsize,int &stackmemsize,int stackptr); - static void FtBasePrecomputePlanRec(CFtPlan &plan,const int entryoffset,const int stackptr); - static void FFtTwCalc(double &a[],const int aoffset,const int n1,const int n2); - static void InternalComplexLinTranspose(double &a[],const int m,const int n,const int astart,double &buf[]); - static void InternalRealLinTranspose(double &a[],const int m,const int n,const int astart,double &buf[]); - static void FFtICLTRec(double &a[],const int astart,const int astride,double &b[],const int bstart,const int bstride,const int m,const int n); - static void FFtIRLTRec(double &a[],const int astart,const int astride,double &b[],const int bstart,const int bstride,const int m,const int n); - static void FtBaseFindSmoothRec(const int n,const int seed,const int leastfactor,int &best); - static void FFtArrayResize(int &a[],int &asize,const int newasize); - static void ReFFHt(double &a[],const int n,const int offs); -public: - //--- class constants - static const int m_ftbaseplanentrysize; - static const int m_ftbasecffttask; - static const int m_ftbaserfhttask; - static const int m_ftbaserffttask; - static const int m_fftcooleytukeyplan; - static const int m_fftbluesteinplan; - static const int m_fftcodeletplan; - static const int m_fhtcooleytukeyplan; - static const int m_fhtcodeletplan; - static const int m_fftrealcooleytukeyplan; - static const int m_fftemptyplan; - static const int m_fhtn2plan; - static const int m_ftbaseupdatetw; - static const int m_ftbasecodeletrecommended; - static const double m_ftbaseinefficiencyfactor; - static const int m_ftbasemaxsmoothfactor; - //--- constructor, destructor - CFtBase(void); - ~CFtBase(void); - //--- public methods - static void FtBaseGenerateComplexFFtPlan(const int n,CFtPlan &plan); - static void FtBaseGenerateRealFFtPlan(const int n,CFtPlan &plan); - static void FtBaseGenerateRealFHtPlan(const int n,CFtPlan &plan); - static void FtBaseExecutePlan(double &a[],const int aoffset,const int n,CFtPlan &plan); - static void FtBaseExecutePlanRec(double &a[],const int aoffset,CFtPlan &plan,const int entryoffset,const int stackptr); - static void FtBaseFactorize(const int n,const int tasktype,int &n1,int &n2); - static bool FtBaseIsSmooth(int n); - static int FtBaseFindSmooth(const int n); - static int FtBaseFindSmoothEven(const int n); - static double FtBaseGetFlopEstimate(const int n); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CFtBase::CFtBase(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CFtBase::~CFtBase(void) - { - - } -//+------------------------------------------------------------------+ -//| Initialize constants | -//+------------------------------------------------------------------+ -const int CFtBase::m_ftbaseplanentrysize=8; -const int CFtBase::m_ftbasecffttask=0; -const int CFtBase::m_ftbaserfhttask=1; -const int CFtBase::m_ftbaserffttask=2; -const int CFtBase::m_fftcooleytukeyplan=0; -const int CFtBase::m_fftbluesteinplan=1; -const int CFtBase::m_fftcodeletplan=2; -const int CFtBase::m_fhtcooleytukeyplan=3; -const int CFtBase::m_fhtcodeletplan=4; -const int CFtBase::m_fftrealcooleytukeyplan=5; -const int CFtBase::m_fftemptyplan=6; -const int CFtBase::m_fhtn2plan=999; -const int CFtBase::m_ftbaseupdatetw=4; -const int CFtBase::m_ftbasecodeletrecommended=5; -const double CFtBase::m_ftbaseinefficiencyfactor=1.3; -const int CFtBase::m_ftbasemaxsmoothfactor=5; -//+------------------------------------------------------------------+ -//| This subroutine generates FFT plan - a decomposition of a | -//| N-length FFT to the more simpler operations. Plan consists of the| -//| root entry and the child entries. | -//| Subroutine parameters: | -//| N task size | -//| Output parameters: | -//| Plan plan | -//+------------------------------------------------------------------+ -static void CFtBase::FtBaseGenerateComplexFFtPlan(const int n,CFtPlan &plan) - { -//--- create variables - int planarraysize=0; - int plansize=0; - int precomputedsize=0; - int tmpmemsize=0; - int stackmemsize=0; - int stackptr=0; -//--- initialization - planarraysize=1; - plansize=0; - precomputedsize=0; - stackmemsize=0; - stackptr=0; - tmpmemsize=2*n; -//--- allocation - ArrayResizeAL(plan.m_plan,planarraysize); -//--- function call - FtBaseGeneratePlanRec(n,m_ftbasecffttask,plan,plansize,precomputedsize,planarraysize,tmpmemsize,stackmemsize,stackptr); -//--- check - if(!CAp::Assert(stackptr==0,__FUNCTION__+": stack ptr!")) - return; -//--- allocation - ArrayResizeAL(plan.m_stackbuf,(int)MathMax(stackmemsize,1)); -//--- allocation - ArrayResizeAL(plan.m_tmpbuf,(int)MathMax(tmpmemsize,1)); -//--- allocation - ArrayResizeAL(plan.m_precomputed,(int)MathMax(precomputedsize,1)); - stackptr=0; -//--- function call - FtBasePrecomputePlanRec(plan,0,stackptr); -//--- check - if(!CAp::Assert(stackptr==0,__FUNCTION__+": stack ptr!")) - return; - } -//+------------------------------------------------------------------+ -//| Generates real FFT plan | -//+------------------------------------------------------------------+ -static void CFtBase::FtBaseGenerateRealFFtPlan(const int n,CFtPlan &plan) - { -//--- create variables - int planarraysize=0; - int plansize=0; - int precomputedsize=0; - int tmpmemsize=0; - int stackmemsize=0; - int stackptr=0; -//--- initialization - planarraysize=1; - plansize=0; - precomputedsize=0; - stackmemsize=0; - stackptr=0; - tmpmemsize=2*n; -//--- allocation - ArrayResizeAL(plan.m_plan,planarraysize); -//--- function call - FtBaseGeneratePlanRec(n,m_ftbaserffttask,plan,plansize,precomputedsize,planarraysize,tmpmemsize,stackmemsize,stackptr); -//--- check - if(!CAp::Assert(stackptr==0,__FUNCTION__+": stack ptr!")) - return; -//--- allocation - ArrayResizeAL(plan.m_stackbuf,(int)MathMax(stackmemsize,1)); -//--- allocation - ArrayResizeAL(plan.m_tmpbuf,(int)MathMax(tmpmemsize,1)); -//--- allocation - ArrayResizeAL(plan.m_precomputed,(int)MathMax(precomputedsize,1)); - stackptr=0; -//--- function call - FtBasePrecomputePlanRec(plan,0,stackptr); -//--- check - if(!CAp::Assert(stackptr==0,__FUNCTION__+": stack ptr!")) - return; - } -//+------------------------------------------------------------------+ -//| Generates real FHT plan | -//+------------------------------------------------------------------+ -static void CFtBase::FtBaseGenerateRealFHtPlan(const int n,CFtPlan &plan) - { -//--- create variables - int planarraysize=0; - int plansize=0; - int precomputedsize=0; - int tmpmemsize=0; - int stackmemsize=0; - int stackptr=0; -//--- initialization - planarraysize=1; - plansize=0; - precomputedsize=0; - stackmemsize=0; - stackptr=0; - tmpmemsize=n; -//--- allocation - ArrayResizeAL(plan.m_plan,planarraysize); -//--- function call - FtBaseGeneratePlanRec(n,m_ftbaserfhttask,plan,plansize,precomputedsize,planarraysize,tmpmemsize,stackmemsize,stackptr); -//--- check - if(!CAp::Assert(stackptr==0,__FUNCTION__+": stack ptr!")) - return; -//--- allocation - ArrayResizeAL(plan.m_stackbuf,(int)MathMax(stackmemsize,1)); -//--- allocation - ArrayResizeAL(plan.m_tmpbuf,(int)MathMax(tmpmemsize,1)); -//--- allocation - ArrayResizeAL(plan.m_precomputed,(int)MathMax(precomputedsize,1)); - stackptr=0; -//--- function call - FtBasePrecomputePlanRec(plan,0,stackptr); -//--- check - if(!CAp::Assert(stackptr==0,__FUNCTION__+": stack ptr!")) - return; - } -//+------------------------------------------------------------------+ -//| This subroutine executes FFT/FHT plan. | -//| If Plan is a: | -//| * complex FFT plan - sizeof(A)=2*N, | -//| A contains interleaved real/imaginary | -//| values | -//| * real FFT plan - sizeof(A)=2*N, | -//| A contains real values interleaved with | -//| zeros | -//| * real FHT plan - sizeof(A)=2*N, | -//| A contains real values interleaved with | -//| zeros | -//+------------------------------------------------------------------+ -static void CFtBase::FtBaseExecutePlan(double &a[],const int aoffset, - const int n,CFtPlan &plan) - { -//--- create a variable - int stackptr=0; -//--- function call - FtBaseExecutePlanRec(a,aoffset,plan,0,stackptr); - } -//+------------------------------------------------------------------+ -//| Recurrent subroutine for the FTBaseExecutePlan | -//| Parameters: | -//| A FFT'ed array | -//| AOffset offset of the FFT'ed part (distance is measured | -//| in doubles) | -//+------------------------------------------------------------------+ -static void CFtBase::FtBaseExecutePlanRec(double &a[],const int aoffset, - CFtPlan &plan,const int entryoffset, - const int stackptr) - { -//--- create variables - int i=0; - int j=0; - int k=0; - int n1=0; - int n2=0; - int n=0; - int m=0; - int offs=0; - int offs1=0; - int offs2=0; - int offsa=0; - int offsb=0; - int offsp=0; - double hk=0; - double hnk=0; - double x=0; - double y=0; - double bx=0; - double by=0; - double emptyarray[]; - double a0x=0; - double a0y=0; - double a1x=0; - double a1y=0; - double a2x=0; - double a2y=0; - double a3x=0; - double a3y=0; - double v0=0; - double v1=0; - double v2=0; - double v3=0; - double t1x=0; - double t1y=0; - double t2x=0; - double t2y=0; - double t3x=0; - double t3y=0; - double t4x=0; - double t4y=0; - double t5x=0; - double t5y=0; - double m1x=0; - double m1y=0; - double m2x=0; - double m2y=0; - double m3x=0; - double m3y=0; - double m4x=0; - double m4y=0; - double m5x=0; - double m5y=0; - double s1x=0; - double s1y=0; - double s2x=0; - double s2y=0; - double s3x=0; - double s3y=0; - double s4x=0; - double s4y=0; - double s5x=0; - double s5y=0; - double c1=0; - double c2=0; - double c3=0; - double c4=0; - double c5=0; - double tmp[]; - int i_=0; - int i1_=0; -//--- check - if(plan.m_plan[entryoffset+3]==m_fftemptyplan) - return; -//--- check - if(plan.m_plan[entryoffset+3]==m_fftcooleytukeyplan) - { - //--- Cooley-Tukey plan - //--- * transposition - //--- * row-wise FFT - //--- * twiddle factors: - //--- - TwBase is a basis twiddle factor for I=1,J=1 - //--- - TwRow is a twiddle factor for a second element in a row (J=1) - //--- - Tw is a twiddle factor for a current element - //--- * transposition again - //--- * row-wise FFT again - n1=plan.m_plan[entryoffset+1]; - n2=plan.m_plan[entryoffset+2]; - //--- function call - InternalComplexLinTranspose(a,n1,n2,aoffset,plan.m_tmpbuf); - for(i=0;i<=n2-1;i++) - { - //--- function call - FtBaseExecutePlanRec(a,aoffset+i*n1*2,plan,plan.m_plan[entryoffset+5],stackptr); - } - //--- function call - FFtTwCalc(a,aoffset,n1,n2); - //--- function call - InternalComplexLinTranspose(a,n2,n1,aoffset,plan.m_tmpbuf); - for(i=0;i<=n1-1;i++) - { - //--- function call - FtBaseExecutePlanRec(a,aoffset+i*n2*2,plan,plan.m_plan[entryoffset+6],stackptr); - } - //--- function call - InternalComplexLinTranspose(a,n1,n2,aoffset,plan.m_tmpbuf); - //--- exit the function - return; - } -//--- check - if(plan.m_plan[entryoffset+3]==m_fftrealcooleytukeyplan) - { - //--- Cooley-Tukey plan - //--- * transposition - //--- * row-wise FFT - //--- * twiddle factors: - //--- - TwBase is a basis twiddle factor for I=1,J=1 - //--- - TwRow is a twiddle factor for a second element in a row (J=1) - //--- - Tw is a twiddle factor for a current element - //--- * transposition again - //--- * row-wise FFT again - n1=plan.m_plan[entryoffset+1]; - n2=plan.m_plan[entryoffset+2]; - //--- function call - InternalComplexLinTranspose(a,n2,n1,aoffset,plan.m_tmpbuf); - for(i=0;i<=n1/2-1;i++) - { - //--- pack two adjacent smaller real FFT's together, - //--- make one complex FFT, - //--- unpack result - offs=aoffset+2*i*n2*2; - for(k=0;k<=n2-1;k++) - a[offs+2*k+1]=a[offs+2*n2+2*k+0]; - //--- function call - FtBaseExecutePlanRec(a,offs,plan,plan.m_plan[entryoffset+6],stackptr); - //--- change values - plan.m_tmpbuf[0]=a[offs+0]; - plan.m_tmpbuf[1]=0; - plan.m_tmpbuf[2*n2+0]=a[offs+1]; - plan.m_tmpbuf[2*n2+1]=0; - for(k=1;k<=n2-1;k++) - { - //--- change values - offs1=2*k; - offs2=2*n2+2*k; - hk=a[offs+2*k+0]; - hnk=a[offs+2*(n2-k)+0]; - plan.m_tmpbuf[offs1+0]=0.5*(hk+hnk); - plan.m_tmpbuf[offs2+1]=-(0.5*(hk-hnk)); - hk=a[offs+2*k+1]; - hnk=a[offs+2*(n2-k)+1]; - plan.m_tmpbuf[offs2+0]=0.5*(hk+hnk); - plan.m_tmpbuf[offs1+1]=0.5*(hk-hnk); - } - i1_=-offs; - for(i_=offs;i_<=offs+2*n2*2-1;i_++) - a[i_]=plan.m_tmpbuf[i_+i1_]; - } - //--- check - if(n1%2!=0) - { - //--- function call - FtBaseExecutePlanRec(a,aoffset+(n1-1)*n2*2,plan,plan.m_plan[entryoffset+6],stackptr); - } - //--- function call - FFtTwCalc(a,aoffset,n2,n1); - //--- function call - InternalComplexLinTranspose(a,n1,n2,aoffset,plan.m_tmpbuf); - for(i=0;i<=n2-1;i++) - { - //--- function call - FtBaseExecutePlanRec(a,aoffset+i*n1*2,plan,plan.m_plan[entryoffset+5],stackptr); - } - //--- function call - InternalComplexLinTranspose(a,n2,n1,aoffset,plan.m_tmpbuf); - //--- exit the function - return; - } -//--- check - if(plan.m_plan[entryoffset+3]==m_fhtcooleytukeyplan) - { - //--- Cooley-Tukey FHT plan: - //--- * transpose \ - //--- * smaller FHT's | - //--- * pre-process | - //--- * multiply by twiddle factors | corresponds to multiplication by H1 - //--- * post-process | - //--- * transpose again / - //--- * multiply by H2 (smaller FHT's) - //--- * final transposition - //--- For more details see Vitezslav Vesely,"Fast algorithms - //--- of Fourier and Hartley transform and their implementation in MATLAB", - //--- page 31. - n1=plan.m_plan[entryoffset+1]; - n2=plan.m_plan[entryoffset+2]; - n=n1*n2; - //--- function call - InternalRealLinTranspose(a,n1,n2,aoffset,plan.m_tmpbuf); - for(i=0;i<=n2-1;i++) - { - //--- function call - FtBaseExecutePlanRec(a,aoffset+i*n1,plan,plan.m_plan[entryoffset+5],stackptr); - } - for(i=0;i<=n2-1;i++) - { - for(j=0;j<=n1-1;j++) - { - //--- change values - offsa=aoffset+i*n1; - hk=a[offsa+j]; - hnk=a[offsa+(n1-j)%n1]; - offs=2*(i*n1+j); - plan.m_tmpbuf[offs+0]=-(0.5*(hnk-hk)); - plan.m_tmpbuf[offs+1]=0.5*(hk+hnk); - } - } - //--- function call - FFtTwCalc(plan.m_tmpbuf,0,n1,n2); - for(j=0;j<=n1-1;j++) - a[aoffset+j]=plan.m_tmpbuf[2*j+0]+plan.m_tmpbuf[2*j+1]; - //--- check - if(n2%2==0) - { - offs=2*(n2/2)*n1; - offsa=aoffset+n2/2*n1; - for(j=0;j<=n1-1;j++) - a[offsa+j]=plan.m_tmpbuf[offs+2*j+0]+plan.m_tmpbuf[offs+2*j+1]; - } - for(i=1;i<=(n2+1)/2-1;i++) - { - //--- change values - offs=2*i*n1; - offs2=2*(n2-i)*n1; - offsa=aoffset+i*n1; - for(j=0;j<=n1-1;j++) - a[offsa+j]=plan.m_tmpbuf[offs+2*j+1]+plan.m_tmpbuf[offs2+2*j+0]; - offsa=aoffset+(n2-i)*n1; - for(j=0;j<=n1-1;j++) - a[offsa+j]=plan.m_tmpbuf[offs+2*j+0]+plan.m_tmpbuf[offs2+2*j+1]; - } - //--- function call - InternalRealLinTranspose(a,n2,n1,aoffset,plan.m_tmpbuf); - for(i=0;i<=n1-1;i++) - { - //--- function call - FtBaseExecutePlanRec(a,aoffset+i*n2,plan,plan.m_plan[entryoffset+6],stackptr); - } - //--- function call - InternalRealLinTranspose(a,n1,n2,aoffset,plan.m_tmpbuf); - //--- exit the function - return; - } -//--- check - if(plan.m_plan[entryoffset+3]==m_fhtn2plan) - { - //--- Cooley-Tukey FHT plan - n1=plan.m_plan[entryoffset+1]; - n2=plan.m_plan[entryoffset+2]; - n=n1*n2; - ReFFHt(a,n,aoffset); - //--- exit the function - return; - } -//--- check - if(plan.m_plan[entryoffset+3]==m_fftcodeletplan) - { - n1=plan.m_plan[entryoffset+1]; - n2=plan.m_plan[entryoffset+2]; - n=n1*n2; - //--- check - if(n==2) - { - //--- change values - a0x=a[aoffset+0]; - a0y=a[aoffset+1]; - a1x=a[aoffset+2]; - a1y=a[aoffset+3]; - v0=a0x+a1x; - v1=a0y+a1y; - v2=a0x-a1x; - v3=a0y-a1y; - a[aoffset+0]=v0; - a[aoffset+1]=v1; - a[aoffset+2]=v2; - a[aoffset+3]=v3; - //--- exit the function - return; - } - //--- check - if(n==3) - { - //--- change values - offs=plan.m_plan[entryoffset+7]; - c1=plan.m_precomputed[offs+0]; - c2=plan.m_precomputed[offs+1]; - a0x=a[aoffset+0]; - a0y=a[aoffset+1]; - a1x=a[aoffset+2]; - a1y=a[aoffset+3]; - a2x=a[aoffset+4]; - a2y=a[aoffset+5]; - t1x=a1x+a2x; - t1y=a1y+a2y; - a0x=a0x+t1x; - a0y=a0y+t1y; - m1x=c1*t1x; - m1y=c1*t1y; - m2x=c2*(a1y-a2y); - m2y=c2*(a2x-a1x); - s1x=a0x+m1x; - s1y=a0y+m1y; - a1x=s1x+m2x; - a1y=s1y+m2y; - a2x=s1x-m2x; - a2y=s1y-m2y; - a[aoffset+0]=a0x; - a[aoffset+1]=a0y; - a[aoffset+2]=a1x; - a[aoffset+3]=a1y; - a[aoffset+4]=a2x; - a[aoffset+5]=a2y; - //--- exit the function - return; - } - //--- check - if(n==4) - { - //--- change values - a0x=a[aoffset+0]; - a0y=a[aoffset+1]; - a1x=a[aoffset+2]; - a1y=a[aoffset+3]; - a2x=a[aoffset+4]; - a2y=a[aoffset+5]; - a3x=a[aoffset+6]; - a3y=a[aoffset+7]; - t1x=a0x+a2x; - t1y=a0y+a2y; - t2x=a1x+a3x; - t2y=a1y+a3y; - m2x=a0x-a2x; - m2y=a0y-a2y; - m3x=a1y-a3y; - m3y=a3x-a1x; - a[aoffset+0]=t1x+t2x; - a[aoffset+1]=t1y+t2y; - a[aoffset+4]=t1x-t2x; - a[aoffset+5]=t1y-t2y; - a[aoffset+2]=m2x+m3x; - a[aoffset+3]=m2y+m3y; - a[aoffset+6]=m2x-m3x; - a[aoffset+7]=m2y-m3y; - //--- exit the function - return; - } - //--- check - if(n==5) - { - //--- change values - offs=plan.m_plan[entryoffset+7]; - c1=plan.m_precomputed[offs+0]; - c2=plan.m_precomputed[offs+1]; - c3=plan.m_precomputed[offs+2]; - c4=plan.m_precomputed[offs+3]; - c5=plan.m_precomputed[offs+4]; - t1x=a[aoffset+2]+a[aoffset+8]; - t1y=a[aoffset+3]+a[aoffset+9]; - t2x=a[aoffset+4]+a[aoffset+6]; - t2y=a[aoffset+5]+a[aoffset+7]; - t3x=a[aoffset+2]-a[aoffset+8]; - t3y=a[aoffset+3]-a[aoffset+9]; - t4x=a[aoffset+6]-a[aoffset+4]; - t4y=a[aoffset+7]-a[aoffset+5]; - t5x=t1x+t2x; - t5y=t1y+t2y; - a[aoffset+0]=a[aoffset+0]+t5x; - a[aoffset+1]=a[aoffset+1]+t5y; - m1x=c1*t5x; - m1y=c1*t5y; - m2x=c2*(t1x-t2x); - m2y=c2*(t1y-t2y); - m3x=-(c3*(t3y+t4y)); - m3y=c3*(t3x+t4x); - m4x=-(c4*t4y); - m4y=c4*t4x; - m5x=-(c5*t3y); - m5y=c5*t3x; - s3x=m3x-m4x; - s3y=m3y-m4y; - s5x=m3x+m5x; - s5y=m3y+m5y; - s1x=a[aoffset+0]+m1x; - s1y=a[aoffset+1]+m1y; - s2x=s1x+m2x; - s2y=s1y+m2y; - s4x=s1x-m2x; - s4y=s1y-m2y; - a[aoffset+2]=s2x+s3x; - a[aoffset+3]=s2y+s3y; - a[aoffset+4]=s4x+s5x; - a[aoffset+5]=s4y+s5y; - a[aoffset+6]=s4x-s5x; - a[aoffset+7]=s4y-s5y; - a[aoffset+8]=s2x-s3x; - a[aoffset+9]=s2y-s3y; - //--- exit the function - return; - } - } -//--- check - if(plan.m_plan[entryoffset+3]==m_fhtcodeletplan) - { - //--- change values - n1=plan.m_plan[entryoffset+1]; - n2=plan.m_plan[entryoffset+2]; - n=n1*n2; - //--- check - if(n==2) - { - //--- change values - a0x=a[aoffset+0]; - a1x=a[aoffset+1]; - a[aoffset+0]=a0x+a1x; - a[aoffset+1]=a0x-a1x; - //--- exit the function - return; - } - //--- check - if(n==3) - { - //--- change values - offs=plan.m_plan[entryoffset+7]; - c1=plan.m_precomputed[offs+0]; - c2=plan.m_precomputed[offs+1]; - a0x=a[aoffset+0]; - a1x=a[aoffset+1]; - a2x=a[aoffset+2]; - t1x=a1x+a2x; - a0x=a0x+t1x; - m1x=c1*t1x; - m2y=c2*(a2x-a1x); - s1x=a0x+m1x; - a[aoffset+0]=a0x; - a[aoffset+1]=s1x-m2y; - a[aoffset+2]=s1x+m2y; - //--- exit the function - return; - } - //--- check - if(n==4) - { - //--- change values - a0x=a[aoffset+0]; - a1x=a[aoffset+1]; - a2x=a[aoffset+2]; - a3x=a[aoffset+3]; - t1x=a0x+a2x; - t2x=a1x+a3x; - m2x=a0x-a2x; - m3y=a3x-a1x; - a[aoffset+0]=t1x+t2x; - a[aoffset+1]=m2x-m3y; - a[aoffset+2]=t1x-t2x; - a[aoffset+3]=m2x+m3y; - //--- exit the function - return; - } - //--- check - if(n==5) - { - //--- change values - offs=plan.m_plan[entryoffset+7]; - c1=plan.m_precomputed[offs+0]; - c2=plan.m_precomputed[offs+1]; - c3=plan.m_precomputed[offs+2]; - c4=plan.m_precomputed[offs+3]; - c5=plan.m_precomputed[offs+4]; - t1x=a[aoffset+1]+a[aoffset+4]; - t2x=a[aoffset+2]+a[aoffset+3]; - t3x=a[aoffset+1]-a[aoffset+4]; - t4x=a[aoffset+3]-a[aoffset+2]; - t5x=t1x+t2x; - v0=a[aoffset+0]+t5x; - a[aoffset+0]=v0; - m2x=c2*(t1x-t2x); - m3y=c3*(t3x+t4x); - s3y=m3y-c4*t4x; - s5y=m3y+c5*t3x; - s1x=v0+c1*t5x; - s2x=s1x+m2x; - s4x=s1x-m2x; - a[aoffset+1]=s2x-s3y; - a[aoffset+2]=s4x-s5y; - a[aoffset+3]=s4x+s5y; - a[aoffset+4]=s2x+s3y; - //--- exit the function - return; - } - } -//--- check - if(plan.m_plan[entryoffset+3]==m_fftbluesteinplan) - { - //--- Bluestein plan: - //--- 1. multiply by precomputed coefficients - //--- 2. make convolution: forward FFT,multiplication by precomputed FFT - //--- and backward FFT. backward FFT is represented as - //--- invfft(x)=fft(x')'/M - //--- for performance reasons reduction of inverse FFT to - //--- forward FFT is merged with multiplication of FFT components - //--- and last stage of Bluestein's transformation. - //--- 3. post-multiplication by Bluestein factors - n=plan.m_plan[entryoffset+1]; - m=plan.m_plan[entryoffset+4]; - offs=plan.m_plan[entryoffset+7]; - for(i=stackptr+2*n;i<=stackptr+2*m-1;i++) - plan.m_stackbuf[i]=0; - //--- change values - offsp=offs+2*m; - offsa=aoffset; - offsb=stackptr; - for(i=0;i<=n-1;i++) - { - //--- change values - bx=plan.m_precomputed[offsp+0]; - by=plan.m_precomputed[offsp+1]; - x=a[offsa+0]; - y=a[offsa+1]; - plan.m_stackbuf[offsb+0]=x*bx-y*-by; - plan.m_stackbuf[offsb+1]=x*-by+y*bx; - offsp=offsp+2; - offsa=offsa+2; - offsb=offsb+2; - } - //--- function call - FtBaseExecutePlanRec(plan.m_stackbuf,stackptr,plan,plan.m_plan[entryoffset+5],stackptr+2*2*m); - offsb=stackptr; - offsp=offs; - for(i=0;i<=m-1;i++) - { - //--- change values - x=plan.m_stackbuf[offsb+0]; - y=plan.m_stackbuf[offsb+1]; - bx=plan.m_precomputed[offsp+0]; - by=plan.m_precomputed[offsp+1]; - plan.m_stackbuf[offsb+0]=x*bx-y*by; - plan.m_stackbuf[offsb+1]=-(x*by+y*bx); - offsb=offsb+2; - offsp=offsp+2; - } - //--- function call - FtBaseExecutePlanRec(plan.m_stackbuf,stackptr,plan,plan.m_plan[entryoffset+5],stackptr+2*2*m); - offsb=stackptr; - offsp=offs+2*m; - offsa=aoffset; - for(i=0;i<=n-1;i++) - { - //--- change values - x=plan.m_stackbuf[offsb+0]/m; - y=-(plan.m_stackbuf[offsb+1]/m); - bx=plan.m_precomputed[offsp+0]; - by=plan.m_precomputed[offsp+1]; - a[offsa+0]=x*bx-y*-by; - a[offsa+1]=x*-by+y*bx; - offsp=offsp+2; - offsa=offsa+2; - offsb=offsb+2; - } - //--- exit the function - return; - } - } -//+------------------------------------------------------------------+ -//| Returns good factorization N=N1*N2. | -//| Usually N1<=N2 (but not always - small N's may be exception). | -//| if N1<>1 then N2<>1. | -//| Factorization is chosen depending on task type and codelets we | -//| have. | -//+------------------------------------------------------------------+ -static void CFtBase::FtBaseFactorize(const int n,const int tasktype, - int &n1,int &n2) - { -//--- create a variable - int j=0; -//--- initialization - n1=0; - n2=0; -//--- try to find good codelet - if(n1*n2!=n) - { - for(j=m_ftbasecodeletrecommended;j>=2;j--) - { - //--- check - if(n%j==0) - { - n1=j; - n2=n/j; - break; - } - } - } -//--- try to factorize N - if(n1*n2!=n) - { - for(j=m_ftbasecodeletrecommended+1;j<=n-1;j++) - { - //--- check - if(n%j==0) - { - n1=j; - n2=n/j; - break; - } - } - } -//--- looks like N is prime :( - if(n1*n2!=n) - { - n1=1; - n2=n; - } -//--- normalize - if(n2==1 && n1!=1) - { - n2=n1; - n1=1; - } - } -//+------------------------------------------------------------------+ -//| Is number smooth? | -//+------------------------------------------------------------------+ -static bool CFtBase::FtBaseIsSmooth(int n) - { -//--- create a variable - int i=0; -//--- change n - for(i=2;i<=m_ftbasemaxsmoothfactor;i++) - { - while(n%i==0) - n=n/i; - } -//--- check - if(n==1) - return(true); -//--- return result - return(false); - } -//+------------------------------------------------------------------+ -//| Returns smallest smooth (divisible only by 2, 3, 5) number that | -//| is greater than or equal to max(N,2) | -//+------------------------------------------------------------------+ -static int CFtBase::FtBaseFindSmooth(const int n) - { -//--- create a variable - int best=0; -//--- calculation - best=2; - while(bestplanarraysize) - FFtArrayResize(plan.m_plan,planarraysize,8*planarraysize); - entryoffset=plansize; - esize=m_ftbaseplanentrysize; - plansize=plansize+esize; -//--- if N=1,generate empty plan and exit - if(n==1) - { - //--- change values - plan.m_plan[entryoffset+0]=esize; - plan.m_plan[entryoffset+1]=-1; - plan.m_plan[entryoffset+2]=-1; - plan.m_plan[entryoffset+3]=m_fftemptyplan; - plan.m_plan[entryoffset+4]=-1; - plan.m_plan[entryoffset+5]=-1; - plan.m_plan[entryoffset+6]=-1; - plan.m_plan[entryoffset+7]=-1; - //--- exit the function - return; - } -//--- generate plans - FtBaseFactorize(n,tasktype,n1,n2); -//--- check - if(tasktype==m_ftbasecffttask || tasktype==m_ftbaserffttask) - { - //--- complex FFT plans - if(n1!=1) - { - //--- Cooley-Tukey plan (real or complex) - //--- Note that child plans are COMPLEX - //--- (whether plan itself is complex or not). - tmpmemsize=MathMax(tmpmemsize,2*n1*n2); - plan.m_plan[entryoffset+0]=esize; - plan.m_plan[entryoffset+1]=n1; - plan.m_plan[entryoffset+2]=n2; - //--- check - if(tasktype==m_ftbasecffttask) - plan.m_plan[entryoffset+3]=m_fftcooleytukeyplan; - else - plan.m_plan[entryoffset+3]=m_fftrealcooleytukeyplan; - plan.m_plan[entryoffset+4]=0; - plan.m_plan[entryoffset+5]=plansize; - //--- function call - FtBaseGeneratePlanRec(n1,m_ftbasecffttask,plan,plansize,precomputedsize,planarraysize,tmpmemsize,stackmemsize,stackptr); - plan.m_plan[entryoffset+6]=plansize; - //--- function call - FtBaseGeneratePlanRec(n2,m_ftbasecffttask,plan,plansize,precomputedsize,planarraysize,tmpmemsize,stackmemsize,stackptr); - plan.m_plan[entryoffset+7]=-1; - //--- exit the function - return; - } - else - { - //--- check - if(((n==2 || n==3) || n==4) || n==5) - { - //--- hard-coded plan - plan.m_plan[entryoffset+0]=esize; - plan.m_plan[entryoffset+1]=n1; - plan.m_plan[entryoffset+2]=n2; - plan.m_plan[entryoffset+3]=m_fftcodeletplan; - plan.m_plan[entryoffset+4]=0; - plan.m_plan[entryoffset+5]=-1; - plan.m_plan[entryoffset+6]=-1; - plan.m_plan[entryoffset+7]=precomputedsize; - //--- check - if(n==3) - precomputedsize=precomputedsize+2; - //--- check - if(n==5) - precomputedsize=precomputedsize+5; - //--- exit the function - return; - } - else - { - //--- Bluestein's plan - //--- Select such M that M>=2*N-1,M is composite,and M's - //--- factors are 2,3,5 - k=2*n2-1; - m=FtBaseFindSmooth(k); - tmpmemsize=MathMax(tmpmemsize,2*m); - plan.m_plan[entryoffset+0]=esize; - plan.m_plan[entryoffset+1]=n2; - plan.m_plan[entryoffset+2]=-1; - plan.m_plan[entryoffset+3]=m_fftbluesteinplan; - plan.m_plan[entryoffset+4]=m; - plan.m_plan[entryoffset+5]=plansize; - stackptr=stackptr+2*2*m; - stackmemsize=MathMax(stackmemsize,stackptr); - //--- function call - FtBaseGeneratePlanRec(m,m_ftbasecffttask,plan,plansize,precomputedsize,planarraysize,tmpmemsize,stackmemsize,stackptr); - stackptr=stackptr-2*2*m; - plan.m_plan[entryoffset+6]=-1; - plan.m_plan[entryoffset+7]=precomputedsize; - precomputedsize=precomputedsize+2*m+2*n; - //--- exit the function - return; - } - } - } -//--- check - if(tasktype==m_ftbaserfhttask) - { - //--- real FHT plans - if(n1!=1) - { - //--- Cooley-Tukey plan - tmpmemsize=MathMax(tmpmemsize,2*n1*n2); - plan.m_plan[entryoffset+0]=esize; - plan.m_plan[entryoffset+1]=n1; - plan.m_plan[entryoffset+2]=n2; - plan.m_plan[entryoffset+3]=m_fhtcooleytukeyplan; - plan.m_plan[entryoffset+4]=0; - plan.m_plan[entryoffset+5]=plansize; - //--- function call - FtBaseGeneratePlanRec(n1,tasktype,plan,plansize,precomputedsize,planarraysize,tmpmemsize,stackmemsize,stackptr); - plan.m_plan[entryoffset+6]=plansize; - //--- function call - FtBaseGeneratePlanRec(n2,tasktype,plan,plansize,precomputedsize,planarraysize,tmpmemsize,stackmemsize,stackptr); - plan.m_plan[entryoffset+7]=-1; - //--- exit the function - return; - } - else - { - //--- N2 plan - plan.m_plan[entryoffset+0]=esize; - plan.m_plan[entryoffset+1]=n1; - plan.m_plan[entryoffset+2]=n2; - plan.m_plan[entryoffset+3]=m_fhtn2plan; - plan.m_plan[entryoffset+4]=0; - plan.m_plan[entryoffset+5]=-1; - plan.m_plan[entryoffset+6]=-1; - plan.m_plan[entryoffset+7]=-1; - //--- check - if(((n==2 || n==3) || n==4) || n==5) - { - //--- hard-coded plan - plan.m_plan[entryoffset+0]=esize; - plan.m_plan[entryoffset+1]=n1; - plan.m_plan[entryoffset+2]=n2; - plan.m_plan[entryoffset+3]=m_fhtcodeletplan; - plan.m_plan[entryoffset+4]=0; - plan.m_plan[entryoffset+5]=-1; - plan.m_plan[entryoffset+6]=-1; - plan.m_plan[entryoffset+7]=precomputedsize; - //--- check - if(n==3) - precomputedsize=precomputedsize+2; - //--- check - if(n==5) - precomputedsize=precomputedsize+5; - //--- exit the function - return; - } - //--- exit the function - return; - } - } - } -//+------------------------------------------------------------------+ -//| Recurrent subroutine for precomputing FFT plans | -//+------------------------------------------------------------------+ -static void CFtBase::FtBasePrecomputePlanRec(CFtPlan &plan,const int entryoffset, - const int stackptr) - { -//--- create variables - int i=0; - int n1=0; - int n2=0; - int n=0; - int m=0; - int offs=0; - double v=0; - double emptyarray[]; - double bx=0; - double by=0; -//--- check - if((plan.m_plan[entryoffset+3]==m_fftcooleytukeyplan || plan.m_plan[entryoffset+3]==m_fftrealcooleytukeyplan) || plan.m_plan[entryoffset+3]==m_fhtcooleytukeyplan) - { - //--- function call - FtBasePrecomputePlanRec(plan,plan.m_plan[entryoffset+5],stackptr); - //--- function call - FtBasePrecomputePlanRec(plan,plan.m_plan[entryoffset+6],stackptr); - //--- exit the function - return; - } -//--- check - if(plan.m_plan[entryoffset+3]==m_fftcodeletplan || plan.m_plan[entryoffset+3]==m_fhtcodeletplan) - { - n1=plan.m_plan[entryoffset+1]; - n2=plan.m_plan[entryoffset+2]; - n=n1*n2; - //--- check - if(n==3) - { - offs=plan.m_plan[entryoffset+7]; - plan.m_precomputed[offs+0]=MathCos(2*M_PI/3)-1; - plan.m_precomputed[offs+1]=MathSin(2*M_PI/3); - //--- exit the function - return; - } - //--- check - if(n==5) - { - offs=plan.m_plan[entryoffset+7]; - v=2*M_PI/5; - plan.m_precomputed[offs+0]=(MathCos(v)+MathCos(2*v))/2-1; - plan.m_precomputed[offs+1]=(MathCos(v)-MathCos(2*v))/2; - plan.m_precomputed[offs+2]=-MathSin(v); - plan.m_precomputed[offs+3]=-(MathSin(v)+MathSin(2*v)); - plan.m_precomputed[offs+4]=MathSin(v)-MathSin(2*v); - //--- exit the function - return; - } - } -//--- check - if(plan.m_plan[entryoffset+3]==m_fftbluesteinplan) - { - //--- function call - FtBasePrecomputePlanRec(plan,plan.m_plan[entryoffset+5],stackptr); - n=plan.m_plan[entryoffset+1]; - m=plan.m_plan[entryoffset+4]; - offs=plan.m_plan[entryoffset+7]; - for(i=0;i<=2*m-1;i++) - plan.m_precomputed[offs+i]=0; - //--- change values - for(i=0;i<=n-1;i++) - { - bx=MathCos(M_PI*CMath::Sqr(i)/n); - by=MathSin(M_PI*CMath::Sqr(i)/n); - plan.m_precomputed[offs+2*i+0]=bx; - plan.m_precomputed[offs+2*i+1]=by; - plan.m_precomputed[offs+2*m+2*i+0]=bx; - plan.m_precomputed[offs+2*m+2*i+1]=by; - //--- check - if(i>0) - { - plan.m_precomputed[offs+2*(m-i)+0]=bx; - plan.m_precomputed[offs+2*(m-i)+1]=by; - } - } - //--- function call - FtBaseExecutePlanRec(plan.m_precomputed,offs,plan,plan.m_plan[entryoffset+5],stackptr); - //--- exit the function - return; - } - } -//+------------------------------------------------------------------+ -//| Twiddle factors calculation | -//+------------------------------------------------------------------+ -static void CFtBase::FFtTwCalc(double &a[],const int aoffset,const int n1, - const int n2) - { -//--- create variables - int i=0; - int j=0; - int n=0; - int idx=0; - int offs=0; - double x=0; - double y=0; - double twxm1=0; - double twy=0; - double twbasexm1=0; - double twbasey=0; - double twrowxm1=0; - double twrowy=0; - double tmpx=0; - double tmpy=0; - double v=0; -//--- initialization - n=n1*n2; - v=-(2*M_PI/n); - twbasexm1=-(2*CMath::Sqr(MathSin(0.5*v))); - twbasey=MathSin(v); - twrowxm1=0; - twrowy=0; -//--- calculation - for(i=0;i<=n2-1;i++) - { - twxm1=0; - twy=0; - for(j=0;j<=n1-1;j++) - { - //--- change values - idx=i*n1+j; - offs=aoffset+2*idx; - x=a[offs+0]; - y=a[offs+1]; - tmpx=x*twxm1-y*twy; - tmpy=x*twy+y*twxm1; - a[offs+0]=x+tmpx; - a[offs+1]=y+tmpy; - //--- update Tw: Tw(new)=Tw(old)*TwRow - if(jm) - { - //--- New partition: - //--- "A^T -> B" becomes "(A1 A2)^T -> ( B1 ) - //--- ( B2 ) - n1=n/2; - //--- check - if(n-n1>=8 && n1%8!=0) - n1=n1+(8-n1%8); - //--- check - if(!CAp::Assert(n-n1>0)) - return; - //--- function call - FFtICLTRec(a,astart,astride,b,bstart,bstride,m,n1); - //--- function call - FFtICLTRec(a,astart+2*n1,astride,b,bstart+2*n1*bstride,bstride,m,n-n1); - } - else - { - //--- New partition: - //--- "A^T -> B" becomes "( A1 )^T -> ( B1 B2 ) - //--- ( A2 ) - m1=m/2; - //--- check - if(m-m1>=8 && m1%8!=0) - m1=m1+(8-m1%8); - //--- check - if(!CAp::Assert(m-m1>0)) - return; - //--- function call - FFtICLTRec(a,astart,astride,b,bstart,bstride,m1,n); - //--- function call - FFtICLTRec(a,astart+2*m1*astride,astride,b,bstart+2*m1,bstride,m-m1,n); - } - } -//+------------------------------------------------------------------+ -//| Recurrent subroutine for a InternalRealLinTranspose | -//+------------------------------------------------------------------+ -static void CFtBase::FFtIRLTRec(double &a[],const int astart,const int astride, - double &b[],const int bstart,const int bstride, - const int m,const int n) - { -//--- create variables - int i=0; - int j=0; - int idx1=0; - int idx2=0; - int m1=0; - int n1=0; -//--- check - if(m==0 || n==0) - return; -//--- check - if(MathMax(m,n)<=8) - { - for(i=0;i<=m-1;i++) - { - //--- calculation - idx1=bstart+i; - idx2=astart+i*astride; - for(j=0;j<=n-1;j++) - { - b[idx1]=a[idx2]; - idx1=idx1+bstride; - idx2=idx2+1; - } - } - //--- exit the function - return; - } -//--- check - if(n>m) - { - //--- New partition: - //--- "A^T -> B" becomes "(A1 A2)^T -> ( B1 ) - //--- ( B2 ) - n1=n/2; - //--- check - if(n-n1>=8 && n1%8!=0) - n1=n1+(8-n1%8); - //--- check - if(!CAp::Assert(n-n1>0)) - return; - //--- function call - FFtIRLTRec(a,astart,astride,b,bstart,bstride,m,n1); - //--- function call - FFtIRLTRec(a,astart+n1,astride,b,bstart+n1*bstride,bstride,m,n-n1); - } - else - { - //--- New partition: - //--- "A^T -> B" becomes "( A1 )^T -> ( B1 B2 ) - //--- ( A2 ) - m1=m/2; - //--- check - if(m-m1>=8 && m1%8!=0) - m1=m1+(8-m1%8); - //--- check - if(!CAp::Assert(m-m1>0)) - return; - //--- function call - FFtIRLTRec(a,astart,astride,b,bstart,bstride,m1,n); - //--- function call - FFtIRLTRec(a,astart+m1*astride,astride,b,bstart+m1,bstride,m-m1,n); - } - } -//+------------------------------------------------------------------+ -//| recurrent subroutine for FFTFindSmoothRec | -//+------------------------------------------------------------------+ -static void CFtBase::FtBaseFindSmoothRec(const int n,const int seed, - const int leastfactor,int &best) - { -//--- check - if(!CAp::Assert(m_ftbasemaxsmoothfactor<=5,__FUNCTION__+": internal error!")) - return; -//--- check - if(seed>=n) - { - best=MathMin(best,seed); - return; - } -//--- check - if(leastfactor<=2) - { - //--- function call - FtBaseFindSmoothRec(n,seed*2,2,best); - } -//--- check - if(leastfactor<=3) - { - //--- function call - FtBaseFindSmoothRec(n,seed*3,3,best); - } -//--- check - if(leastfactor<=5) - { - //--- function call - FtBaseFindSmoothRec(n,seed*5,5,best); - } - } -//+------------------------------------------------------------------+ -//| Internal subroutine: array resize | -//+------------------------------------------------------------------+ -static void CFtBase::FFtArrayResize(int &a[],int &asize,const int newasize) - { -//--- create variables - int tmp[]; - int i=0; -//--- allocation - ArrayResizeAL(tmp,asize); - for(i=0;i<=asize-1;i++) - tmp[i]=a[i]; -//--- allocation - ArrayResizeAL(a,newasize); - for(i=0;i<=asize-1;i++) - a[i]=tmp[i]; -//--- get result - asize=newasize; - } -//+------------------------------------------------------------------+ -//| Reference FHT stub | -//+------------------------------------------------------------------+ -static void CFtBase::ReFFHt(double &a[],const int n,const int offs) - { -//--- create array - double buf[]; -//--- create variables - int i=0; - int j=0; - double v=0; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": incorrect N!")) - return; -//--- allocation - ArrayResizeAL(buf,n); -//--- calculation - for(i=0;i<=n-1;i++) - { - v=0; - for(j=0;j<=n-1;j++) - v=v+a[offs+j]*(MathCos(2*M_PI*i*j/n)+MathSin(2*M_PI*i*j/n)); - buf[i]=v; - } -//--- get result - for(i=0;i<=n-1;i++) - a[offs+i]=buf[i]; - } -//+------------------------------------------------------------------+ -//| Auxiliary class for calculation mathematical functions | -//+------------------------------------------------------------------+ -class CNearUnitYUnit - { -public: - //--- constructor, destructor - CNearUnitYUnit(void); - ~CNearUnitYUnit(void); - //--- methods - static double NULog1p(const double x); - static double NUExp1m(const double x); - static double NUCos1m(const double x); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CNearUnitYUnit::CNearUnitYUnit(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CNearUnitYUnit::~CNearUnitYUnit(void) - { - - } -//+------------------------------------------------------------------+ -//| Log | -//+------------------------------------------------------------------+ -static double CNearUnitYUnit::NULog1p(const double x) - { -//--- create variables - double z=1.0+x; - double lp=0; - double lq=0; -//--- check - if(z<0.70710678118654752440 || z>1.41421356237309504880) - return(MathLog(z)); -//--- calculation result - z=x*x; - lp=4.5270000862445199635215E-5; - lp=lp*x+4.9854102823193375972212E-1; - lp=lp*x+6.5787325942061044846969E0; - lp=lp*x+2.9911919328553073277375E1; - lp=lp*x+6.0949667980987787057556E1; - lp=lp*x+5.7112963590585538103336E1; - lp=lp*x+2.0039553499201281259648E1; - lq=1.0000000000000000000000E0; - lq=lq*x+1.5062909083469192043167E1; - lq=lq*x+8.3047565967967209469434E1; - lq=lq*x+2.2176239823732856465394E2; - lq=lq*x+3.0909872225312059774938E2; - lq=lq*x+2.1642788614495947685003E2; - lq=lq*x+6.0118660497603843919306E1; - z=-(0.5*z)+x*(z*lp/lq); -//--- return result - return(x+z); - } -//+------------------------------------------------------------------+ -//| Exp | -//+------------------------------------------------------------------+ -static double CNearUnitYUnit::NUExp1m(const double x) - { -//--- create variables - double r; - double xx; - double ep; - double eq; -//--- check - if(x<-0.5 || x>0.5) - return(MathExp(x)-1.0); -//--- calculation result - xx=x*x; - ep=1.2617719307481059087798E-4; - ep=ep*xx+3.0299440770744196129956E-2; - ep=ep*xx+9.9999999999999999991025E-1; - eq=3.0019850513866445504159E-6; - eq=eq*xx+2.5244834034968410419224E-3; - eq=eq*xx+2.2726554820815502876593E-1; - eq=eq*xx+2.0000000000000000000897E0; - r=x*ep; - r=r/(eq-r); -//--- return result - return(r+r); - } -//+------------------------------------------------------------------+ -//| Cos | -//+------------------------------------------------------------------+ -static double CNearUnitYUnit::NUCos1m(const double x) - { -//--- create variables - double xx; - double c; -//--- check - if(x<-0.25*M_PI || x>0.25*M_PI) - return(MathCos(x)-1); -//--- get result - xx=x*x; - c=4.7377507964246204691685E-14; - c=c*xx-1.1470284843425359765671E-11; - c=c*xx+2.0876754287081521758361E-9; - c=c*xx-2.7557319214999787979814E-7; - c=c*xx+2.4801587301570552304991E-5; - c=c*xx-1.3888888888888872993737E-3; - c=c*xx+4.1666666666666666609054E-2; -//--- return result - return(-(0.5*xx)+xx*xx*c); - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Alglib/alglibmisc.mqh b/Include/Math/Alglib/alglibmisc.mqh deleted file mode 100644 index 3d7bf4a..0000000 --- a/Include/Math/Alglib/alglibmisc.mqh +++ /dev/null @@ -1,1493 +0,0 @@ -//+------------------------------------------------------------------+ -//| alglibmisc.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 "ap.mqh" -#include "alglibinternal.mqh" -//+------------------------------------------------------------------+ -//| KD-trees | -//+------------------------------------------------------------------+ -class CKDTree - { -public: - int m_n; - int m_nx; - int m_ny; - int m_normtype; - int m_kneeded; - double m_rneeded; - bool m_selfmatch; - double m_approxf; - int m_kcur; - double m_curdist; - int m_debugcounter; - //--- arrays - int m_tags[]; - double m_boxmin[]; - double m_boxmax[]; - int m_nodes[]; - double m_splits[]; - double m_x[]; - int m_idx[]; - double m_r[]; - double m_buf[]; - double m_curboxmin[]; - double m_curboxmax[]; - //--- matrix - CMatrixDouble m_xy; - //--- constructor, destructor - CKDTree(void); - ~CKDTree(void); - //--- copy - void Copy(CKDTree &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CKDTree::CKDTree(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CKDTree::~CKDTree(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CKDTree::Copy(CKDTree &obj) - { -//--- copy variables - m_n=obj.m_n; - m_nx=obj.m_nx; - m_ny=obj.m_ny; - m_normtype=obj.m_normtype; - m_kneeded=obj.m_kneeded; - m_rneeded=obj.m_rneeded; - m_selfmatch=obj.m_selfmatch; - m_approxf=obj.m_approxf; - m_kcur=obj.m_kcur; - m_curdist=obj.m_curdist; - m_debugcounter=obj.m_debugcounter; -//--- copy arrays - ArrayCopy(m_tags,obj.m_tags); - ArrayCopy(m_boxmin,obj.m_boxmin); - ArrayCopy(m_boxmax,obj.m_boxmax); - ArrayCopy(m_nodes,obj.m_nodes); - ArrayCopy(m_splits,obj.m_splits); - ArrayCopy(m_x,obj.m_x); - ArrayCopy(m_idx,obj.m_idx); - ArrayCopy(m_r,obj.m_r); - ArrayCopy(m_buf,obj.m_buf); - ArrayCopy(m_curboxmin,obj.m_curboxmin); - ArrayCopy(m_curboxmax,obj.m_curboxmax); -//--- copy matrix - m_xy=obj.m_xy; - } -//+------------------------------------------------------------------+ -//| This class is a shell for class CKDTree | -//+------------------------------------------------------------------+ -class CKDTreeShell - { -private: - CKDTree m_innerobj; -public: - //--- constructors, destructor - CKDTreeShell(void); - CKDTreeShell(CKDTree &obj); - ~CKDTreeShell(void); - //--- method - CKDTree *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CKDTreeShell::CKDTreeShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -CKDTreeShell::CKDTreeShell(CKDTree &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CKDTreeShell::~CKDTreeShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Return object of CKDTree | -//+------------------------------------------------------------------+ -CKDTree *CKDTreeShell::GetInnerObj(void) - { - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Build KD-trees | -//+------------------------------------------------------------------+ -class CNearestNeighbor - { -public: - //--- class constants - static const int m_splitnodesize; - static const int m_kdtreefirstversion; - //--- constructor, destructor - CNearestNeighbor(void); - ~CNearestNeighbor(void); - //--- build - static void KDTreeBuild(CMatrixDouble &xy,const int n,const int nx,const int ny,const int normtype,CKDTree &kdt); - static void KDTreeBuildTagged(CMatrixDouble &xy,int &tags[],const int n,const int nx,const int ny,const int normtype,CKDTree &kdt); - static int KDTreeQueryKNN(CKDTree &kdt,double &x[],const int k,const bool selfmatch); - static int KDTreeQueryRNN(CKDTree &kdt,double &x[],const double r,const bool selfmatch); - static int KDTreeQueryAKNN(CKDTree &kdt,double &x[],int k,const bool selfmatch,const double eps); - static void KDTreeQueryResultsX(CKDTree &kdt,CMatrixDouble &x); - static void KDTreeQueryResultsXY(CKDTree &kdt,CMatrixDouble &xy); - static void KDTreeQueryResultsTags(CKDTree &kdt,int &tags[]); - static void KDTreeQueryResultsDistances(CKDTree &kdt,double &r[]); - static void KDTreeQueryResultsXI(CKDTree &kdt,CMatrixDouble &x); - static void KDTreeQueryResultsXYI(CKDTree &kdt,CMatrixDouble &xy); - static void KDTreeQueryResultsTagsI(CKDTree &kdt,int &tags[]); - static void KDTreeQueryResultsDistancesI(CKDTree &kdt,double &r[]); - //--- serialize - static void KDTreeAlloc(CSerializer &s,CKDTree &tree); - static void KDTreeSerialize(CSerializer &s,CKDTree &tree); - static void KDTreeUnserialize(CSerializer &s,CKDTree &tree); -private: - //--- private methods - static void KDTreeSplit(CKDTree &kdt,const int i1,const int i2,const int d,const double s,int &i3); - static void KDTreeGenerateTreeRec(CKDTree &kdt,int &nodesoffs,int &splitsoffs,const int i1,const int i2,const int maxleafsize); - static void KDTreeQueryNNRec(CKDTree &kdt,const int offs); - static void KDTreeInitBox(CKDTree &kdt,double &x[]); - static void KDTreeAllocDataSetIndependent(CKDTree &kdt,const int nx,const int ny); - static void KDTreeAllocDataSetDependent(CKDTree &kdt,const int n,const int nx,const int ny); - static void KDTreeAllocTemporaries(CKDTree &kdt,const int n,const int nx,const int ny); - }; -//+------------------------------------------------------------------+ -//| Initialize constants | -//+------------------------------------------------------------------+ -const int CNearestNeighbor::m_splitnodesize=6; -const int CNearestNeighbor::m_kdtreefirstversion=0; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CNearestNeighbor::CNearestNeighbor(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CNearestNeighbor::~CNearestNeighbor(void) - { - - } -//+------------------------------------------------------------------+ -//| KD-tree creation | -//| This subroutine creates KD-tree from set of X-values and optional| -//| Y-values | -//| INPUT PARAMETERS | -//| XY - dataset, array[0..N-1,0..NX+NY-1]. | -//| one row corresponds to one point. | -//| first NX columns contain X-values, next NY (NY | -//| may be zero) | -//| columns may contain associated Y-values | -//| N - number of points, N>=1 | -//| NX - space dimension, NX>=1. | -//| NY - number of optional Y-values, NY>=0. | -//| NormType- norm type: | -//| * 0 denotes infinity-norm | -//| * 1 denotes 1-norm | -//| * 2 denotes 2-norm (Euclidean norm) | -//| OUTPUT PARAMETERS | -//| KDT - KD-tree | -//| NOTES | -//| 1. KD-tree creation have O(N*logN) complexity and | -//| O(N*(2*NX+NY)) memory requirements. | -//| 2. Although KD-trees may be used with any combination of N and | -//| NX, they are more efficient than brute-force search only when | -//| N >> 4^NX. So they are most useful in low-dimensional tasks | -//| (NX=2, NX=3). NX=1 is another inefficient case, because | -//| simple binary search (without additional structures) is | -//| much more efficient in such tasks than KD-trees. | -//+------------------------------------------------------------------+ -static void CNearestNeighbor::KDTreeBuild(CMatrixDouble &xy,const int n, - const int nx,const int ny, - const int normtype,CKDTree &kdt) - { -//--- create a variable - int i=0; -//--- creating array - int tags[]; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(nx>=1,__FUNCTION__+": NX<1!")) - return; -//--- check - if(!CAp::Assert(ny>=0,__FUNCTION__+": NY<0!")) - return; -//--- check - if(!CAp::Assert(normtype>=0&&normtype<=2,__FUNCTION__+": incorrect NormType!")) - return; -//--- check - if(!CAp::Assert(CAp::Rows(xy)>=n,__FUNCTION__+": rows(X)=nx+ny,__FUNCTION__+": cols(X)=1 | -//| NX - space dimension, NX>=1. | -//| NY - number of optional Y-values, NY>=0. | -//| NormType- norm type: | -//| * 0 denotes infinity-norm | -//| * 1 denotes 1-norm | -//| * 2 denotes 2-norm (Euclidean norm) | -//| OUTPUT PARAMETERS | -//| KDT - KD-tree | -//| NOTES | -//| 1. KD-tree creation have O(N*logN) complexity and | -//| O(N*(2*NX+NY)) memory requirements. | -//| 2. Although KD-trees may be used with any combination of N and | -//| NX, they are more efficient than brute-force search only when | -//| N >> 4^NX. So they are most useful in low-dimensional tasks | -//| (NX=2, NX=3). NX=1 is another inefficient case, because simple| -//| binary search (without additional structures) is much more | -//| efficient in such tasks than KD-trees. | -//+------------------------------------------------------------------+ -static void CNearestNeighbor::KDTreeBuildTagged(CMatrixDouble &xy,int &tags[], - const int n,const int nx, - const int ny, - const int normtype,CKDTree &kdt) - { -//--- create variables - int i=0; - int j=0; - int maxnodes=0; - int nodesoffs=0; - int splitsoffs=0; - int i_=0; - int i1_=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(nx>=1,__FUNCTION__+": NX<1!")) - return; -//--- check - if(!CAp::Assert(ny>=0,__FUNCTION__+": NY<0!")) - return; -//--- check - if(!CAp::Assert(normtype>=0&&normtype<=2,__FUNCTION__+": incorrect NormType!")) - return; -//--- check - if(!CAp::Assert(CAp::Rows(xy)>=n,__FUNCTION__+": rows(X)=nx+ny,__FUNCTION__+": cols(X)=1 | -//| SelfMatch - whether self-matches are allowed: | -//| * if True, nearest neighbor may be the point | -//| itself (if it exists in original dataset) | -//| * if False, then only points with non-zero | -//| distance are returned | -//| * if not given, considered True | -//| RESULT | -//| number of actual neighbors found (either K or N, if K>N). | -//| This subroutine performs query and stores its result in the | -//| internal structures of the KD-tree. You can use following | -//| subroutines to obtain these results: | -//| * KDTreeQueryResultsX() to get X-values | -//| * KDTreeQueryResultsXY() to get X- and Y-values | -//| * KDTreeQueryResultsTags() to get tag values | -//| * KDTreeQueryResultsDistances() to get distances | -//+------------------------------------------------------------------+ -static int CNearestNeighbor::KDTreeQueryKNN(CKDTree &kdt,double &x[], - const int k,const bool selfmatch) - { -//--- check - if(!CAp::Assert(k>=1,__FUNCTION__+": K<1!")) - return(-1); -//--- check - if(!CAp::Assert(CAp::Len(x)>=kdt.m_nx,__FUNCTION__+": Length(X)0| -//| SelfMatch - whether self-matches are allowed: | -//| * if True, nearest neighbor may be the point | -//| itself (if it exists in original dataset) | -//| * if False, then only points with non-zero | -//| distance are returned | -//| * if not given, considered True | -//| RESULT | -//| number of neighbors found, >=0 | -//| This subroutine performs query and stores its result in the | -//| internal structures of the KD-tree. You can use following | -//| subroutines to obtain actual results: | -//| * KDTreeQueryResultsX() to get X-values | -//| * KDTreeQueryResultsXY() to get X- and Y-values | -//| * KDTreeQueryResultsTags() to get tag values | -//| * KDTreeQueryResultsDistances() to get distances | -//+------------------------------------------------------------------+ -static int CNearestNeighbor::KDTreeQueryRNN(CKDTree &kdt,double &x[], - const double r,const bool selfmatch) - { -//--- create variables - int result=0; - int i=0; - int j=0; -//--- check - if(!CAp::Assert((double)(r)>0.0,__FUNCTION__+": incorrect R!")) - return(-1); -//--- check - if(!CAp::Assert(CAp::Len(x)>=kdt.m_nx,__FUNCTION__+": Length(X)=2;i--) - CTSort::TagHeapPopI(kdt.m_r,kdt.m_idx,j); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| K-NN query: approximate K nearest neighbors | -//| INPUT PARAMETERS | -//| KDT - KD-tree | -//| X - point, array[0..NX-1]. | -//| K - number of neighbors to return, K>=1 | -//| SelfMatch - whether self-matches are allowed: | -//| * if True, nearest neighbor may be the point | -//| itself (if it exists in original dataset) | -//| * if False, then only points with non-zero | -//| distance are returned | -//| * if not given, considered True | -//| Eps - approximation factor, Eps>=0. eps-approximate| -//| nearest neighbor is a neighbor whose distance| -//| from X is at most (1+eps) times distance of | -//| true nearest neighbor. | -//| RESULT | -//| number of actual neighbors found (either K or N, if K>N). | -//| NOTES | -//| significant performance gain may be achieved only when Eps is| -//| on the order of magnitude of 1 or larger. | -//| This subroutine performs query and stores its result in the | -//| internal structures of the KD-tree. You can use following | -//| these subroutines to obtain results: | -//| * KDTreeQueryResultsX() to get X-values | -//| * KDTreeQueryResultsXY() to get X- and Y-values | -//| * KDTreeQueryResultsTags() to get tag values | -//| * KDTreeQueryResultsDistances() to get distances | -//+------------------------------------------------------------------+ -static int CNearestNeighbor::KDTreeQueryAKNN(CKDTree &kdt,double &x[], - int k,const bool selfmatch, - const double eps) - { -//--- create variables - int result=0; - int i=0; - int j=0; -//--- check - if(!CAp::Assert(k>0,__FUNCTION__+": incorrect K!")) - return(-1); -//--- check - if(!CAp::Assert(eps>=0.0,__FUNCTION__+": incorrect Eps!")) - return(-1); -//--- check - if(!CAp::Assert(CAp::Len(x)>=kdt.m_nx,__FUNCTION__+": Length(X)=2;i--) - CTSort::TagHeapPopI(kdt.m_r,kdt.m_idx,j); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| X-values from last query | -//| INPUT PARAMETERS | -//| KDT - KD-tree | -//| X - possibly pre-allocated buffer. If X is too small | -//| to store result, it is resized. If size(X) is | -//| enough to store result, it is left unchanged. | -//| OUTPUT PARAMETERS | -//| X - rows are filled with X-values | -//| NOTES | -//| 1. points are ordered by distance from the query point (first = | -//| closest) | -//| 2. if XY is larger than required to store result, only leading | -//| part will be overwritten; trailing part will be left | -//| unchanged. So if on input XY = [[A,B],[C,D]], and result is | -//| [1,2], then on exit we will get XY = [[1,2],[C,D]]. This is | -//| done purposely to increase performance; if you want function | -//| to resize array according to result size, use function with | -//| same name and suffix 'I'. | -//| SEE ALSO | -//| * KDTreeQueryResultsXY() X- and Y-values | -//| * KDTreeQueryResultsTags() tag values | -//| * KDTreeQueryResultsDistances() distances | -//+------------------------------------------------------------------+ -static void CNearestNeighbor::KDTreeQueryResultsX(CKDTree &kdt,CMatrixDouble &x) - { -//--- create variables - int i=0; - int k=0; - int i_=0; - int i1_=0; -//--- check - if(kdt.m_kcur==0) - return; -//--- check - if(CAp::Rows(x)i1,__FUNCTION__+": internal error")) - return; -//--- Generate leaf if needed - if(i2-i1<=maxleafsize) - { - kdt.m_nodes[nodesoffs+0]=i2-i1; - kdt.m_nodes[nodesoffs+1]=i1; - nodesoffs=nodesoffs+2; - //--- exit the function - return; - } -//--- Load values for easier access - nx=kdt.m_nx; - ny=kdt.m_ny; -//--- select dimension to split: -//--- * D is a dimension number - d=0; - ds=kdt.m_curboxmax[0]-kdt.m_curboxmin[0]; - for(i=1;i<=nx-1;i++) - { - v=kdt.m_curboxmax[i]-kdt.m_curboxmin[i]; - //--- check - if(v>ds) - { - ds=v; - d=i; - } - } -//--- Select split position S using sliding midpoint rule, -//--- rearrange points into [I1,I3) and [I3,I2) - s=kdt.m_curboxmin[d]+0.5*ds; - i1_=(i1) -(0); - for(i_=0;i_<=i2-i1-1;i_++) - kdt.m_buf[i_]=kdt.m_xy[i_+i1_][d]; -//--- change values - n=i2-i1; - cntless=0; - cntgreater=0; - minv=kdt.m_buf[0]; - maxv=kdt.m_buf[0]; - minidx=i1; - maxidx=i1; - for(i=0;i<=n-1;i++) - { - v=kdt.m_buf[i]; - //--- check - if(vmaxv) - { - maxv=v; - maxidx=i1+i; - } - //--- check - if(vs) - cntgreater=cntgreater+1; - } -//--- check - if(cntless>0&&cntgreater>0) - { - //--- normal midpoint split - KDTreeSplit(kdt,i1,i2,d,s,i3); - } - else - { - //--- sliding midpoint - if(cntless==0) - { - //--- 1. move split to MinV, - //--- 2. place one point to the left bin (move to I1), - //--- others - to the right bin - s=minv; - //--- check - if(minidx!=i1) - { - for(i=0;i<=2*kdt.m_nx+kdt.m_ny-1;i++) - { - v=kdt.m_xy[minidx][i]; - kdt.m_xy[minidx].Set(i,kdt.m_xy[i1][i]); - kdt.m_xy[i1].Set(i,v); - } - //--- change values - j=kdt.m_tags[minidx]; - kdt.m_tags[minidx]=kdt.m_tags[i1]; - kdt.m_tags[i1]=j; - } - i3=i1+1; - } - else - { - //--- 1. move split to MaxV, - //--- 2. place one point to the right bin (move to I2-1), - //--- others - to the left bin - s=maxv; - //--- check - if(maxidx!=i2-1) - { - for(i=0;i<=2*kdt.m_nx+kdt.m_ny-1;i++) - { - v=kdt.m_xy[maxidx][i]; - kdt.m_xy[maxidx].Set(i,kdt.m_xy[i2-1][i]); - kdt.m_xy[i2-1].Set(i,v); - } - //--- change values - j=kdt.m_tags[maxidx]; - kdt.m_tags[maxidx]=kdt.m_tags[i2-1]; - kdt.m_tags[i2-1]=j; - } - i3=i2-1; - } - } -//--- Generate 'split' node - kdt.m_nodes[nodesoffs+0]=0; - kdt.m_nodes[nodesoffs+1]=d; - kdt.m_nodes[nodesoffs+2]=splitsoffs; - kdt.m_splits[splitsoffs+0]=s; - oldoffs=nodesoffs; - nodesoffs=nodesoffs+m_splitnodesize; - splitsoffs=splitsoffs+1; -//--- Recirsive generation: -//--- * update CurBox -//--- * call subroutine -//--- * restore CurBox - kdt.m_nodes[oldoffs+3]=nodesoffs; - v=kdt.m_curboxmax[d]; - kdt.m_curboxmax[d]=s; -//--- function call - KDTreeGenerateTreeRec(kdt,nodesoffs,splitsoffs,i1,i3,maxleafsize); - kdt.m_curboxmax[d]=v; - kdt.m_nodes[oldoffs+4]=nodesoffs; - v=kdt.m_curboxmin[d]; - kdt.m_curboxmin[d]=s; -//--- function call - KDTreeGenerateTreeRec(kdt,nodesoffs,splitsoffs,i3,i2,maxleafsize); - kdt.m_curboxmin[d]=v; - } -//+------------------------------------------------------------------+ -//| Recursive subroutine for NN queries. | -//+------------------------------------------------------------------+ -static void CNearestNeighbor::KDTreeQueryNNRec(CKDTree &kdt,const int offs) - { -//--- create variables - double ptdist=0; - int i=0; - int j=0; - int nx=0; - int i1=0; - int i2=0; - int d=0; - double s=0; - double v=0; - double t1=0; - int childbestoffs=0; - int childworstoffs=0; - int childoffs=0; - double prevdist=0; - bool todive; - bool bestisleft; - bool updatemin; -//--- Leaf node. -//--- Process points. - if(kdt.m_nodes[offs]>0) - { - i1=kdt.m_nodes[offs+1]; - i2=i1+kdt.m_nodes[offs]; - for(i=i1;i<=i2-1;i++) - { - //--- Calculate distance - ptdist=0; - nx=kdt.m_nx; - //--- check - if(kdt.m_normtype==0) - { - for(j=0;j<=nx-1;j++) - ptdist=MathMax(ptdist,MathAbs(kdt.m_xy[i][j]-kdt.m_x[j])); - } - //--- check - if(kdt.m_normtype==1) - { - for(j=0;j<=nx-1;j++) - ptdist=ptdist+MathAbs(kdt.m_xy[i][j]-kdt.m_x[j]); - } - //--- check - if(kdt.m_normtype==2) - { - for(j=0;j<=nx-1;j++) - ptdist=ptdist+CMath::Sqr(kdt.m_xy[i][j]-kdt.m_x[j]); - } - //--- Skip points with zero distance if self-matches are turned off - if(ptdist==0.0 && !kdt.m_selfmatch) - continue; - //--- We CAN'T process point if R-criterion isn't satisfied, - //--- i.e. (RNeeded<>0) AND (PtDist>R). - if(kdt.m_rneeded==0.0 || ptdist<=kdt.m_rneeded) - { - //--- R-criterion is satisfied, we must either: - //--- * replace worst point, if (KNeeded<>0) AND (KCur=KNeeded) - //--- (or skip, if worst point is better) - //--- * add point without replacement otherwise - if(kdt.m_kcur=s) - { - //--- check - if(kdt.m_normtype==0) - kdt.m_curdist=MathMax(kdt.m_curdist,t1-s); - //--- check - if(kdt.m_normtype==1) - kdt.m_curdist=kdt.m_curdist-MathMax(t1-v,0)+t1-s; - //--- check - if(kdt.m_normtype==2) - kdt.m_curdist=kdt.m_curdist-CMath::Sqr(MathMax(t1-v,0))+CMath::Sqr(t1-s); - } - kdt.m_curboxmax[d]=s; - } - //--- Decide: to dive into cell or not to dive - if(kdt.m_rneeded!=0.0 && kdt.m_curdist>kdt.m_rneeded) - todive=false; - else - { - //--- check - if(kdt.m_kcurvmax) - kdt.m_curdist=MathMax(kdt.m_curdist,vx-vmax); - } - } - } -//--- check - if(kdt.m_normtype==1) - { - for(i=0;i<=kdt.m_nx-1;i++) - { - vx=x[i]; - vmin=kdt.m_boxmin[i]; - vmax=kdt.m_boxmax[i]; - kdt.m_x[i]=vx; - kdt.m_curboxmin[i]=vmin; - kdt.m_curboxmax[i]=vmax; - //--- check - if(vxvmax) - kdt.m_curdist=kdt.m_curdist+vx-vmax; - } - } - } -//--- check - if(kdt.m_normtype==2) - { - for(i=0;i<=kdt.m_nx-1;i++) - { - vx=x[i]; - vmin=kdt.m_boxmin[i]; - vmax=kdt.m_boxmax[i]; - kdt.m_x[i]=vx; - kdt.m_curboxmin[i]=vmin; - kdt.m_curboxmax[i]=vmax; - //--- check - if(vxvmax) - kdt.m_curdist=kdt.m_curdist+CMath::Sqr(vx-vmax); - } - } - } - } -//+------------------------------------------------------------------+ -//| This function allocates all dataset-independent array fields of | -//| KDTree, i.e. such array fields that their dimensions do not | -//| depend on dataset size. | -//| This function do not sets KDT.NX or KDT.NY - it just allocates | -//| arrays | -//+------------------------------------------------------------------+ -static void CNearestNeighbor::KDTreeAllocDataSetIndependent(CKDTree &kdt, - const int nx, - const int ny) - { -//--- allocation - ArrayResizeAL(kdt.m_x,nx); - ArrayResizeAL(kdt.m_boxmin,nx); - ArrayResizeAL(kdt.m_boxmax,nx); - ArrayResizeAL(kdt.m_curboxmin,nx); - ArrayResizeAL(kdt.m_curboxmax,nx); - } -//+------------------------------------------------------------------+ -//| This function allocates all dataset-dependent array fields of | -//| KDTree, i.e. such array fields that their dimensions depend on | -//| dataset size. | -//| This function do not sets KDT.N, KDT.NX or KDT.NY - | -//| it just allocates arrays. | -//+------------------------------------------------------------------+ -static void CNearestNeighbor::KDTreeAllocDataSetDependent(CKDTree &kdt, - const int n, - const int nx, - const int ny) - { -//--- allocation - kdt.m_xy.Resize(n,2*nx+ny); - ArrayResizeAL(kdt.m_tags,n); - ArrayResizeAL(kdt.m_idx,n); - ArrayResizeAL(kdt.m_r,n); - ArrayResizeAL(kdt.m_x,nx); - ArrayResizeAL(kdt.m_buf,MathMax(n,nx)); - ArrayResizeAL(kdt.m_nodes,m_splitnodesize*2*n); - ArrayResizeAL(kdt.m_splits,2*n); - } -//+------------------------------------------------------------------+ -//| This function allocates temporaries. | -//| This function do not sets KDT.N,KDT.NX or KDT.NY - | -//| it just allocates arrays. | -//+------------------------------------------------------------------+ -static void CNearestNeighbor::KDTreeAllocTemporaries(CKDTree &kdt,const int n, - const int nx,const int ny) - { -//--- allocation - ArrayResizeAL(kdt.m_x,nx); - ArrayResizeAL(kdt.m_idx,n); - ArrayResizeAL(kdt.m_r,n); - ArrayResizeAL(kdt.m_buf,MathMax(n,nx)); - ArrayResizeAL(kdt.m_curboxmin,nx); - ArrayResizeAL(kdt.m_curboxmax,nx); - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Alglib/ap.mqh b/Include/Math/Alglib/ap.mqh deleted file mode 100644 index fcd5711..0000000 --- a/Include/Math/Alglib/ap.mqh +++ /dev/null @@ -1,2175 +0,0 @@ -//+------------------------------------------------------------------+ -//| ap.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 -#include "complex.mqh" -#include "matrix.mqh" -#include "bitconvert.mqh" -//+------------------------------------------------------------------+ -//| Reverse communication structure | -//+------------------------------------------------------------------+ -struct RCommState - { -public: - int stage; - int ia[]; - bool ba[]; - double ra[]; - al_complex ca[]; - - RCommState(void) { stage=-1; } - ~RCommState(void) { }; - void Copy(RCommState &obj); - }; -//+------------------------------------------------------------------+ -//| Create a copy | -//+------------------------------------------------------------------+ -void RCommState::Copy(RCommState &obj) - { -//--- copy a variable - stage=obj.stage; -//--- copy arrays - ArrayCopy(ia,obj.ia); - ArrayCopy(ba,obj.ba); - ArrayCopy(ra,obj.ra); - ArrayCopy(ca,obj.ca); - } -//+------------------------------------------------------------------+ -//| Internal functions | -//+------------------------------------------------------------------+ -class CAp - { -public: - //--- variable that determines whether an exception happened - static bool exception_happened; - //--- constructor, destructor - CAp(void); - ~CAp(void); - //--- len - static int Len(const int &a[]); - static int Len(const bool &a[]); - static int Len(const double &a[]); - static int Len(const al_complex &a[]); - //--- rows count - static int Rows(const CMatrixInt &a); - static int Rows(const CMatrixDouble &a); - static int Rows(const CMatrixComplex &a); - //--- cols count - static int Cols(const CMatrixInt &a); - static int Cols(const CMatrixDouble &a); - static int Cols(const CMatrixComplex &a); - //--- swap - static void Swap(int &a,int &b); - static void Swap(double &a,double &b); - static void Swap(al_complex &a,al_complex &b); - static void Swap(bool &a[],bool &b[]); - static void Swap(int &a[],int &b[]); - static void Swap(double &a[],double &b[]); - static void Swap(al_complex &a[],al_complex &b[]); - static void Swap(CMatrixInt &a,CMatrixInt &b); - static void Swap(CMatrixDouble &a,CMatrixDouble &b); - static void Swap(CMatrixComplex &a,CMatrixComplex &b); - //--- check assertions - static bool Assert(const bool cond); - static bool Assert(const bool cond,const string s); - //--- determination of accuracy - static int ThresHoldToDPS(const double threshold); - //--- join string - static string StringJoin(const string sep,const string &a[]); - //--- convert to string - static string Format(const al_complex &a,const int dps); - static string Format(const bool &a[]); - static string Format(const int &a[]); - static string Format(const double &a[],const int dps); - static string Format(const al_complex &a[],const int dps); - static string FormatB(const CMatrixInt &a); - static string Format(const CMatrixInt &a); - static string Format(const CMatrixDouble &a,const int dps); - static string Format(const CMatrixComplex &a,const int dps); - //--- work with matrix - static bool IsSymmetric(const CMatrixDouble &a); - static bool IsHermitian(const CMatrixComplex &a); - static bool ForceSymmetric(CMatrixDouble &a); - static bool ForceHermitian(CMatrixComplex &a); - }; -//+------------------------------------------------------------------+ -//| Initialize variable | -//+------------------------------------------------------------------+ -bool CAp::exception_happened=false; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CAp::CAp(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CAp::~CAp(void) - { - - } -//+------------------------------------------------------------------+ -//| Get array lenght | -//+------------------------------------------------------------------+ -static int CAp::Len(const int &a[]) - { - return(ArraySize(a)); - } -//+------------------------------------------------------------------+ -//| Get array lenght | -//+------------------------------------------------------------------+ -static int CAp::Len(const bool &a[]) - { - return(ArraySize(a)); - } -//+------------------------------------------------------------------+ -//| Get array lenght | -//+------------------------------------------------------------------+ -static int CAp::Len(const double &a[]) - { - return(ArraySize(a)); - } -//+------------------------------------------------------------------+ -//| Get array lenght | -//+------------------------------------------------------------------+ -static int CAp::Len(const al_complex &a[]) - { - return(ArraySize(a)); - } -//+------------------------------------------------------------------+ -//| Get rows count | -//+------------------------------------------------------------------+ -static int CAp::Rows(const CMatrixInt &a) - { - return(a.Size()); - } -//+------------------------------------------------------------------+ -//| Get rows count | -//+------------------------------------------------------------------+ -static int CAp::Rows(const CMatrixDouble &a) - { - return(a.Size()); - } -//+------------------------------------------------------------------+ -//| Get rows count | -//+------------------------------------------------------------------+ -static int CAp::Rows(const CMatrixComplex &a) - { - return(a.Size()); - } -//+------------------------------------------------------------------+ -//| Get cols count | -//+------------------------------------------------------------------+ -static int CAp::Cols(const CMatrixInt &a) - { -//--- check - if(a.Size()==0) - return(0); -//--- return result - return(a[0].Size()); - } -//+------------------------------------------------------------------+ -//| Get rows count | -//+------------------------------------------------------------------+ -static int CAp::Cols(const CMatrixDouble &a) - { -//--- check - if(a.Size()==0) - return(0); -//--- return result - return(a[0].Size()); - } -//+------------------------------------------------------------------+ -//| Get rows count | -//+------------------------------------------------------------------+ -static int CAp::Cols(const CMatrixComplex &a) - { -//--- check - if(a.Size()==0) - return(0); -//--- return result - return(a[0].Size()); - } -//+------------------------------------------------------------------+ -//| Swap | -//+------------------------------------------------------------------+ -static void CAp::Swap(int &a,int &b) - { - int t=a; - a=b; - b=t; - } -//+------------------------------------------------------------------+ -//| Swap | -//+------------------------------------------------------------------+ -static void CAp::Swap(double &a,double &b) - { - double t=a; - a=b; - b=t; - } -//+------------------------------------------------------------------+ -//| Swap | -//+------------------------------------------------------------------+ -static void CAp::Swap(al_complex &a,al_complex &b) - { - al_complex t(a.re,a.im); - a=b; - b=t; - } -//+------------------------------------------------------------------+ -//| Swap | -//+------------------------------------------------------------------+ -static void CAp::Swap(bool &a[],bool &b[]) - { -//--- calculation - int na=ArraySize(a); - int nb=ArraySize(b); -//--- create array - bool t[]; - ArrayResizeAL(t,na); -//--- swap - ArrayCopy(t,a); - ArrayResizeAL(a,nb); - ArrayCopy(a,b); - ArrayResizeAL(b,na); - ArrayCopy(b,t); - } -//+------------------------------------------------------------------+ -//| Swap | -//+------------------------------------------------------------------+ -static void CAp::Swap(int &a[],int &b[]) - { -//--- calculation - int na=ArraySize(a); - int nb=ArraySize(b); -//--- create array - int t[]; - ArrayResizeAL(t,na); -//--- swap - ArrayCopy(t,a); - ArrayResizeAL(a,nb); - ArrayCopy(a,b); - ArrayResizeAL(b,na); - ArrayCopy(b,t); - } -//+------------------------------------------------------------------+ -//| Swap | -//+------------------------------------------------------------------+ -static void CAp::Swap(double &a[],double &b[]) - { -//--- calculation - int na=ArraySize(a); - int nb=ArraySize(b); -//--- create array - double t[]; - ArrayResizeAL(t,na); -//--- swap - ArrayCopy(t,a); - ArrayResizeAL(a,nb); - ArrayCopy(a,b); - ArrayResizeAL(b,na); - ArrayCopy(b,t); - } -//+------------------------------------------------------------------+ -//| Swap | -//+------------------------------------------------------------------+ -static void CAp::Swap(al_complex &a[],al_complex &b[]) - { -//--- calculation - int na=ArraySize(a); - int nb=ArraySize(b); -//--- create array - al_complex t[]; - ArrayResizeAL(t,na); -//--- swap - ArrayCopy(t,a); - ArrayResizeAL(a,nb); - ArrayCopy(a,b); - ArrayResizeAL(b,na); - ArrayCopy(b,t); - } -//+------------------------------------------------------------------+ -//| Swap | -//+------------------------------------------------------------------+ -static void CAp::Swap(CMatrixInt &a,CMatrixInt &b) - { -//--- create matrix - CMatrixInt t; -//--- swap - t=a; - a=b; - b=t; - } -//+------------------------------------------------------------------+ -//| Swap | -//+------------------------------------------------------------------+ -static void CAp::Swap(CMatrixDouble &a,CMatrixDouble &b) - { -//--- create matrix - CMatrixDouble t; -//--- swap - t=a; - a=b; - b=t; - } -//+------------------------------------------------------------------+ -//| Swap | -//+------------------------------------------------------------------+ -static void CAp::Swap(CMatrixComplex &a,CMatrixComplex &b) - { -//--- create matrix - CMatrixComplex t; -//--- swap - t=a; - a=b; - b=t; - } -//+------------------------------------------------------------------+ -//| Check assertions | -//+------------------------------------------------------------------+ -static bool CAp::Assert(const bool cond) - { - return(Assert(cond,"ALGLIB: assertion failed")); - } -//+------------------------------------------------------------------+ -//| Check assertions | -//+------------------------------------------------------------------+ -static bool CAp::Assert(const bool cond,const string s) - { -//--- check - if(cond==0) - { - Print(__FUNCTION__+" "+s); - exception_happened=true; - return(false); - } -//--- the assertion is true - return(true); - } -//+------------------------------------------------------------------+ -//| returns dps (digits-of-precision) value corresponding to | -//| threshold. | -//| dps(0.9) = dps(0.5) = dps(0.1) = 0 | -//| dps(0.09) = dps(0.05) = dps(0.01) = 1 | -//| and so on | -//+------------------------------------------------------------------+ -static int CAp::ThresHoldToDPS(const double threshold) - { -//--- initialization - int res=0; - double t=1.0; - for(res=0;t/10>threshold*(1+1E-10);res++) - t/=10; -//--- return result - return(res); - } -//+------------------------------------------------------------------+ -//| Concatenation | -//+------------------------------------------------------------------+ -static string CAp::StringJoin(const string sep,const string &a[]) - { - int size=ArraySize(a); -//--- check - if(size==0) - { - Print(__FUNCTION__+": array size error"); - return(NULL); - } -//--- concatenation - string res=""; - for(int i=0;i=0) fmt="f"; - else fmt="e"; -//--- get sign of the imaginary part - string sign; - if(a.im>=0) sign="+"; - else sign="-"; -//--- converting - int d=(int)MathAbs(dps); - string fmtx=StringFormat(".%d"+fmt,d); - string fmty=StringFormat(".%d"+fmt,d); -//--- get result - string res=StringFormat("%"+fmtx,a.re)+sign+ - StringFormat("%"+fmty,MathAbs(a.im))+"i"; - StringReplace(res,",","."); -//--- return result - return(res); - } -//+------------------------------------------------------------------+ -//| Prints formatted array | -//+------------------------------------------------------------------+ -static string CAp::Format(const bool &a[]) - { - int size=ArraySize(a); -//--- check - if(size==0) - { - Print(__FUNCTION__+": array size error"); - return(NULL); - } -//--- converting - string result[]; - ArrayResizeAL(result,size); - for(int i=0;i=0) sfmt="f"; - else sfmt="e"; -//--- converting - int d=(int)MathAbs(dps); - string fmt=StringFormat(".%d"+sfmt,d); - for(int i=0;i=0) fmt="f"; - else fmt="e"; -//--- converting - int d=(int)MathAbs(dps); - string fmtx=StringFormat(".%d"+fmt,d); - string fmty=StringFormat(".%d"+fmt,d); - string sign; - for(int i=0;i=0) sign="+"; - else sign="-"; - //--- fill result - result[i]=StringFormat("%"+fmtx,a[i].re)+sign+ - StringFormat("%"+fmty,MathAbs(a[i].im))+"i"; - StringReplace(result[i],",","."); - } -//--- return result - return("{"+StringJoin(",",result)+"}"); - } -//+------------------------------------------------------------------+ -//| Prints formatted matrix | -//+------------------------------------------------------------------+ -static string CAp::FormatB(const CMatrixInt &a) - { - int m=a.Size(); -//--- check - if(m==0) - { - Print(__FUNCTION__+": array size error"); - return(NULL); - } - int n=a[0].Size(); -//--- check - if(n==0) - { - Print(__FUNCTION__+": array size error"); - return(NULL); - } -//--- prepare arrays - bool line[]; - string result[]; - ArrayResizeAL(line,n); - ArrayResizeAL(result,m); -//--- converting - for(int i=0;iK*N) - if(!CAp::Assert(n>0,__FUNCTION__+": N<=0!")) - return(-1); -//--- check - if(!CAp::Assert(n=RNDBaseMax-1!")) - return(-1); -//--- initialization - mx=m_HQRndMax-1-(m_HQRndMax-1)%n; - do - result=HQRndIntegerBase(state)-1; - while(result>=mx); -//--- get result - result=result%n; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Random number generator: normal numbers | -//| This function generates one random number from normal | -//| distribution. | -//| Its performance is equal to that of HQRNDNormal2() | -//| State structure must be initialized with HQRNDRandomize() or | -//| HQRNDSeed(). | -//+------------------------------------------------------------------+ -static double CHighQualityRand::HQRndNormal(CHighQualityRandState &state) - { -//--- create variables - double v1=0; - double v2=0; -//--- function call - HQRndNormal2(state,v1,v2); -//--- return result - return(v1); - } -//+------------------------------------------------------------------+ -//| Random number generator: random X and Y such that X^2+Y^2=1 | -//| State structure must be initialized with HQRNDRandomize() or | -//| HQRNDSeed(). | -//+------------------------------------------------------------------+ -static void CHighQualityRand::HQRndUnit2(CHighQualityRandState &state, - double &x,double &y) - { -//--- create variables - double v=0; - double mx=0; - double mn=0; -//--- initialization - x=0; - y=0; -//--- function call - do - HQRndNormal2(state,x,y); - while(!(x!=0.0 || y!=0.0)); -//--- change values - mx=MathMax(MathAbs(x),MathAbs(y)); - mn=MathMin(MathAbs(x),MathAbs(y)); - v=mx*MathSqrt(1+CMath::Sqr(mn/mx)); -//--- get result - x=x/v; - y=y/v; - } -//+------------------------------------------------------------------+ -//| Random number generator: normal numbers | -//| This function generates two independent random numbers from | -//| normal distribution. Its performance is equal to that of | -//| HQRNDNormal() | -//| State structure must be initialized with HQRNDRandomize() or | -//| HQRNDSeed(). | -//+------------------------------------------------------------------+ -static void CHighQualityRand::HQRndNormal2(CHighQualityRandState &state, - double &x1,double &x2) - { -//--- create variables - double u=0; - double v=0; - double s=0; -//--- initialization - x1=0; - x2=0; -//--- cycle - while(true) - { - u=2*HQRndUniformR(state)-1; - v=2*HQRndUniformR(state)-1; - s=CMath::Sqr(u)+CMath::Sqr(v); - //--- check - if(s>0.0 && s<1.0) - { - //--- two Sqrt's instead of one to - //--- avoid overflow when S is too small - s=MathSqrt(-(2*MathLog(s)))/MathSqrt(s); - x1=u*s; - x2=v*s; - //--- exit the function - return; - } - } - } -//+------------------------------------------------------------------+ -//| Random number generator: exponential distribution | -//| State structure must be initialized with HQRNDRandomize() or | -//| HQRNDSeed(). | -//+------------------------------------------------------------------+ -static double CHighQualityRand::HQRndExponential(CHighQualityRandState &state, - const double lambdav) - { -//--- check - if(!CAp::Assert(lambdav>0.0,__FUNCTION__+": LambdaV<=0!")) - return(EMPTY_VALUE); -//--- return result - return(-(MathLog(HQRndUniformR(state))/lambdav)); - } -//+------------------------------------------------------------------+ -//| L'Ecuyer, Efficient and portable combined random number | -//| generators | -//+------------------------------------------------------------------+ -static int CHighQualityRand::HQRndIntegerBase(CHighQualityRandState &state) - { -//--- create variables - int result=0; - int k=0; -//--- check - if(!CAp::Assert(state.m_magicv==m_HQRndMagic,__FUNCTION__+": State is not correctly initialized!")) - return(-1); -//--- initialization - k=state.m_s1/53668; - state.m_s1=40014*(state.m_s1-k*53668)-k*12211; -//--- check - if(state.m_s1<0) - state.m_s1=state.m_s1+2147483563; -//--- change values - k=state.m_s2/52774; - state.m_s2=40692*(state.m_s2-k*52774)-k*3791; -//--- check - if(state.m_s2<0) - state.m_s2=state.m_s2+2147483399; -//--- Result - result=state.m_s1-state.m_s2; -//--- check - if(result<1) - result=result+2147483562; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Math functions | -//+------------------------------------------------------------------+ -class CMath - { -public: - //--- class variables - static bool m_first_call; - static double m_last; - static CHighQualityRandState m_state; - //--- machine constants - static const double m_machineepsilon; - static const double m_maxrealnumber; - static const double m_minrealnumber; - //--- constructor, destructor - CMath(void); - ~CMath(void); - //--- methods - static bool IsFinite(const double d); - static double RandomReal(void); - static int RandomInteger(const int n); - static double Sqr(const double x) { return(x*x); } - static double AbsComplex(const al_complex &z); - static double AbsComplex(const double r); - static al_complex Conj(const al_complex &z); - static al_complex Csqr(const al_complex &z); - }; -//+------------------------------------------------------------------+ -//| Initialize class constants | -//+------------------------------------------------------------------+ -const double CMath::m_machineepsilon=5E-16; -const double CMath::m_maxrealnumber=1E300; -const double CMath::m_minrealnumber=1E-300; -bool CMath::m_first_call=true; -double CMath::m_last=0.0; -CHighQualityRandState CMath::m_state; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMath::CMath(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMath::~CMath(void) - { - - } -//+------------------------------------------------------------------+ -//| Check on +-inf | -//+------------------------------------------------------------------+ -static bool CMath::IsFinite(const double d) - { -//--- return result - return(MathIsValidNumber(d)); - } -//+------------------------------------------------------------------+ -//| Random real value [0,1) | -//+------------------------------------------------------------------+ -static double CMath::RandomReal(void) - { -//--- create variable - double result; -//--- check - if(m_first_call) - { - CHighQualityRand::HQRndSeed(1+MathRand(),1+MathRand(),m_state); - m_first_call=false; - } -//--- get value - result=CHighQualityRand::HQRndUniformR(m_state); -//--- check - if(result==m_last) - { - m_first_call=true; - return(RandomReal()); - } -//--- change value - m_last=result; -//--- return result - return(CHighQualityRand::HQRndUniformR(m_state)); - } -//+------------------------------------------------------------------+ -//| Random integer value | -//+------------------------------------------------------------------+ -static int CMath::RandomInteger(const int n) - { -//--- check - if(m_first_call) - { - CHighQualityRand::HQRndSeed(1+MathRand(),1+MathRand(),m_state); - m_first_call=false; - } -//--- check and return result - if(n>=CHighQualityRand::m_HQRndM1-1) - return(CHighQualityRand::HQRndUniformI(m_state,CHighQualityRand::m_HQRndM1-2)); - else - return(CHighQualityRand::HQRndUniformI(m_state,n)); - } -//+------------------------------------------------------------------+ -//| The absolute value of a complex number | -//+------------------------------------------------------------------+ -static double CMath::AbsComplex(const al_complex &z) - { -//--- initialization - double w=0.0; - double v=0.0; - double xabs=MathAbs(z.re); - double yabs=MathAbs(z.im); -//--- check - if(xabs>yabs) w=xabs; - else w=yabs; -//--- check - if(xabsyabs) w=xabs; - else w=yabs; -//--- check - if(xabs63) - return('?'); -//--- return result - return(_sixbits2char_tbl[v]); - } -//+------------------------------------------------------------------+ -//| This function converts character to six-bit value (from 0 to 63).| -//| This function is inverse of ae_sixbits2char() | -//| If c is not correct character, this function returns -1. | -//+------------------------------------------------------------------+ -static int CSerializer::Char2SixBits(const char c) - { -//--- check - if(c>=0 && c<127) - return(_char2sixbits_tbl[c]); -//--- return result - return(-1); - } -//+------------------------------------------------------------------+ -//| This function converts three bytes (24 bits) to four six-bit | -//| values (24 bits again). | -//| src array | -//| src_offs offset of three-bytes chunk | -//| dst array for ints | -//| dst_offs offset of four-ints chunk | -//+------------------------------------------------------------------+ -static void CSerializer::ThreeBytes2FourSixBits(uchar &src[],const int src_offs, - int &dst[],const int dst_offs) - { -//--- get bits - dst[dst_offs+0]=src[src_offs+0] & 0x3F; - dst[dst_offs+1]=(src[src_offs+0]>>6) | ((src[src_offs+1]&0x0F)<<2); - dst[dst_offs+2]=(src[src_offs+1]>>4) | ((src[src_offs+2]&0x03)<<4); - dst[dst_offs+3]=src[src_offs+2]>>2; - } -//+------------------------------------------------------------------+ -//| This function converts four six-bit values (24 bits) to three | -//| bytes (24 bits again). | -//| src pointer to four ints | -//| src_offs offset of the chunk | -//| dst pointer to three bytes | -//| dst_offs offset of the chunk | -//+------------------------------------------------------------------+ -static void CSerializer::FourSixBits2ThreeBytes(int &src[],const int src_offs, - uchar &dst[],const int dst_offs) - { -//--- get bytes - dst[dst_offs+0]=(uchar)(src[src_offs+0] | ((src[src_offs+1]&0x03)<<6)); - dst[dst_offs+1]=(uchar)((src[src_offs+1]>>2) | ((src[src_offs+2]&0x0F)<<4)); - dst[dst_offs+2]=(uchar)((src[src_offs+2]>>4) | (src[src_offs+3]<<2)); - } -//+------------------------------------------------------------------+ -//| This function serializes boolean value into buffer | -//| v boolean value to be serialized | -//| buf buffer, at least 11 characters wide | -//| offs offset in the buffer | -//| after return(from this function, offs points to the char's past | -//| the value being read. | -//+------------------------------------------------------------------+ -static void CSerializer::Bool2Str(const bool v,char &buf[],int &offs) - { -//--- create variables - char c; - int i; -//--- check - if(v) - c='1'; - else - c='0'; -//--- copy c - for(i=0;i=m_ser_entry_length) - { - Print(__FUNCTION__+" "+emsg); - //--- return result - return(-1); - } - sixbits[sixbitsread]=d; - sixbitsread++; - offs++; - } -//--- check - if(sixbitsread==0) - { - Print(__FUNCTION__+" "+emsg); - //--- return result - return(-1); - } - for(i=sixbitsread;i<12;i++) - sixbits[i]=0; -//--- function call - FourSixBits2ThreeBytes(sixbits,0,bytes,0); -//--- function call - FourSixBits2ThreeBytes(sixbits,4,bytes,3); -//--- function call - FourSixBits2ThreeBytes(sixbits,8,bytes,6); -//--- check - if((bytes[sizeof(int)-1]&0x80)!=0) - c=(uchar)0xFF; - else - c=(uchar)0x00; - for(i=sizeof(int);i<8;i++) - //--- check - if(bytes[i]!=c) - { - Print(__FUNCTION__+" "+emsg3264); - //--- return result - return(-1); - } -//--- copy - for(i=0;i=m_ser_entry_length) - { - Print(__FUNCTION__+"emsg"); - //--- return result - return(EMPTY_VALUE); - } - sixbits[sixbitsread]=d; - sixbitsread++; - offs++; - } -//--- check - if(sixbitsread!=m_ser_entry_length) - { - Print(__FUNCTION__+"emsg"); - //--- return result - return(EMPTY_VALUE); - } - sixbits[m_ser_entry_length]=0; -//--- function call - FourSixBits2ThreeBytes(sixbits,0,bytes,0); -//--- function call - FourSixBits2ThreeBytes(sixbits,4,bytes,3); -//--- function call - FourSixBits2ThreeBytes(sixbits,8,bytes,6); -//--- copy - for(i=0;i0 && old0 && old0 && old0 && old0 && old0 && old=0) - bytes[i]=0; - else - bytes[i]=255; - } -//--- initialization - q=-1; - r=-1; - i=3; - div=256*256*256; -//--- check - if(d<0) - x=~d; - else - x=d; -//--- converting number - while(i!=-1) - { - //--- quotient - q=x/div; - //--- remainder of division - r=x%div; - //--- get byte - if(d>=0) - bytes[i]+=(uchar)q; - else - bytes[i]-=(uchar)q; - //--- the next iteration is reduced divisor - x=r; - div=div/256; - i--; - } - } -//+------------------------------------------------------------------+ -//| Converting double to a byte array | -//+------------------------------------------------------------------+ -static void BitConverter::GetBytes(const double d,uchar &bytes[]) - { -//--- module - double abs_d=MathAbs(d); -//--- number without its fractional - double floor_d=MathFloor(abs_d); -//--- fractional part - double fractional_d=abs_d-floor_d; -//--- variable will store the degree - int power; -//--- exponent shift - double exp_shift; -//--- create variables - int k; - int j; - uchar u; - double step; - double f; -//--- abs_d as bits - bool abs_d_to_bitArray[]; -//--- d as bits in format IEEE 754 - bool d_to_bitArray[]; -//--- allocation - ArrayResizeAL(d_to_bitArray,64); - ArrayResizeAL(bytes,8); -//--- initialization - power=0; -//--- for integer part - while(1) - { - //--- if the number is less than or equal floor_d, we increase the degree - //--- if 2^power > floor_d, then maximal number < floor_d - it 2^(power-1) - if(floor_d>=MathPow(2,power)) - power++; - else - break; - } -//--- get power-1 - power--; -//--- if power=-1, then floor_d=0 -//--- find a negative power for the fractional part - if(power==-1) - { - power=0; - while(1) - { - //--- the same principle as above - if(fractional_dabs_d) - { - //--- if abs_d < f - this bit is zero - ArrayResizeAL(abs_d_to_bitArray,j+1); - abs_d_to_bitArray[j]=0; - j++; - step-=1; - } - else - { - //--- if abs_d >= f, then this bit is equal one - //--- reduction abs_d - abs_d-=f; - ArrayResizeAL(abs_d_to_bitArray,j+1); - abs_d_to_bitArray[j]=1; - j++; - step-=1; - } - } -//--- according to IEEE 754, -//--- zero bit determines sign of the number, 0 -> '+', 1 -> '-'. - if(d>=0) - d_to_bitArray[0]=0; - else - d_to_bitArray[0]=1; -//--- offset input - exp_shift=1023+power; -//--- bits from the first and 11 are reserved for the shifted exponential - j=1; - for(int i=10;i>=0;i--) - { - if(MathPow(2,i)>exp_shift) - d_to_bitArray[j]=0; - else - { - d_to_bitArray[j]=1; - //--- reduction - exp_shift-=MathPow(2,i); - } - j++; - } -//--- Get the length of the array of the binary representation of abs_d - k=ArraySize(abs_d_to_bitArray); - j=1; -//--- Bits from 12 to 63 are filled with binary representation of abs_b -//--- the first element abs_d_to_bitArray is always 1 - for(int i=12;i<64;i++) - { - if(j=0;i--) - { - d+=bytes[i]*mul; - mul=mul/256; - } -//--- return result - return(d); - } -//+------------------------------------------------------------------+ -//| Converting byte array to a double | -//+------------------------------------------------------------------+ -static double BitConverter::ToDouble(uchar &bytes[]) - { -//--- create variables - int s; -//--- exponent shift - int e=0; -//--- mantissa - double m=0; -//--- array of bits in IEEE 754 - bool bits[]; - ArrayResizeAL(bits,64); -//--- get array of bits from array of bytes - for(int i=0;i<8;i++) - { - for(int j=7;j>=0;j--) - { - //--- if 2 in power >, bits[i*8+j]=0, else bits[i*8+j]=0 - if(MathPow(2,j)>bytes[i]) - bits[i*8+j]=0; - else - { - bits[i*8+j]=1; - //--- reduction - bytes[i]-=(uchar)MathPow(2,j); - } - } - } -//--- search bits with 1 - bool allzero=true; - for(int i=0;i<64;i++) - if(bits[i]==1) - allzero=false; -//--- if all bits are 0, then number is 0 - if(allzero==true) - return(0.0); -//--- reverse array - ArrayReverse(bits); -//--- s-the first bit, determines sign of the number - s=bits[0]; -//--- calculation exponent shift - for(int i=10;i>=0;i--) - e+=(int)(bits[11-i]*MathPow(2,i)); -//--- get mantissa - for(int i=0;i<52;i++) - m+=bits[12+i]*MathPow(2,-1-i); -//--- return result - return(MathPow(-1,s)*MathPow(2,e-1023)*(1+m)); - } -//+------------------------------------------------------------------+ -//| Byte ordering (forward, backward) | -//+------------------------------------------------------------------+ -static bool BitConverter::IsLittleEndian(void) - { -//--- forward - return(true); - } -//+------------------------------------------------------------------+ -//| Array reverse (uchar) | -//+------------------------------------------------------------------+ -void ArrayReverse(uchar &array[]) - { -//--- size - int size=ArraySize(array); -//--- half of size - int half=size/2; -//--- create a variable - uchar temp; -//--- reverse - for(int i=0;i0 - if(x>0) - return(1); -//--- if ?==0 - if(x==0) - return(0); -//--- ?<0 - return(-1); - } -#ifndef __MQL5__ -//+------------------------------------------------------------------+ -//| Hyperbolic sine | -//+------------------------------------------------------------------+ -double MathSinh(const double x) - { -//--- return result - return((MathPow(M_E,x)-MathPow(M_E,-x))/2); - } -//+------------------------------------------------------------------+ -//| Hyperbolic cosine | -//+------------------------------------------------------------------+ -double MathCosh(const double x) - { -//--- return result - return((MathPow(M_E,x)+MathPow(M_E,-x))/2); - } -//+------------------------------------------------------------------+ -//| Hyperbolic tangent | -//+------------------------------------------------------------------+ -double MathTanh(const double x) - { -//--- return result - return(MathSinh(x)/MathCosh(x)); - } -#endif -//+------------------------------------------------------------------+ -//| Structure stores a variable of type double | -//+------------------------------------------------------------------+ -union UDoubleValue - { - double value; - long bits; - - UDoubleValue(double dbl):value(dbl) { } - UDoubleValue(long bit_value):bits(bit_value) { } - }; -//+------------------------------------------------------------------+ -//| Work with infinity and NaN | -//+------------------------------------------------------------------+ -class CInfOrNaN - { -public: - //--- constructor, destructor - CInfOrNaN(void); - ~CInfOrNaN(void); - //--- checks - static bool IsPositiveInfinity(const double x); - static bool IsNegativeInfinity(const double x); - static bool IsInfinity(const double x); - static bool IsNaN(const double x); - //--- generation values - static double PositiveInfinity(void); - static double NegativeInfinity(void); - static double NaN(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CInfOrNaN::CInfOrNaN(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CInfOrNaN::~CInfOrNaN(void) - { - - } -//+------------------------------------------------------------------+ -//| Check for +inf | -//+------------------------------------------------------------------+ -static bool CInfOrNaN::IsPositiveInfinity(const double x) - { - UDoubleValue val=x; -//--- check - return(val.bits==0x7FF0000000000000); - } -//+------------------------------------------------------------------+ -//| Check for -inf | -//+------------------------------------------------------------------+ -static bool CInfOrNaN::IsNegativeInfinity(const double x) - { - UDoubleValue val=x; -//--- check - return(val.bits==0xFFF0000000000000); - } -//+------------------------------------------------------------------+ -//| Check for +-inf | -//+------------------------------------------------------------------+ -static bool CInfOrNaN::IsInfinity(const double x) - { - UDoubleValue val=x; -//--- check - return(val.bits==0x7FF0000000000000 || val.bits==0xFFF0000000000000); - } -//+------------------------------------------------------------------+ -//| Check for NaN | -//+------------------------------------------------------------------+ -static bool CInfOrNaN::IsNaN(const double x) - { -//--- check - if(MathIsValidNumber(x)) - { - //--- is valid number - return(false); - } -//--- check - if(IsInfinity(x)) - { - //--- +-inf - return(false); - } -//--- is NaN - return(true); - } -//+------------------------------------------------------------------+ -//| Return +inf | -//+------------------------------------------------------------------+ -static double CInfOrNaN::PositiveInfinity(void) - { - UDoubleValue val(0x7FF0000000000000); - return(val.value); - } -//+------------------------------------------------------------------+ -//| Return -inf | -//+------------------------------------------------------------------+ -static double CInfOrNaN::NegativeInfinity(void) - { - UDoubleValue val(0xFFF0000000000000); - return(val.value); - } -//+------------------------------------------------------------------+ -//| Return NaN | -//+------------------------------------------------------------------+ -static double CInfOrNaN::NaN(void) - { - UDoubleValue val(0x7FFFFFFFFFFFFFFF); - return(val.value); - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Alglib/complex.mqh b/Include/Math/Alglib/complex.mqh deleted file mode 100644 index 9d7cd7f..0000000 --- a/Include/Math/Alglib/complex.mqh +++ /dev/null @@ -1,358 +0,0 @@ -//+------------------------------------------------------------------+ -//| complex.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. | -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ -//| Complex numbers | -//+------------------------------------------------------------------+ -struct al_complex - { -public: - double re; // real part - double im; // imaginary part - -public: - al_complex(void); - al_complex(const double x); - al_complex(const double x,const double y); - ~al_complex(void); - //--- operations - void Copy(const al_complex &rhs); - bool Eq(const al_complex &lhs,const al_complex &rhs); - bool NotEq(const al_complex &lhs,const al_complex &rhs); - al_complex Add(const al_complex &lhs,const al_complex &rhs); - al_complex Sub(const al_complex &lhs,const al_complex &rhs); - al_complex Mul(const al_complex &lhs,const al_complex &rhs); - al_complex Div(const al_complex &lhs,const al_complex &rhs); - al_complex Conjugate(void); - //--- overloading - void operator=(const double rhs); - void operator=(const al_complex &rhs); - void operator+=(const al_complex &rhs); - void operator-=(const al_complex &rhs); - bool operator==(const al_complex &rhs); - bool operator==(const double rhs); - bool operator!=(const al_complex &rhs); - bool operator!=(const double rhs); - al_complex operator+(const al_complex &rhs); - al_complex operator+(const double rhs); - al_complex operator+(void); - al_complex operator-(const al_complex &rhs); - al_complex operator-(const double rhs); - al_complex operator-(void); - al_complex operator*(const al_complex &rhs); - al_complex operator*(const double rhs); - al_complex operator/(const al_complex &rhs); - al_complex operator/(const double rhs); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -al_complex::al_complex(void): re(0),im(0) - { - - } -//+------------------------------------------------------------------+ -//| Constructor with one parameter | -//+------------------------------------------------------------------+ -al_complex::al_complex(const double x): re(x),im(0) - { - - } -//+------------------------------------------------------------------+ -//| Constructor with two parameters | -//+------------------------------------------------------------------+ -al_complex::al_complex(const double x,const double y): re(x),im(y) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -al_complex::~al_complex(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy complex | -//+------------------------------------------------------------------+ -void al_complex::Copy(const al_complex &rhs) - { - re=rhs.re; - im=rhs.im; - } -//+------------------------------------------------------------------+ -//| Comparison (==) | -//+------------------------------------------------------------------+ -bool al_complex::Eq(const al_complex &lhs,const al_complex &rhs) - { -//--- comparison - if(lhs.re==rhs.re && lhs.im==rhs.im) - return(true); -//--- numbers are not equal - return(false); - } -//+------------------------------------------------------------------+ -//| Comparison (!=) | -//+------------------------------------------------------------------+ -bool al_complex::NotEq(const al_complex &lhs,const al_complex &rhs) - { -//--- comparison - if(lhs.re!=rhs.re || lhs.im!=rhs.im) - return(true); -//--- numbers are equal - return(false); - } -//+------------------------------------------------------------------+ -//| Sum | -//+------------------------------------------------------------------+ -al_complex al_complex::Add(const al_complex &lhs,const al_complex &rhs) - { - al_complex res; -//--- sum - res.re=lhs.re+rhs.re; - res.im=lhs.im+rhs.im; -//--- return result - return(res); - } -//+------------------------------------------------------------------+ -//| Subtraction | -//+------------------------------------------------------------------+ -al_complex al_complex::Sub(const al_complex &lhs,const al_complex &rhs) - { - al_complex res; -//--- subtraction - res.re=lhs.re-rhs.re; - res.im=lhs.im-rhs.im; -//--- return result - return(res); - } -//+------------------------------------------------------------------+ -//| Multiplication | -//+------------------------------------------------------------------+ -al_complex al_complex::Mul(const al_complex &lhs,const al_complex &rhs) - { - al_complex res; -//--- multiplication - res.re=lhs.re*rhs.re-lhs.im*rhs.im; - res.im=lhs.re*rhs.im+lhs.im*rhs.re; -//--- return result - return(res); - } -//+------------------------------------------------------------------+ -//| Division | -//+------------------------------------------------------------------+ -al_complex al_complex::Div(const al_complex &lhs,const al_complex &rhs) - { -//--- empty complex value - al_complex res(EMPTY_VALUE,EMPTY_VALUE); -//--- check - if(rhs.re==0 && rhs.im==0) - { - Print(__FUNCTION__+": number is zero"); - return(res); - } -//--- create variables - double e; - double f; -//--- division - if(MathAbs(rhs.im)0" means that we have classification task. | -//| "NClasses<0" means regression task with -NClasses real | -//| outputs. | -//| NOTES(2): | -//| rms. avg, avg.rel errors for classification tasks are | -//| interpreted as errors in posterior probabilities with | -//| respect to probabilities given by training/test set. | -//+------------------------------------------------------------------+ -static void CBdSS::DSErrAllocate(const int nclasses,double &buf[]) - { -//--- allocation - ArrayResizeAL(buf,8); -//--- initialization - buf[0]=0; - buf[1]=0; - buf[2]=0; - buf[3]=0; - buf[4]=0; - buf[5]=nclasses; - buf[6]=0; - buf[7]=0; - } -//+------------------------------------------------------------------+ -//| See DSErrAllocate for comments on this routine. | -//+------------------------------------------------------------------+ -static void CBdSS::DSErrAccumulate(double &buf[],double &y[],double &desiredy[]) - { -//--- create variables - int nclasses=0; - int nout=0; - int offs=0; - int mmax=0; - int rmax=0; - int j=0; - double v=0; - double ev=0; -//--- initialization - offs=5; - nclasses=(int)MathRound(buf[offs]); -//--- check - if(nclasses>0) - { - //--- Classification - rmax=(int)MathRound(desiredy[0]); - mmax=0; - //--- initialization - for(j=1;j<=nclasses-1;j++) - { - //--- check - if(y[j]>y[mmax]) - mmax=j; - } - //--- check - if(mmax!=rmax) - buf[0]=buf[0]+1; - //--- check - if(y[rmax]>0.0) - buf[1]=buf[1]-MathLog(y[rmax]); - else - buf[1]=buf[1]+MathLog(CMath::m_maxrealnumber); - //--- calculation - for(j=0;j<=nclasses-1;j++) - { - v=y[j]; - //--- check - if(j==rmax) - ev=1; - else - ev=0; - //--- change values - buf[2]=buf[2]+CMath::Sqr(v-ev); - buf[3]=buf[3]+MathAbs(v-ev); - //--- check - if(ev!=0.0) - { - buf[4]=buf[4]+MathAbs((v-ev)/ev); - buf[offs+2]=buf[offs+2]+1; - } - } - //--- change value - buf[offs+1]=buf[offs+1]+1; - } - else - { - //--- Regression - nout=-nclasses; - rmax=0; - //--- initialization - for(j=1;j<=nout-1;j++) - { - //--- check - if(desiredy[j]>desiredy[rmax]) - rmax=j; - } - //--- initialization - mmax=0; - for(j=1;j<=nout-1;j++) - { - //--- check - if(y[j]>y[mmax]) - mmax=j; - } - //--- check - if(mmax!=rmax) - buf[0]=buf[0]+1; - //--- calculation - for(j=0;j<=nout-1;j++) - { - //--- change values - v=y[j]; - ev=desiredy[j]; - buf[2]=buf[2]+CMath::Sqr(v-ev); - buf[3]=buf[3]+MathAbs(v-ev); - //--- check - if(ev!=0.0) - { - buf[4]=buf[4]+MathAbs((v-ev)/ev); - buf[offs+2]=buf[offs+2]+1; - } - } - //--- change value - buf[offs+1]=buf[offs+1]+1; - } - } -//+------------------------------------------------------------------+ -//| See DSErrAllocate for comments on this routine. | -//+------------------------------------------------------------------+ -static void CBdSS::DSErrFinish(double &buf[]) - { -//--- create variables - int nout=0; - int offs=0; -//--- initialization - offs=5; - nout=(int)(MathAbs((int)MathRound(buf[offs]))); -//--- check - if(buf[offs+1]!=0.0) - { - //--- change values - buf[0]=buf[0]/buf[offs+1]; - buf[1]=buf[1]/buf[offs+1]; - buf[2]=MathSqrt(buf[2]/(nout*buf[offs+1])); - buf[3]=buf[3]/(nout*buf[offs+1]); - } -//--- check - if(buf[offs+2]!=0.0) - buf[4]=buf[4]/buf[offs+2]; - } -//+------------------------------------------------------------------+ -//| Normalize | -//+------------------------------------------------------------------+ -static void CBdSS::DSNormalize(CMatrixDouble &xy,const int npoints, - const int nvars,int &info,double &means[], - double &sigmas[]) - { -//--- create variables - int i=0; - int j=0; - double mean=0; - double variance=0; - double skewness=0; - double kurtosis=0; - int i_=0; -//--- create array - double tmp[]; -//--- initialization - info=0; -//--- Test parameters - if(npoints<=0 || nvars<1) - { - info=-1; - return; - } -//--- change value - info=1; -//--- Standartization - ArrayResizeAL(means,nvars); - ArrayResizeAL(sigmas,nvars); - ArrayResizeAL(tmp,npoints); -//--- calculation - for(j=0;j<=nvars-1;j++) - { - //--- copy - for(i_=0;i_<=npoints-1;i_++) - tmp[i_]=xy[i_][j]; - //--- function call - CBaseStat::SampleMoments(tmp,npoints,mean,variance,skewness,kurtosis); - //--- change values - means[j]=mean; - sigmas[j]=MathSqrt(variance); - //--- check - if(sigmas[j]==0.0) - sigmas[j]=1; - //--- change values - for(i=0;i<=npoints-1;i++) - xy[i].Set(j,(xy[i][j]-means[j])/sigmas[j]); - } - } -//+------------------------------------------------------------------+ -//| Normalize | -//+------------------------------------------------------------------+ -static void CBdSS::DSNormalizeC(CMatrixDouble &xy,const int npoints, - const int nvars,int &info,double &means[], - double &sigmas[]) - { -//--- create variables - int j=0; - double mean=0; - double variance=0; - double skewness=0; - double kurtosis=0; - int i_=0; -//--- create array - double tmp[]; -//--- initialization - info=0; -//--- Test parameters - if(npoints<=0 || nvars<1) - { - info=-1; - return; - } -//--- change value - info=1; -//--- Standartization - ArrayResizeAL(means,nvars); - ArrayResizeAL(sigmas,nvars); - ArrayResizeAL(tmp,npoints); - for(j=0;j<=nvars-1;j++) - { - //--- copy - for(i_=0;i_<=npoints-1;i_++) - tmp[i_]=xy[i_][j]; - //--- function call - CBaseStat::SampleMoments(tmp,npoints,mean,variance,skewness,kurtosis); - //--- change values - means[j]=mean; - sigmas[j]=MathSqrt(variance); - //--- check - if(sigmas[j]==0.0) - sigmas[j]=1; - } - } -//+------------------------------------------------------------------+ -//| Method | -//+------------------------------------------------------------------+ -static double CBdSS::DSGetMeanMindIstance(CMatrixDouble &xy,const int npoints, - const int nvars) - { -//--- create variables - double result=0; - int i=0; - int j=0; - double v=0; - int i_=0; -//--- creating arrays - double tmp[]; - double tmp2[]; -//--- Test parameters - if(npoints<=0 || nvars<1) - return(0); -//--- Process - ArrayResizeAL(tmp,npoints); - for(i=0;i<=npoints-1;i++) - tmp[i]=CMath::m_maxrealnumber; -//--- allocation - ArrayResizeAL(tmp2,nvars); - for(i=0;i<=npoints-1;i++) - { - for(j=i+1;j<=npoints-1;j++) - { - //--- calculation - for(i_=0;i_<=nvars-1;i_++) - tmp2[i_]=xy[i][i_]; - for(i_=0;i_<=nvars-1;i_++) - tmp2[i_]=tmp2[i_]-xy[j][i_]; - v=0.0; - for(i_=0;i_<=nvars-1;i_++) - v+=tmp2[i_]*tmp2[i_]; - //--- change values - v=MathSqrt(v); - tmp[i]=MathMin(tmp[i],v); - tmp[j]=MathMin(tmp[j],v); - } - } -//--- get result - result=0; - for(i=0;i<=npoints-1;i++) - result=result+tmp[i]/npoints; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Method | -//+------------------------------------------------------------------+ -static void CBdSS::DSTie(double &a[],const int n,int &ties[],int &tiecount, - int &p1[],int &p2[]) - { -//--- create variables - int i=0; - int k=0; -//--- create array - int tmp[]; -//--- initialization - tiecount=0; -//--- Special case - if(n<=0) - { - tiecount=0; - return; - } -//--- Sort A - CTSort::TagSort(a,n,p1,p2); -//--- Process ties - tiecount=1; - for(i=1;i<=n-1;i++) - { - //--- check - if(a[i]!=a[i-1]) - tiecount=tiecount+1; - } -//--- allocation - ArrayResizeAL(ties,tiecount+1); -//--- change values - ties[0]=0; - k=1; -//--- calculation - for(i=1;i<=n-1;i++) - { - //--- check - if(a[i]!=a[i-1]) - { - ties[k]=i; - k=k+1; - } - } -//--- change value - ties[tiecount]=n; - } -//+------------------------------------------------------------------+ -//| Method | -//+------------------------------------------------------------------+ -static void CBdSS::DSTieFastI(double &a[],int &b[],const int n,int &ties[], - int &tiecount,double &bufr[],int &bufi[]) - { -//--- create variables - int i=0; - int k=0; -//--- create array - int tmp[]; -//--- initialization - tiecount=0; -//--- Special case - if(n<=0) - { - tiecount=0; - return; - } -//--- Sort A - CTSort::TagSortFastI(a,b,bufr,bufi,n); -//--- Process ties - ties[0]=0; - k=1; -//--- calculation - for(i=1;i<=n-1;i++) - { - //--- check - if(a[i]!=a[i-1]) - { - ties[k]=i; - k=k+1; - } - } -//--- change values - ties[k]=n; - tiecount=k; - } -//+------------------------------------------------------------------+ -//| Optimal binary classification | -//| Algorithms finds optimal (=with minimal cross-entropy) binary | -//| partition. | -//| Internal subroutine. | -//| INPUT PARAMETERS: | -//| A - array[0..N-1], variable | -//| C - array[0..N-1], class numbers (0 or 1). | -//| N - array size | -//| OUTPUT PARAMETERS: | -//| Info - completetion code: | -//| * -3, all values of A[] are same (partition is | -//| impossible) | -//| * -2, one of C[] is incorrect (<0, >1) | -//| * -1, incorrect pararemets were passed (N<=0). | -//| * 1, OK | -//| Threshold- partiton boundary. Left part contains values | -//| which are strictly less than Threshold. Right | -//| part contains values which are greater than or | -//| equal to Threshold. | -//| PAL, PBL- probabilities P(0|v=Threshold) and | -//| P(1|v>=Threshold) | -//| CVE - cross-validation estimate of cross-entropy | -//+------------------------------------------------------------------+ -static void CBdSS::DSOptimalSplit2(double &ca[],int &cc[],const int n, - int &info,double &threshold,double &pal, - double &pbl,double &par,double &pbr, - double &cve) - { -//--- create variables - int i=0; - int t=0; - double s=0; - int tiecount=0; - int k=0; - int koptimal=0; - double pak=0; - double pbk=0; - double cvoptimal=0; - double cv=0; -//--- creating arrays - int ties[]; - int p1[]; - int p2[]; - double a[]; - int c[]; -//--- copy - ArrayCopy(a,ca); - ArrayCopy(c,cc); -//--- initialization - info=0; - threshold=0; - pal=0; - pbl=0; - par=0; - pbr=0; - cve=0; -//--- Test for errors in inputs - if(n<=0) - { - info=-1; - return; - } - for(i=0;i<=n-1;i++) - { - //--- check - if(c[i]!=0 && c[i]!=1) - { - info=-2; - return; - } - } -//--- change value - info=1; -//--- Tie - DSTie(a,n,ties,tiecount,p1,p2); -//--- swap - for(i=0;i<=n-1;i++) - { - //--- check - if(p2[i]!=i) - { - t=c[i]; - c[i]=c[p2[i]]; - c[p2[i]]=t; - } - } -//--- Special case: number of ties is 1. -//--- NOTE: we assume that P[i][j] equals to 0 or 1, -//--- intermediate values are not allowed. - if(tiecount==1) - { - info=-3; - return; - } -//--- General case,number of ties > 1 -//--- NOTE: we assume that P[i][j] equals to 0 or 1, -//--- intermediate values are not allowed. - pal=0; - pbl=0; - par=0; - pbr=0; - for(i=0;i<=n-1;i++) - { - //--- check - if(c[i]==0) - par=par+1; - //--- check - if(c[i]==1) - pbr=pbr+1; - } -//--- change values - koptimal=-1; - cvoptimal=CMath::m_maxrealnumber; - for(k=0;k<=tiecount-2;k++) - { - //--- first,obtain information about K-th tie which is - //--- moved from R-part to L-part - pak=0; - pbk=0; - for(i=ties[k];i<=ties[k+1]-1;i++) - { - //--- check - if(c[i]==0) - pak=pak+1; - //--- check - if(c[i]==1) - pbk=pbk+1; - } - //--- Calculate cross-validation CE - cv=0; - cv=cv-XLnY(pal+pak,(pal+pak)/(pal+pak+pbl+pbk+1)); - cv=cv-XLnY(pbl+pbk,(pbl+pbk)/(pal+pak+1+pbl+pbk)); - cv=cv-XLnY(par-pak,(par-pak)/(par-pak+pbr-pbk+1)); - cv=cv-XLnY(pbr-pbk,(pbr-pbk)/(par-pak+1+pbr-pbk)); - //--- Compare with best - if(cv0"=OK, "<0"=bad) | -//| RMS training set RMS error | -//| CVRMS leave-one-out RMS error | -//| Note: | -//| content of all arrays is changed by subroutine; | -//| it doesn't allocate temporaries. | -//+------------------------------------------------------------------+ -static void CBdSS::DSOptimalSplit2Fast(double &a[],int &c[],int &tiesbuf[], - int &cntbuf[],double &bufr[],int &bufi[], - const int n,const int nc,double alpha, - int &info,double &threshold, - double &rms,double &cvrms) - { -//--- create variables - int i=0; - int k=0; - int cl=0; - int tiecount=0; - double cbest=0; - double cc=0; - int koptimal=0; - int sl=0; - int sr=0; - double v=0; - double w=0; - double x=0; -//--- initialization - info=0; - threshold=0; - rms=0; - cvrms=0; -//--- Test for errors in inputs - if(n<=0 || nc<2) - { - info=-1; - return; - } - for(i=0;i<=n-1;i++) - { - //--- check - if(c[i]<0 || c[i]>=nc) - { - info=-2; - return; - } - } -//--- change value - info=1; -//--- Tie - DSTieFastI(a,c,n,tiesbuf,tiecount,bufr,bufi); -//--- Special case: number of ties is 1. - if(tiecount==1) - { - info=-3; - return; - } -//--- General case,number of ties > 1 - for(i=0;i<=2*nc-1;i++) - cntbuf[i]=0; - for(i=0;i<=n-1;i++) - cntbuf[nc+c[i]]=cntbuf[nc+c[i]]+1; -//--- change values - koptimal=-1; - threshold=a[n-1]; - cbest=CMath::m_maxrealnumber; - sl=0; - sr=n; -//--- calculation - for(k=0;k<=tiecount-2;k++) - { - //--- first,move Kth tie from right to left - for(i=tiesbuf[k];i<=tiesbuf[k+1]-1;i++) - { - cl=c[i]; - cntbuf[cl]=cntbuf[cl]+1; - cntbuf[nc+cl]=cntbuf[nc+cl]-1; - } - sl=sl+(tiesbuf[k+1]-tiesbuf[k]); - sr=sr-(tiesbuf[k+1]-tiesbuf[k]); - //--- Calculate RMS error - v=0; - for(i=0;i<=nc-1;i++) - { - w=cntbuf[i]; - v=v+w*CMath::Sqr(w/sl-1); - v=v+(sl-w)*CMath::Sqr(w/sl); - w=cntbuf[nc+i]; - v=v+w*CMath::Sqr(w/sr-1); - v=v+(sr-w)*CMath::Sqr(w/sr); - } - //--- change value - v=MathSqrt(v/(nc*n)); - //--- Compare with best - x=(double)(2*sl)/(double)(sl+sr)-1; - cc=v*(1-alpha+alpha*CMath::Sqr(x)); - //--- check - if(cc1) - { - w=cntbuf[i]; - cvrms=cvrms+w*CMath::Sqr((w-1)/(sl-1)-1); - cvrms=cvrms+(sl-w)*CMath::Sqr(w/(sl-1)); - } - else - { - w=cntbuf[i]; - cvrms=cvrms+w*CMath::Sqr(1.0/(double)nc-1); - cvrms=cvrms+(sl-w)*CMath::Sqr(1.0/(double)nc); - } - //--- check - if(sr>1) - { - w=cntbuf[nc+i]; - cvrms=cvrms+w*CMath::Sqr((w-1)/(sr-1)-1); - cvrms=cvrms+(sr-w)*CMath::Sqr(w/(sr-1)); - } - else - { - w=cntbuf[nc+i]; - cvrms=cvrms+w*CMath::Sqr(1.0/(double)nc-1); - cvrms=cvrms+(sr-w)*CMath::Sqr(1.0/(double)nc); - } - } - //--- change value - cvrms=MathSqrt(cvrms/(nc*n)); - } - } -//--- Calculate threshold. -//--- Code is a bit complicated because there can be such -//--- numbers that 0.5(A+B) equals to A or B (if A-B=epsilon) - threshold=0.5*(a[tiesbuf[koptimal]]+a[tiesbuf[koptimal+1]]); -//--- check - if(threshold<=a[tiesbuf[koptimal]]) - threshold=a[tiesbuf[koptimal+1]]; - } -//+------------------------------------------------------------------+ -//| Automatic non-optimal discretization, internal subroutine. | -//+------------------------------------------------------------------+ -static void CBdSS::DSSplitK(double &ca[],int &cc[],const int n,const int nc, - int kmax,int &info,double &thresholds[],int &ni, - double &cve) - { -//--- create variables - int i=0; - int j=0; - int j1=0; - int k=0; - int tiecount=0; - double v2=0; - int bestk=0; - double bestcve=0; - double curcve=0; -//--- creating arrays - int ties[]; - int p1[]; - int p2[]; - int cnt[]; - int bestsizes[]; - int cursizes[]; - double a[]; - int c[]; -//--- copy - ArrayCopy(a,ca); - ArrayCopy(c,cc); -//--- initialization - info=0; - ni=0; - cve=0; -//--- Test for errors in inputs - if((n<=0 || nc<2) || kmax<2) - { - info=-1; - return; - } - for(i=0;i<=n-1;i++) - { - //--- check - if(c[i]<0 || c[i]>=nc) - { - info=-2; - return; - } - } -//--- change value - info=1; -//--- Tie - DSTie(a,n,ties,tiecount,p1,p2); -//--- swap - for(i=0;i<=n-1;i++) - { - //--- check - if(p2[i]!=i) - { - k=c[i]; - c[i]=c[p2[i]]; - c[p2[i]]=k; - } - } -//--- Special cases - if(tiecount==1) - { - info=-3; - return; - } -//--- General case: -//--- 0. allocate arrays - kmax=MathMin(kmax,tiecount); -//--- allocation - ArrayResizeAL(bestsizes,kmax); - ArrayResizeAL(cursizes,kmax); - ArrayResizeAL(cnt,nc); -//--- General case: -//--- 1. prepare "weak" solution (two subintervals,divided at median) - v2=CMath::m_maxrealnumber; - j=-1; - for(i=1;i<=tiecount-1;i++) - { - //--- check - if(MathAbs(ties[i]-0.5*(n-1))0,__FUNCTION__+": internal error #1!")) - return; -//--- change values - bestk=2; - bestsizes[0]=ties[j]; - bestsizes[1]=n-j; - bestcve=0; -//--- calculation - for(i=0;i<=nc-1;i++) - cnt[i]=0; - for(i=0;i<=j-1;i++) - TieAddC(c,ties,i,nc,cnt); - bestcve=bestcve+GetCV(cnt,nc); -//--- calculation - for(i=0;i<=nc-1;i++) - cnt[i]=0; - for(i=j;i<=tiecount-1;i++) - TieAddC(c,ties,i,nc,cnt); - bestcve=bestcve+GetCV(cnt,nc); -//--- General case: -//--- 2. Use greedy algorithm to find sub-optimal split in O(KMax*N) time - for(k=2;k<=kmax;k++) - { - //--- Prepare greedy K-interval split - for(i=0;i<=k-1;i++) - cursizes[i]=0; - //--- change values - i=0; - j=0; - //--- cycle - while(j<=tiecount-1 && i<=k-1) - { - //--- Rule: I-th bin is empty,fill it - if(cursizes[i]==0) - { - cursizes[i]=ties[j+1]-ties[j]; - j=j+1; - continue; - } - //--- Rule: (K-1-I) bins left,(K-1-I) ties left (1 tie per bin);next bin - if(tiecount-j==k-1-i) - { - i=i+1; - continue; - } - //--- Rule: last bin,always place in current - if(i==k-1) - { - cursizes[i]=cursizes[i]+ties[j+1]-ties[j]; - j=j+1; - continue; - } - //--- Place J-th tie in I-th bin,or leave for I+1-th bin. - if(MathAbs(cursizes[i]+ties[j+1]-ties[j]-(double)n/(double)k)=nc) - { - info=-2; - return; - } - } -//--- change value - info=1; -//--- Tie - DSTie(a,n,ties,tiecount,p1,p2); -//--- swap - for(i=0;i<=n-1;i++) - { - //--- check - if(p2[i]!=i) - { - k=c[i]; - c[i]=c[p2[i]]; - c[p2[i]]=k; - } - } -//--- Special cases - if(tiecount==1) - { - info=-3; - return; - } -//--- General case -//--- Use dynamic programming to find best split in O(KMax*NC*TieCount^2) time - kmax=MathMin(kmax,tiecount); -//--- allocation - cv.Resize(kmax,tiecount); - splits.Resize(kmax,tiecount); - ArrayResizeAL(cnt,nc); - ArrayResizeAL(cnt2,nc); -//--- calculation - for(j=0;j<=nc-1;j++) - cnt[j]=0; - for(j=0;j<=tiecount-1;j++) - { - TieAddC(c,ties,j,nc,cnt); - splits[0].Set(j,0); - cv[0].Set(j,GetCV(cnt,nc)); - } - for(k=1;k<=kmax-1;k++) - { - for(j=0;j<=nc-1;j++) - cnt[j]=0; - //--- Subtask size J in [K..TieCount-1]: - //--- optimal K-splitting on ties from 0-th to J-th. - for(j=k;j<=tiecount-1;j++) - { - //--- Update Cnt - let it contain classes of ties from K-th to J-th - TieAddC(c,ties,j,nc,cnt); - //--- Search for optimal split point S in [K..J] - for(i=0;i<=nc-1;i++) - cnt2[i]=cnt[i]; - cv[k].Set(j,cv[k-1][j-1]+GetCV(cnt2,nc)); - splits[k].Set(j,j); - //--- calculation - for(s=k+1;s<=j;s++) - { - //--- Update Cnt2 - let it contain classes of ties from S-th to J-th - TieSubC(c,ties,s-1,nc,cnt2); - //--- Calculate CVE - cvtemp=cv[k-1][s-1]+GetCV(cnt2,nc); - //--- check - if(cvtemp=0,__FUNCTION__+": internal error #1!")) - return; -//--- check - if(koptimal==0) - { - //--- Special case: best partition is one big interval. - //--- Even 2-partition is not better. - //--- This is possible when dealing with "weak" predictor variables. - //--- Make binary split as close to the median as possible. - v2=CMath::m_maxrealnumber; - j=-1; - for(i=1;i<=tiecount-1;i++) - { - //--- check - if(MathAbs(ties[i]-0.5*(n-1))0,__FUNCTION__+": internal error #2!")) - return; - //--- allocation - ArrayResizeAL(thresholds,1); - //--- change values - thresholds[0]=0.5*(a[ties[j-1]]+a[ties[j]]); - ni=2; - cve=0; - //--- calculation - for(i=0;i<=nc-1;i++) - cnt[i]=0; - for(i=0;i<=j-1;i++) - TieAddC(c,ties,i,nc,cnt); - cve=cve+GetCV(cnt,nc); - for(i=0;i<=nc-1;i++) - cnt[i]=0; - for(i=j;i<=tiecount-1;i++) - TieAddC(c,ties,i,nc,cnt); - cve=cve+GetCV(cnt,nc); - } - else - { - //--- General case: 2 or more intervals - ArrayResizeAL(thresholds,koptimal); - ni=koptimal+1; - cve=cv[koptimal][tiecount-1]; - jl=splits[koptimal][tiecount-1]; - jr=tiecount-1; - //--- calculation - for(k=koptimal;k>=1;k--) - { - thresholds[k-1]=0.5*(a[ties[jl-1]]+a[ties[jl]]); - jr=jl-1; - jl=splits[k-1][jl-1]; - } - } - } -//+------------------------------------------------------------------+ -//| Internal function | -//+------------------------------------------------------------------+ -static double CBdSS::XLnY(const double x,const double y) - { -//--- check - if(x==0.0) - return(0); -//--- return result - return(x*MathLog(y)); - } -//+------------------------------------------------------------------+ -//| Internal function, | -//| returns number of samples of class I in Cnt[I] | -//+------------------------------------------------------------------+ -static double CBdSS::GetCV(int &cnt[],const int nc) - { -//--- create variables - double result=0; - int i=0; - double s=0; -//--- calculation - s=0; - for(i=0;i<=nc-1;i++) - s=s+cnt[i]; -//--- get result - result=0; - for(i=0;i<=nc-1;i++) - result=result-XLnY(cnt[i],cnt[i]/(s+nc-1)); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Internal function,adds number of samples of class I in tie NTie | -//| to Cnt[I] | -//+------------------------------------------------------------------+ -static void CBdSS::TieAddC(int &c[],int &ties[],const int ntie,const int nc, - int &cnt[]) - { -//--- create a variable - int i=0; -//--- calculation - for(i=ties[ntie];i<=ties[ntie+1]-1;i++) - cnt[c[i]]=cnt[c[i]]+1; - } -//+------------------------------------------------------------------+ -//| Internal function,subtracts number of samples of class I in tie | -//| NTie to Cnt[I] | -//+------------------------------------------------------------------+ -static void CBdSS::TieSubC(int &c[],int &ties[],const int ntie,const int nc, - int &cnt[]) - { -//--- create a variable - int i=0; -//--- calculation - for(i=ties[ntie];i<=ties[ntie+1]-1;i++) - cnt[c[i]]=cnt[c[i]]-1; - } -//+------------------------------------------------------------------+ -//| Auxiliary class for CDForest | -//+------------------------------------------------------------------+ -class CDecisionForest - { -public: - int m_nvars; - int m_nclasses; - int m_ntrees; - int m_bufsize; - double m_trees[]; - //--- constructor, destructor - CDecisionForest(void); - ~CDecisionForest(void); - //--- copy - void Copy(CDecisionForest &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CDecisionForest::CDecisionForest(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CDecisionForest::~CDecisionForest(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CDecisionForest::Copy(CDecisionForest &obj) - { -//--- copy variables - m_nvars=obj.m_nvars; - m_nclasses=obj.m_nclasses; - m_ntrees=obj.m_ntrees; - m_bufsize=obj.m_bufsize; -//--- copy array - ArrayCopy(m_trees,obj.m_trees); - } -//+------------------------------------------------------------------+ -//| This class is a shell for class CDecisionForest | -//+------------------------------------------------------------------+ -class CDecisionForestShell - { -private: - CDecisionForest m_innerobj; -public: - //--- constructors, destructor - CDecisionForestShell(void); - CDecisionForestShell(CDecisionForest &obj); - ~CDecisionForestShell(void); - //--- method - CDecisionForest *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CDecisionForestShell::CDecisionForestShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CDecisionForestShell::CDecisionForestShell(CDecisionForest &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CDecisionForestShell::~CDecisionForestShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CDecisionForest *CDecisionForestShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Auxiliary class for CDForest | -//+------------------------------------------------------------------+ -class CDFReport - { -public: - //--- variables - double m_relclserror; - double m_avgce; - double m_rmserror; - double m_avgerror; - double m_avgrelerror; - double m_oobrelclserror; - double m_oobavgce; - double m_oobrmserror; - double m_oobavgerror; - double m_oobavgrelerror; - //--- constructor, destructor - CDFReport(void); - ~CDFReport(void); - //--- copy - void Copy(CDFReport &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CDFReport::CDFReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CDFReport::~CDFReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CDFReport::Copy(CDFReport &obj) - { -//--- copy variables - m_relclserror=obj.m_relclserror; - m_avgce=obj.m_avgce; - m_rmserror=obj.m_rmserror; - m_avgerror=obj.m_avgerror; - m_avgrelerror=obj.m_avgrelerror; - m_oobrelclserror=obj.m_oobrelclserror; - m_oobavgce=obj.m_oobavgce; - m_oobrmserror=obj.m_oobrmserror; - m_oobavgerror=obj.m_oobavgerror; - m_oobavgrelerror=obj.m_oobavgrelerror; - } -//+------------------------------------------------------------------+ -//| This class is a shell for class CDFReport | -//+------------------------------------------------------------------+ -class CDFReportShell - { -private: - CDFReport m_innerobj; -public: - //--- constructors, destructor - CDFReportShell(void); - CDFReportShell(CDFReport &obj); - ~CDFReportShell(void); - //--- methods - double GetRelClsError(void); - void SetRelClsError(const double d); - double GetAvgCE(void); - void SetAvgCE(const double d); - double GetRMSError(void); - void SetRMSError(const double d); - double GetAvgError(void); - void SetAvgError(const double d); - double GetAvgRelError(void); - void SetAvgRelError(const double d); - double GetOOBRelClsError(void); - void SetOOBRelClsError(const double d); - double GetOOBAvgCE(void); - void SetOOBAvgCE(const double d); - double GetOOBRMSError(void); - void SetOOBRMSError(const double d); - double GetOOBAvgError(void); - void SetOOBAvgError(const double d); - double GetOOBAvgRelError(void); - void SetOOBAvgRelError(const double d); - CDFReport *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CDFReportShell::CDFReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CDFReportShell::CDFReportShell(CDFReport &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CDFReportShell::~CDFReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable relclserror | -//+------------------------------------------------------------------+ -double CDFReportShell::GetRelClsError(void) - { -//--- return result - return(m_innerobj.m_relclserror); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable relclserror | -//+------------------------------------------------------------------+ -void CDFReportShell::SetRelClsError(const double d) - { -//--- change value - m_innerobj.m_relclserror=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable avgce | -//+------------------------------------------------------------------+ -double CDFReportShell::GetAvgCE(void) - { -//--- return result - return(m_innerobj.m_avgce); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable avgce | -//+------------------------------------------------------------------+ -void CDFReportShell::SetAvgCE(const double d) - { -//--- change value - m_innerobj.m_avgce=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable rmserror | -//+------------------------------------------------------------------+ -double CDFReportShell::GetRMSError(void) - { -//--- return result - return(m_innerobj.m_rmserror); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable rmserror | -//+------------------------------------------------------------------+ -void CDFReportShell::SetRMSError(const double d) - { -//--- change value - m_innerobj.m_rmserror=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable avgerror | -//+------------------------------------------------------------------+ -double CDFReportShell::GetAvgError(void) - { -//--- return result - return(m_innerobj.m_avgerror); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable avgerror | -//+------------------------------------------------------------------+ -void CDFReportShell::SetAvgError(const double d) - { -//--- change value - m_innerobj.m_avgerror=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable avgrelerror | -//+------------------------------------------------------------------+ -double CDFReportShell::GetAvgRelError(void) - { -//--- return result - return(m_innerobj.m_avgrelerror); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable avgrelerror | -//+------------------------------------------------------------------+ -void CDFReportShell::SetAvgRelError(const double d) - { -//--- change value - m_innerobj.m_avgrelerror=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable oobrelclserror | -//+------------------------------------------------------------------+ -double CDFReportShell::GetOOBRelClsError(void) - { -//--- return result - return(m_innerobj.m_oobrelclserror); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable oobrelclserror | -//+------------------------------------------------------------------+ -void CDFReportShell::SetOOBRelClsError(const double d) - { -//--- change value - m_innerobj.m_oobrelclserror=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable oobavgce | -//+------------------------------------------------------------------+ -double CDFReportShell::GetOOBAvgCE(void) - { -//--- return result - return(m_innerobj.m_oobavgce); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable oobavgce | -//+------------------------------------------------------------------+ -void CDFReportShell::SetOOBAvgCE(const double d) - { -//--- change value - m_innerobj.m_oobavgce=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable oobrmserror | -//+------------------------------------------------------------------+ -double CDFReportShell::GetOOBRMSError(void) - { -//--- return result - return(m_innerobj.m_oobrmserror); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable oobrmserror | -//+------------------------------------------------------------------+ -void CDFReportShell::SetOOBRMSError(const double d) - { -//--- change value - m_innerobj.m_oobrmserror=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable oobavgerror | -//+------------------------------------------------------------------+ -double CDFReportShell::GetOOBAvgError(void) - { -//--- return result - return(m_innerobj.m_oobavgerror); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable oobavgerror | -//+------------------------------------------------------------------+ -void CDFReportShell::SetOOBAvgError(const double d) - { -//--- change value - m_innerobj.m_oobavgerror=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable oobavgrelerror | -//+------------------------------------------------------------------+ -double CDFReportShell::GetOOBAvgRelError(void) - { -//--- return result - return(m_innerobj.m_oobavgrelerror); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable oobavgrelerror | -//+------------------------------------------------------------------+ -void CDFReportShell::SetOOBAvgRelError(const double d) - { -//--- change value - m_innerobj.m_oobavgrelerror=d; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CDFReport *CDFReportShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Auxiliary class for CDForest | -//+------------------------------------------------------------------+ -class CDFInternalBuffers - { -public: - //--- arrays - double m_treebuf[]; - int m_idxbuf[]; - double m_tmpbufr[]; - double m_tmpbufr2[]; - int m_tmpbufi[]; - int m_classibuf[]; - double m_sortrbuf[]; - double m_sortrbuf2[]; - int m_sortibuf[]; - int m_varpool[]; - bool m_evsbin[]; - double m_evssplits[]; - //--- constructor, destructor - CDFInternalBuffers(void); - ~CDFInternalBuffers(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CDFInternalBuffers::CDFInternalBuffers(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CDFInternalBuffers::~CDFInternalBuffers(void) - { - - } -//+------------------------------------------------------------------+ -//| Decision forest class | -//+------------------------------------------------------------------+ -class CDForest - { -private: - //--- private methods - static int DFClsError(CDecisionForest &df,CMatrixDouble &xy,const int npoints); - static void DFProcessInternal(CDecisionForest &df,const int offs,double &x[],double &y[]); - static void DFBuildTree(CMatrixDouble &xy,const int npoints,const int nvars,const int nclasses,const int nfeatures,const int nvarsinpool,const int flags,CDFInternalBuffers &bufs); - static void DFBuildTreeRec(CMatrixDouble &xy,const int npoints,const int nvars,const int nclasses,const int nfeatures,int nvarsinpool,const int flags,int &numprocessed,const int idx1,const int idx2,CDFInternalBuffers &bufs); - static void DFSplitC(double &x[],int &c[],int &cntbuf[],const int n,const int nc,const int flags,int &info,double &threshold,double &e,double &sortrbuf[],int &sortibuf[]); - static void DFSplitR(double &x[],double &y[],const int n,const int flags,int &info,double &threshold,double &e,double &sortrbuf[],double &sortrbuf2[]); -public: - //--- class constants - static const int m_innernodewidth; - static const int m_leafnodewidth; - static const int m_dfusestrongsplits; - static const int m_dfuseevs; - static const int m_dffirstversion; - //--- constructor, destructor - CDForest(void); - ~CDForest(void); - //--- public methods - static void DFBuildRandomDecisionForest(CMatrixDouble &xy,const int npoints,const int nvars,const int nclasses,const int ntrees,const double r,int &info,CDecisionForest &df,CDFReport &rep); - static void DFBuildRandomDecisionForestX1(CMatrixDouble &xy,const int npoints,const int nvars,const int nclasses,const int ntrees,const int nrndvars,const double r,int &info,CDecisionForest &df,CDFReport &rep); - static void DFBuildInternal(CMatrixDouble &xy,const int npoints,const int nvars,const int nclasses,const int ntrees,const int samplesize,const int nfeatures,const int flags,int &info,CDecisionForest &df,CDFReport &rep); - static void DFProcess(CDecisionForest &df,double &x[],double &y[]); - static void DFProcessI(CDecisionForest &df,double &x[],double &y[]); - static double DFRelClsError(CDecisionForest &df,CMatrixDouble &xy,const int npoints); - static double DFAvgCE(CDecisionForest &df,CMatrixDouble &xy,const int npoints); - static double DFRMSError(CDecisionForest &df,CMatrixDouble &xy,const int npoints); - static double DFAvgError(CDecisionForest &df,CMatrixDouble &xy,const int npoints); - static double DFAvgRelError(CDecisionForest &df,CMatrixDouble &xy,const int npoints); - static void DFCopy(CDecisionForest &df1,CDecisionForest &df2); - static void DFAlloc(CSerializer &s,CDecisionForest &forest); - static void DFSerialize(CSerializer &s,CDecisionForest &forest); - static void DFUnserialize(CSerializer &s,CDecisionForest &forest); - }; -//+------------------------------------------------------------------+ -//| Initialize constants | -//+------------------------------------------------------------------+ -const int CDForest::m_innernodewidth=3; -const int CDForest::m_leafnodewidth=2; -const int CDForest::m_dfusestrongsplits=1; -const int CDForest::m_dfuseevs=2; -const int CDForest::m_dffirstversion=0; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CDForest::CDForest(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CDForest::~CDForest(void) - { - - } -//+------------------------------------------------------------------+ -//| This subroutine builds random decision forest. | -//| INPUT PARAMETERS: | -//| XY - training set | -//| NPoints - training set size, NPoints>=1 | -//| NVars - number of independent variables, NVars>=1 | -//| NClasses - task type: | -//| * NClasses=1 - regression task with one | -//| dependent variable | -//| * NClasses>1 - classification task with | -//| NClasses classes. | -//| NTrees - number of trees in a forest, NTrees>=1. | -//| recommended values: 50-100. | -//| R - percent of a training set used to build | -//| individual trees. 01). | -//| * 1, if task has been solved | -//| DF - model built | -//| Rep - training report, contains error on a training| -//| set and out-of-bag estimates of | -//| generalization error. | -//+------------------------------------------------------------------+ -static void CDForest::DFBuildRandomDecisionForest(CMatrixDouble &xy, - const int npoints, - const int nvars, - const int nclasses, - const int ntrees, - const double r,int &info, - CDecisionForest &df, - CDFReport &rep) - { -//--- create a variable - int samplesize=0; -//--- initialization - info=0; -//--- check - if(r<=0.0 || r>1.0) - { - info=-1; - return; - } -//--- calculation - samplesize=(int)(MathMax((int)MathRound(r*npoints),1)); -//--- function call - DFBuildInternal(xy,npoints,nvars,nclasses,ntrees,samplesize,(int)(MathMax(nvars/2,1)),m_dfusestrongsplits+m_dfuseevs,info,df,rep); - } -//+------------------------------------------------------------------+ -//| This subroutine builds random decision forest. | -//| This function gives ability to tune number of variables used when| -//| choosing best split. | -//| INPUT PARAMETERS: | -//| XY - training set | -//| NPoints - training set size, NPoints>=1 | -//| NVars - number of independent variables, NVars>=1 | -//| NClasses - task type: | -//| * NClasses=1 - regression task with one | -//| dependent variable | -//| * NClasses>1 - classification task with | -//| NClasses classes. | -//| NTrees - number of trees in a forest, NTrees>=1. | -//| recommended values: 50-100. | -//| NRndVars - number of variables used when choosing best | -//| split | -//| R - percent of a training set used to build | -//| individual trees. 01). | -//| * 1, if task has been solved | -//| DF - model built | -//| Rep - training report, contains error on a training| -//| set and out-of-bag estimates of | -//| generalization error. | -//+------------------------------------------------------------------+ -static void CDForest::DFBuildRandomDecisionForestX1(CMatrixDouble &xy, - const int npoints, - const int nvars, - const int nclasses, - const int ntrees, - const int nrndvars, - const double r,int &info, - CDecisionForest &df, - CDFReport &rep) - { -//--- create a variable - int samplesize=0; -//--- initialization - info=0; -//--- check - if(r<=0.0 || r>1.0) - { - info=-1; - return; - } -//--- check - if(nrndvars<=0 || nrndvars>nvars) - { - info=-1; - return; - } -//--- calculation - samplesize=(int)(MathMax((int)MathRound(r*npoints),1)); -//--- function call - DFBuildInternal(xy,npoints,nvars,nclasses,ntrees,samplesize,nrndvars,m_dfusestrongsplits+m_dfuseevs,info,df,rep); - } -//+------------------------------------------------------------------+ -//| Class method | -//+------------------------------------------------------------------+ -static void CDForest::DFBuildInternal(CMatrixDouble &xy,const int npoints, - const int nvars,const int nclasses, - const int ntrees,const int samplesize, - const int nfeatures,const int flags, - int &info,CDecisionForest &df, - CDFReport &rep) - { -//--- create variables - int i=0; - int j=0; - int k=0; - int tmpi=0; - int lasttreeoffs=0; - int offs=0; - int ooboffs=0; - int treesize=0; - int nvarsinpool=0; - bool useevs; - int oobcnt=0; - int oobrelcnt=0; - double v=0; - double vmin=0; - double vmax=0; - bool bflag; - int i_=0; - int i1_=0; -//--- creating arrays - int permbuf[]; - double oobbuf[]; - int oobcntbuf[]; - double x[]; - double y[]; -//--- create matrix - CMatrixDouble xys; -//--- create object of class - CDFInternalBuffers bufs; -//--- initialization - info=0; -//--- Test for inputs - if(npoints<1 || samplesize<1 || samplesize>npoints || nvars<1 || nclasses<1 || ntrees<1 || nfeatures<1) - { - info=-1; - return; - } -//--- check - if(nclasses>1) - { - for(i=0;i<=npoints-1;i++) - { - //--- check - if((int)MathRound(xy[i][nvars])<0 || (int)MathRound(xy[i][nvars])>=nclasses) - { - info=-2; - return; - } - } - } -//--- change value - info=1; -//--- Flags - useevs=flags/m_dfuseevs%2!=0; -//--- Allocate data,prepare header - treesize=1+m_innernodewidth*(samplesize-1)+m_leafnodewidth*samplesize; -//--- allocation - ArrayResizeAL(permbuf,npoints); - ArrayResizeAL(bufs.m_treebuf,treesize); - ArrayResizeAL(bufs.m_idxbuf,npoints); - ArrayResizeAL(bufs.m_tmpbufr,npoints); - ArrayResizeAL(bufs.m_tmpbufr2,npoints); - ArrayResizeAL(bufs.m_tmpbufi,npoints); - ArrayResizeAL(bufs.m_sortrbuf,npoints); - ArrayResizeAL(bufs.m_sortrbuf2,npoints); - ArrayResizeAL(bufs.m_sortibuf,npoints); - ArrayResizeAL(bufs.m_varpool,nvars); - ArrayResizeAL(bufs.m_evsbin,nvars); - ArrayResizeAL(bufs.m_evssplits,nvars); - ArrayResizeAL(bufs.m_classibuf,2*nclasses); - ArrayResizeAL(oobbuf,nclasses*npoints); - ArrayResizeAL(oobcntbuf,npoints); - ArrayResizeAL(df.m_trees,ntrees*treesize); - xys.Resize(samplesize,nvars+1); - ArrayResizeAL(x,nvars); - ArrayResizeAL(y,nclasses); -//--- initialization - for(i=0;i<=npoints-1;i++) - permbuf[i]=i; - for(i=0;i<=npoints*nclasses-1;i++) - oobbuf[i]=0; - for(i=0;i<=npoints-1;i++) - oobcntbuf[i]=0; -//--- Prepare variable pool and EVS (extended variable selection/splitting) buffers -//--- (whether EVS is turned on or not): -//--- 1. detect binary variables and pre-calculate splits for them -//--- 2. detect variables with non-distinct values and exclude them from pool - for(i=0;i<=nvars-1;i++) - bufs.m_varpool[i]=i; - nvarsinpool=nvars; -//--- check - if(useevs) - { - for(j=0;j<=nvars-1;j++) - { - vmin=xy[0][j]; - vmax=vmin; - //--- calculation - for(i=0;i<=npoints-1;i++) - { - v=xy[i][j]; - vmin=MathMin(vmin,v); - vmax=MathMax(vmax,v); - } - //--- check - if(vmin==vmax) - { - //--- exclude variable from pool - bufs.m_varpool[j]=bufs.m_varpool[nvarsinpool-1]; - bufs.m_varpool[nvarsinpool-1]=-1; - nvarsinpool=nvarsinpool-1; - continue; - } - //--- change value - bflag=false; - for(i=0;i<=npoints-1;i++) - { - v=xy[i][j]; - //--- check - if(v!=vmin&&v!=vmax) - { - bflag=true; - break; - } - } - //--- check - if(bflag) - { - //--- non-binary variable - bufs.m_evsbin[j]=false; - } - else - { - //--- Prepare - bufs.m_evsbin[j]=true; - bufs.m_evssplits[j]=0.5*(vmin+vmax); - //--- check - if(bufs.m_evssplits[j]<=vmin) - bufs.m_evssplits[j]=vmax; - } - } - } -//--- RANDOM FOREST FORMAT -//--- W[0] - size of array -//--- W[1] - version number -//--- W[2] - NVars -//--- W[3] - NClasses (1 for regression) -//--- W[4] - NTrees -//--- W[5] - trees offset -//--- TREE FORMAT -//--- W[Offs] - size of sub-array -//--- node info: -//--- W[K+0] - variable number (-1 for leaf mode) -//--- W[K+1] - threshold (class/value for leaf node) -//--- W[K+2] - ">=" branch index (absent for leaf node) - df.m_nvars=nvars; - df.m_nclasses=nclasses; - df.m_ntrees=ntrees; -//--- Build forest - offs=0; - for(i=0;i<=ntrees-1;i++) - { - //--- Prepare sample - for(k=0;k<=samplesize-1;k++) - { - //--- calculation - j=k+CMath::RandomInteger(npoints-k); - tmpi=permbuf[k]; - permbuf[k]=permbuf[j]; - permbuf[j]=tmpi; - j=permbuf[k]; - for(i_=0;i_<=nvars;i_++) - xys[k].Set(i_,xy[j][i_]); - } - //--- build tree,copy - DFBuildTree(xys,samplesize,nvars,nclasses,nfeatures,nvarsinpool,flags,bufs); - //--- calculation - j=(int)MathRound(bufs.m_treebuf[0]); - i1_=-offs; - for(i_=offs;i_<=offs+j-1;i_++) - df.m_trees[i_]=bufs.m_treebuf[i_+i1_]; - lasttreeoffs=offs; - offs=offs+j; - //--- OOB estimates - for(k=samplesize;k<=npoints-1;k++) - { - for(j=0;j<=nclasses-1;j++) - y[j]=0; - j=permbuf[k]; - for(i_=0;i_<=nvars-1;i_++) - x[i_]=xy[j][i_]; - //--- function call - DFProcessInternal(df,lasttreeoffs,x,y); - //--- calculation - i1_=-j*nclasses; - for(i_=j*nclasses;i_<=(j+1)*nclasses-1;i_++) - oobbuf[i_]=oobbuf[i_]+y[i_+i1_]; - oobcntbuf[j]=oobcntbuf[j]+1; - } - } - df.m_bufsize=offs; -//--- Normalize OOB results - for(i=0;i<=npoints-1;i++) - { - //--- check - if(oobcntbuf[i]!=0) - { - v=1.0/(double)oobcntbuf[i]; - for(i_=i*nclasses;i_<=i*nclasses+nclasses-1;i_++) - oobbuf[i_]=v*oobbuf[i_]; - } - } -//--- Calculate training set estimates - rep.m_relclserror=DFRelClsError(df,xy,npoints); - rep.m_avgce=DFAvgCE(df,xy,npoints); - rep.m_rmserror=DFRMSError(df,xy,npoints); - rep.m_avgerror=DFAvgError(df,xy,npoints); - rep.m_avgrelerror=DFAvgRelError(df,xy,npoints); -//--- Calculate OOB estimates. - rep.m_oobrelclserror=0; - rep.m_oobavgce=0; - rep.m_oobrmserror=0; - rep.m_oobavgerror=0; - rep.m_oobavgrelerror=0; - oobcnt=0; - oobrelcnt=0; - for(i=0;i<=npoints-1;i++) - { - //--- check - if(oobcntbuf[i]!=0) - { - ooboffs=i*nclasses; - //--- check - if(nclasses>1) - { - //--- classification-specific code - k=(int)MathRound(xy[i][nvars]); - tmpi=0; - for(j=1;j<=nclasses-1;j++) - { - //--- check - if(oobbuf[ooboffs+j]>oobbuf[ooboffs+tmpi]) - tmpi=j; - } - //--- check - if(tmpi!=k) - rep.m_oobrelclserror=rep.m_oobrelclserror+1; - //--- check - if(oobbuf[ooboffs+k]!=0.0) - rep.m_oobavgce=rep.m_oobavgce-MathLog(oobbuf[ooboffs+k]); - else - rep.m_oobavgce=rep.m_oobavgce-MathLog(CMath::m_minrealnumber); - //--- calculation - for(j=0;j<=nclasses-1;j++) - { - //--- check - if(j==k) - { - rep.m_oobrmserror=rep.m_oobrmserror+CMath::Sqr(oobbuf[ooboffs+j]-1); - rep.m_oobavgerror=rep.m_oobavgerror+MathAbs(oobbuf[ooboffs+j]-1); - rep.m_oobavgrelerror=rep.m_oobavgrelerror+MathAbs(oobbuf[ooboffs+j]-1); - oobrelcnt=oobrelcnt+1; - } - else - { - rep.m_oobrmserror=rep.m_oobrmserror+CMath::Sqr(oobbuf[ooboffs+j]); - rep.m_oobavgerror=rep.m_oobavgerror+MathAbs(oobbuf[ooboffs+j]); - } - } - } - else - { - //--- regression-specific code - rep.m_oobrmserror=rep.m_oobrmserror+CMath::Sqr(oobbuf[ooboffs]-xy[i][nvars]); - rep.m_oobavgerror=rep.m_oobavgerror+MathAbs(oobbuf[ooboffs]-xy[i][nvars]); - //--- check - if(xy[i][nvars]!=0.0) - { - rep.m_oobavgrelerror=rep.m_oobavgrelerror+MathAbs((oobbuf[ooboffs]-xy[i][nvars])/xy[i][nvars]); - oobrelcnt=oobrelcnt+1; - } - } - //--- update OOB estimates count. - oobcnt=oobcnt+1; - } - } -//--- check - if(oobcnt>0) - { - //--- change values - rep.m_oobrelclserror=rep.m_oobrelclserror/oobcnt; - rep.m_oobavgce=rep.m_oobavgce/oobcnt; - rep.m_oobrmserror=MathSqrt(rep.m_oobrmserror/(oobcnt*nclasses)); - rep.m_oobavgerror=rep.m_oobavgerror/(oobcnt*nclasses); - //--- check - if(oobrelcnt>0) - rep.m_oobavgrelerror=rep.m_oobavgrelerror/oobrelcnt; - } - } -//+------------------------------------------------------------------+ -//| Procesing | -//| INPUT PARAMETERS: | -//| DF - decision forest model | -//| X - input vector, array[0..NVars-1]. | -//| OUTPUT PARAMETERS: | -//| Y - result. Regression estimate when solving | -//| regression task, vector of posterior | -//| probabilities for classification task. | -//| See also DFProcessI. | -//+------------------------------------------------------------------+ -static void CDForest::DFProcess(CDecisionForest &df,double &x[],double &y[]) - { -//--- create variables - int offs=0; - int i=0; - double v=0; - int i_=0; -//--- Proceed - if(CAp::Len(y)1) - { - //--- classification-specific code - k=(int)MathRound(xy[i][df.m_nvars]); - tmpi=0; - for(j=1;j<=df.m_nclasses-1;j++) - { - //--- check - if(y[j]>(double)(y[tmpi])) - tmpi=j; - } - //--- check - if(y[k]!=0.0) - result=result-MathLog(y[k]); - else - result=result-MathLog(CMath::m_minrealnumber); - } - } -//--- return result - return(result/npoints); - } -//+------------------------------------------------------------------+ -//| RMS error on the test set | -//| INPUT PARAMETERS: | -//| DF - decision forest model | -//| XY - test set | -//| NPoints - test set size | -//| RESULT: | -//| root mean square error. | -//| Its meaning for regression task is obvious. As for | -//| classification task,RMS error means error when estimating | -//| posterior probabilities. | -//+------------------------------------------------------------------+ -static double CDForest::DFRMSError(CDecisionForest &df,CMatrixDouble &xy, - const int npoints) - { -//--- create variables - double result=0; - int i=0; - int j=0; - int k=0; - int tmpi=0; - int i_=0; -//--- creating arrays - double x[]; - double y[]; -//--- allocation - ArrayResizeAL(x,df.m_nvars); - ArrayResizeAL(y,df.m_nclasses); -//--- initialization - result=0; - for(i=0;i<=npoints-1;i++) - { - for(i_=0;i_<=df.m_nvars-1;i_++) - x[i_]=xy[i][i_]; - //--- function call - DFProcess(df,x,y); - //--- check - if(df.m_nclasses>1) - { - //--- classification-specific code - k=(int)MathRound(xy[i][df.m_nvars]); - tmpi=0; - for(j=1;j<=df.m_nclasses-1;j++) - { - //--- check - if(y[j]>y[tmpi]) - tmpi=j; - } - for(j=0;j<=df.m_nclasses-1;j++) - { - //--- check - if(j==k) - result=result+CMath::Sqr(y[j]-1); - else - result=result+CMath::Sqr(y[j]); - } - } - else - { - //--- regression-specific code - result=result+CMath::Sqr(y[0]-xy[i][df.m_nvars]); - } - } -//--- return result - return(MathSqrt(result/(npoints*df.m_nclasses))); - } -//+------------------------------------------------------------------+ -//| Average error on the test set | -//| INPUT PARAMETERS: | -//| DF - decision forest model | -//| XY - test set | -//| NPoints - test set size | -//| RESULT: | -//| Its meaning for regression task is obvious. As for | -//| classification task, it means average error when estimating | -//| posterior probabilities. | -//+------------------------------------------------------------------+ -static double CDForest::DFAvgError(CDecisionForest &df,CMatrixDouble &xy, - const int npoints) - { -//--- create variables - double result=0; - int i=0; - int j=0; - int k=0; - int i_=0; -//--- creating arrays - double x[]; - double y[]; -//--- allocation - ArrayResizeAL(x,df.m_nvars); - ArrayResizeAL(y,df.m_nclasses); -//--- initialization - result=0; - for(i=0;i<=npoints-1;i++) - { - //--- copy - for(i_=0;i_<=df.m_nvars-1;i_++) - x[i_]=xy[i][i_]; - //--- function call - DFProcess(df,x,y); - //--- check - if(df.m_nclasses>1) - { - //--- classification-specific code - k=(int)MathRound(xy[i][df.m_nvars]); - for(j=0;j<=df.m_nclasses-1;j++) - { - //--- check - if(j==k) - result=result+MathAbs(y[j]-1); - else - result=result+MathAbs(y[j]); - } - } - else - { - //--- regression-specific code - result=result+MathAbs(y[0]-xy[i][df.m_nvars]); - } - } -//--- return result - return(result/(npoints*df.m_nclasses)); - } -//+------------------------------------------------------------------+ -//| Average relative error on the test set | -//| INPUT PARAMETERS: | -//| DF - decision forest model | -//| XY - test set | -//| NPoints - test set size | -//| RESULT: | -//| Its meaning for regression task is obvious. As for | -//| classification task, it means average relative error when | -//| estimating posterior probability of belonging to the correct | -//| class. | -//+------------------------------------------------------------------+ -static double CDForest::DFAvgRelError(CDecisionForest &df,CMatrixDouble &xy, - const int npoints) - { -//--- create variables - double result=0; - int relcnt=0; - int i=0; - int j=0; - int k=0; - int i_=0; -//--- creating arrays - double x[]; - double y[]; -//--- allocation - ArrayResizeAL(x,df.m_nvars); - ArrayResizeAL(y,df.m_nclasses); -//--- initialization - result=0; - relcnt=0; - for(i=0;i<=npoints-1;i++) - { - //--- copy - for(i_=0;i_<=df.m_nvars-1;i_++) - x[i_]=xy[i][i_]; - //--- function call - DFProcess(df,x,y); - //--- check - if(df.m_nclasses>1) - { - //--- classification-specific code - k=(int)MathRound(xy[i][df.m_nvars]); - for(j=0;j<=df.m_nclasses-1;j++) - { - //--- check - if(j==k) - { - result=result+MathAbs(y[j]-1); - relcnt=relcnt+1; - } - } - } - else - { - //--- regression-specific code - if(xy[i][df.m_nvars]!=0.0) - { - result=result+MathAbs((y[0]-xy[i][df.m_nvars])/xy[i][df.m_nvars]); - relcnt=relcnt+1; - } - } - } -//--- check - if(relcnt>0) - result=result/relcnt; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Copying of DecisionForest strucure | -//| INPUT PARAMETERS: | -//| DF1 - original | -//| OUTPUT PARAMETERS: | -//| DF2 - copy | -//+------------------------------------------------------------------+ -static void CDForest::DFCopy(CDecisionForest &df1,CDecisionForest &df2) - { -//--- create a variable - int i_=0; -//--- change values - df2.m_nvars=df1.m_nvars; - df2.m_nclasses=df1.m_nclasses; - df2.m_ntrees=df1.m_ntrees; - df2.m_bufsize=df1.m_bufsize; -//--- allocation - ArrayResizeAL(df2.m_trees,df1.m_bufsize); -//--- copy - for(i_=0;i_<=df1.m_bufsize-1;i_++) - df2.m_trees[i_]=df1.m_trees[i_]; - } -//+------------------------------------------------------------------+ -//| Serializer: allocation | -//+------------------------------------------------------------------+ -static void CDForest::DFAlloc(CSerializer &s,CDecisionForest &forest) - { -//--- preparation to serialize - s.Alloc_Entry(); - s.Alloc_Entry(); - s.Alloc_Entry(); - s.Alloc_Entry(); - s.Alloc_Entry(); - s.Alloc_Entry(); -//--- function call - CApServ::AllocRealArray(s,forest.m_trees,forest.m_bufsize); - } -//+------------------------------------------------------------------+ -//| Serializer: serialization | -//+------------------------------------------------------------------+ -static void CDForest::DFSerialize(CSerializer &s,CDecisionForest &forest) - { -//--- serializetion - s.Serialize_Int(CSCodes::GetRDFSerializationCode()); - s.Serialize_Int(m_dffirstversion); - s.Serialize_Int(forest.m_nvars); - s.Serialize_Int(forest.m_nclasses); - s.Serialize_Int(forest.m_ntrees); - s.Serialize_Int(forest.m_bufsize); -//--- function call - CApServ::SerializeRealArray(s,forest.m_trees,forest.m_bufsize); - } -//+------------------------------------------------------------------+ -//| Serializer: unserialization | -//+------------------------------------------------------------------+ -static void CDForest::DFUnserialize(CSerializer &s,CDecisionForest &forest) - { -//--- create variables - int i0=0; - int i1=0; -//--- check correctness of header - i0=s.Unserialize_Int(); -//--- check - if(!CAp::Assert(i0==CSCodes::GetRDFSerializationCode(),__FUNCTION__+": stream header corrupted")) - return; -//--- unserializetion - i1=s.Unserialize_Int(); -//--- check - if(!CAp::Assert(i1==m_dffirstversion,__FUNCTION__+": stream header corrupted")) - return; -//--- Unserialize data - forest.m_nvars=s.Unserialize_Int(); - forest.m_nclasses=s.Unserialize_Int(); - forest.m_ntrees=s.Unserialize_Int(); - forest.m_bufsize=s.Unserialize_Int(); -//--- function call - CApServ::UnserializeRealArray(s,forest.m_trees); - } -//+------------------------------------------------------------------+ -//| Classification error | -//+------------------------------------------------------------------+ -static int CDForest::DFClsError(CDecisionForest &df,CMatrixDouble &xy, - const int npoints) - { -//--- create variables - int result=0; - int i=0; - int j=0; - int k=0; - int tmpi=0; - int i_=0; -//--- creating arrays - double x[]; - double y[]; -//--- check - if(df.m_nclasses<=1) - return(0); -//--- allocation - ArrayResizeAL(x,df.m_nvars); - ArrayResizeAL(y,df.m_nclasses); -//--- initialization - result=0; - for(i=0;i<=npoints-1;i++) - { - //--- copy - for(i_=0;i_<=df.m_nvars-1;i_++) - x[i_]=xy[i][i_]; - //--- function call - DFProcess(df,x,y); - //--- change values - k=(int)MathRound(xy[i][df.m_nvars]); - tmpi=0; - for(j=1;j<=df.m_nclasses-1;j++) - { - //--- check - if(y[j]>(double)(y[tmpi])) - tmpi=j; - } - //--- check - if(tmpi!=k) - result=result+1; - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Internal subroutine for processing one decision tree starting at | -//| Offs | -//+------------------------------------------------------------------+ -static void CDForest::DFProcessInternal(CDecisionForest &df,const int offs, - double &x[],double &y[]) - { -//--- create variables - int k=0; - int idx=0; -//--- Set pointer to the root - k=offs+1; -//--- Navigate through the tree - while(true) - { - //--- check - if(df.m_trees[k]==-1.0) - { - //--- check - if(df.m_nclasses==1) - y[0]=y[0]+df.m_trees[k+1]; - else - { - idx=(int)MathRound(df.m_trees[k+1]); - y[idx]=y[idx]+1; - } - //--- break the cycle - break; - } - //--- check - if(x[(int)MathRound(df.m_trees[k])]0)) - return; -//--- Prepare IdxBuf. It stores indices of the training set elements. -//--- When training set is being split,contents of IdxBuf is -//--- correspondingly reordered so we can know which elements belong -//--- to which branch of decision tree. - for(i=0;i<=npoints-1;i++) - bufs.m_idxbuf[i]=i; -//--- Recursive procedure - numprocessed=1; -//--- function call - DFBuildTreeRec(xy,npoints,nvars,nclasses,nfeatures,nvarsinpool,flags,numprocessed,0,npoints-1,bufs); -//--- change values - bufs.m_treebuf[0]=numprocessed; - } -//+------------------------------------------------------------------+ -//| Builds one decision tree (internal recursive subroutine) | -//| Parameters: | -//| TreeBuf - large enough array,at least TreeSize | -//| IdxBuf - at least NPoints elements | -//| TmpBufR - at least NPoints | -//| TmpBufR2 - at least NPoints | -//| TmpBufI - at least NPoints | -//| TmpBufI2 - at least NPoints+1 | -//+------------------------------------------------------------------+ -static void CDForest::DFBuildTreeRec(CMatrixDouble &xy,const int npoints, - const int nvars,const int nclasses, - const int nfeatures,int nvarsinpool, - const int flags,int &numprocessed, - const int idx1,const int idx2, - CDFInternalBuffers &bufs) - { -//--- create variables - int i=0; - int j=0; - int k=0; - bool bflag; - int i1=0; - int i2=0; - int info=0; - double sl=0; - double sr=0; - double w=0; - int idxbest=0; - double ebest=0; - double tbest=0; - int varcur=0; - double s=0; - double v=0; - double v1=0; - double v2=0; - double threshold=0; - int oldnp=0; - double currms=0; - bool useevs; -//--- these initializers are not really necessary, -//--- but without them compiler complains about uninitialized locals - tbest=0; -//--- Prepare - if(!CAp::Assert(npoints>0)) - return; -//--- check - if(!CAp::Assert(idx2>=idx1)) - return; - useevs=flags/m_dfuseevs%2!=0; -//--- Leaf node - if(idx2==idx1) - { - bufs.m_treebuf[numprocessed]=-1; - bufs.m_treebuf[numprocessed+1]=xy[bufs.m_idxbuf[idx1]][nvars]; - numprocessed=numprocessed+m_leafnodewidth; - //--- exit the function - return; - } -//--- Non-leaf node. -//--- Select random variable,prepare split: -//--- 1. prepare default solution - no splitting,class at random -//--- 2. investigate possible splits,compare with default/best - idxbest=-1; -//--- check - if(nclasses>1) - { - //--- default solution for classification - for(i=0;i<=nclasses-1;i++) - bufs.m_classibuf[i]=0; - s=idx2-idx1+1; - for(i=idx1;i<=idx2;i++) - { - j=(int)MathRound(xy[bufs.m_idxbuf[i]][nvars]); - bufs.m_classibuf[j]=bufs.m_classibuf[j]+1; - } - //--- calculation - ebest=0; - for(i=0;i<=nclasses-1;i++) - ebest=ebest+bufs.m_classibuf[i]*CMath::Sqr(1-bufs.m_classibuf[i]/s)+(s-bufs.m_classibuf[i])*CMath::Sqr(bufs.m_classibuf[i]/s); - ebest=MathSqrt(ebest/(nclasses*(idx2-idx1+1))); - } - else - { - //--- default solution for regression - v=0; - for(i=idx1;i<=idx2;i++) - v=v+xy[bufs.m_idxbuf[i]][nvars]; - v=v/(idx2-idx1+1); - //--- calculation - ebest=0; - for(i=idx1;i<=idx2;i++) - ebest=ebest+CMath::Sqr(xy[bufs.m_idxbuf[i]][nvars]-v); - ebest=MathSqrt(ebest/(idx2-idx1+1)); - } -//--- change value - i=0; -//--- cycle - while(i<=MathMin(nfeatures,nvarsinpool)-1) - { - //--- select variables from pool - j=i+CMath::RandomInteger(nvarsinpool-i); - k=bufs.m_varpool[i]; - bufs.m_varpool[i]=bufs.m_varpool[j]; - bufs.m_varpool[j]=k; - varcur=bufs.m_varpool[i]; - //--- load variable values to working array - //--- apply EVS preprocessing: if all variable values are same, - //--- variable is excluded from pool. - //--- This is necessary for binary pre-splits (see later) to work. - for(j=idx1;j<=idx2;j++) - bufs.m_tmpbufr[j-idx1]=xy[bufs.m_idxbuf[j]][varcur]; - //--- check - if(useevs) - { - bflag=false; - v=bufs.m_tmpbufr[0]; - for(j=0;j<=idx2-idx1;j++) - { - //--- check - if(bufs.m_tmpbufr[j]!=v) - { - bflag=true; - break; - } - } - //--- check - if(!bflag) - { - //--- exclude variable from pool, - //--- go to the next iteration. - //--- I is not increased. - k=bufs.m_varpool[i]; - bufs.m_varpool[i]=bufs.m_varpool[nvarsinpool-1]; - bufs.m_varpool[nvarsinpool-1]=k; - nvarsinpool=nvarsinpool-1; - continue; - } - } - //--- load labels to working array - if(nclasses>1) - { - for(j=idx1;j<=idx2;j++) - bufs.m_tmpbufi[j-idx1]=(int)MathRound(xy[bufs.m_idxbuf[j]][nvars]); - } - else - { - for(j=idx1;j<=idx2;j++) - bufs.m_tmpbufr2[j-idx1]=xy[bufs.m_idxbuf[j]][nvars]; - } - //--- calculate split - if(useevs && bufs.m_evsbin[varcur]) - { - //--- Pre-calculated splits for binary variables. - //--- Threshold is already known,just calculate RMS error - threshold=bufs.m_evssplits[varcur]; - //--- check - if(nclasses>1) - { - //--- classification-specific code - for(j=0;j<=2*nclasses-1;j++) - bufs.m_classibuf[j]=0; - //--- change values - sl=0; - sr=0; - //--- calculation - for(j=0;j<=idx2-idx1;j++) - { - k=bufs.m_tmpbufi[j]; - //--- check - if(bufs.m_tmpbufr[j]1) - DFSplitC(bufs.m_tmpbufr,bufs.m_tmpbufi,bufs.m_classibuf,idx2-idx1+1,nclasses,m_dfusestrongsplits,info,threshold,currms,bufs.m_sortrbuf,bufs.m_sortibuf); - else - DFSplitR(bufs.m_tmpbufr,bufs.m_tmpbufr2,idx2-idx1+1,m_dfusestrongsplits,info,threshold,currms,bufs.m_sortrbuf,bufs.m_sortrbuf2); - } - //--- check - if(info>0) - { - //--- check - if(currms<=ebest) - { - ebest=currms; - idxbest=varcur; - tbest=threshold; - } - } - //--- Next iteration - i=i+1; - } -//--- to split or not to split - if(idxbest<0) - { - //--- All values are same,cannot split. - bufs.m_treebuf[numprocessed]=-1; - //--- check - if(nclasses>1) - { - //--- Select random class label (randomness allows us to - //--- approximate distribution of the classes) - bufs.m_treebuf[numprocessed+1]=(int)MathRound(xy[bufs.m_idxbuf[idx1+CMath::RandomInteger(idx2-idx1+1)]][nvars]); - } - else - { - //--- Select average (for regression task). - v=0; - for(i=idx1;i<=idx2;i++) - v=v+xy[bufs.m_idxbuf[i]][nvars]/(idx2-idx1+1); - bufs.m_treebuf[numprocessed+1]=v; - } - //--- change value - numprocessed=numprocessed+m_leafnodewidth; - } - else - { - //--- we can split - bufs.m_treebuf[numprocessed]=idxbest; - bufs.m_treebuf[numprocessed+1]=tbest; - i1=idx1; - i2=idx2; - //--- cycle - while(i1<=i2) - { - //--- Reorder indices so that left partition is in [Idx1..I1-1], - //--- and right partition is in [I2+1..Idx2] - if(xy[bufs.m_idxbuf[i1]][idxbest]=tbest) - { - i2=i2-1; - continue; - } - //--- change values - j=bufs.m_idxbuf[i1]; - bufs.m_idxbuf[i1]=bufs.m_idxbuf[i2]; - bufs.m_idxbuf[i2]=j; - i1=i1+1; - i2=i2-1; - } - //--- change values - oldnp=numprocessed; - numprocessed=numprocessed+m_innernodewidth; - //--- function call - DFBuildTreeRec(xy,npoints,nvars,nclasses,nfeatures,nvarsinpool,flags,numprocessed,idx1,i1-1,bufs); - bufs.m_treebuf[oldnp+2]=numprocessed; - //--- function call - DFBuildTreeRec(xy,npoints,nvars,nclasses,nfeatures,nvarsinpool,flags,numprocessed,i2+1,idx2,bufs); - } - } -//+------------------------------------------------------------------+ -//| Makes split on attribute | -//+------------------------------------------------------------------+ -static void CDForest::DFSplitC(double &x[],int &c[],int &cntbuf[],const int n, - const int nc,const int flags,int &info, - double &threshold,double &e,double &sortrbuf[], - int &sortibuf[]) - { -//--- create variables - int i=0; - int neq=0; - int nless=0; - int ngreater=0; - int q=0; - int qmin=0; - int qmax=0; - int qcnt=0; - double cursplit=0; - int nleft=0; - double v=0; - double cure=0; - double w=0; - double sl=0; - double sr=0; -//--- initialization - info=0; - threshold=0; - e=0; -//--- function call - CTSort::TagSortFastI(x,c,sortrbuf,sortibuf,n); -//--- change values - e=CMath::m_maxrealnumber; - threshold=0.5*(x[0]+x[n-1]); - info=-3; -//--- check - if(flags/m_dfusestrongsplits%2==0) - { - //--- weak splits,split at half - qcnt=2; - qmin=1; - qmax=1; - } - else - { - //--- strong splits: choose best quartile - qcnt=4; - qmin=1; - qmax=3; - } - for(q=qmin;q<=qmax;q++) - { - //--- change values - cursplit=x[n*q/qcnt]; - neq=0; - nless=0; - ngreater=0; - //--- calculation - for(i=0;i<=n-1;i++) - { - //--- check - if(x[i]cursplit) - ngreater=ngreater+1; - } - //--- check - if(!CAp::Assert(neq!=0,__FUNCTION__+": NEq=0,something strange!!!")) - return; - //--- check - if(nless!=0 || ngreater!=0) - { - //--- set threshold between two partitions, with - //--- some tweaking to avoid problems with floating point - //--- arithmetics. - //--- The problem is that when you calculates C = 0.5*(A+B) there - //--- can be no C which lies strictly between A and B (for example, - //--- there is no floating point number which is - //--- greater than 1 and less than 1+eps). In such situations - //--- we choose right side as theshold (remember that - //--- points which lie on threshold falls to the right side). - if(nlesscursplit) - ngreater=ngreater+1; - } - //--- check - if(!CAp::Assert(neq!=0,__FUNCTION__+": NEq=0,something strange!!!")) - return; - //--- check - if(nless!=0 || ngreater!=0) - { - //--- set threshold between two partitions, with - //--- some tweaking to avoid problems with floating point - //--- arithmetics. - //--- The problem is that when you calculates C = 0.5*(A+B) there - //--- can be no C which lies strictly between A and B (for example, - //--- there is no floating point number which is - //--- greater than 1 and less than 1+eps). In such situations - //--- we choose right side as theshold (remember that - //--- points which lie on threshold falls to the right side). - if(nless=K | -//| NVars - number of variables, NVars>=1 | -//| K - desired number of clusters, K>=1 | -//| Restarts - number of restarts, Restarts>=1 | -//| OUTPUT PARAMETERS: | -//| Info - return code: | -//| * -3, if task is degenerate (number of | -//| distinct points is less than K) | -//| * -1, if incorrect | -//| NPoints/NFeatures/K/Restarts was passed| -//| * 1, if subroutine finished successfully | -//| C - array[0..NVars-1,0..K-1].matrix whose columns| -//| store cluster's centers | -//| XYC - array[NPoints], which contains cluster | -//| indexes | -//+------------------------------------------------------------------+ -static void CKMeans::KMeansGenerate(CMatrixDouble &xy,const int npoints, - const int nvars,const int k, - const int restarts,int &info, - CMatrixDouble &c,int &xyc[]) - { -//--- create variables - int i=0; - int j=0; - double e=0; - double ebest=0; - double v=0; - int cclosest=0; - bool waschanges; - bool zerosizeclusters; - int pass=0; - int i_=0; - double dclosest=0; -//--- creating arrays - int xycbest[]; - double x[]; - double tmp[]; - double d2[]; - double p[]; - int csizes[]; - bool cbusy[]; - double work[]; -//--- create matrix - CMatrixDouble ct; - CMatrixDouble ctbest; -//--- initialization - info=0; -//--- Test parameters - if(npoints=0 | -//| NVars - number of independent variables, NVars>=1 | -//| NClasses - number of classes, NClasses>=2 | -//| OUTPUT PARAMETERS: | -//| Info - return code: | -//| * -4, if internal EVD subroutine hasn't | -//| converged | -//| * -2, if there is a point with class number | -//| outside of [0..NClasses-1]. | -//| * -1, if incorrect parameters was passed | -//| (NPoints<0, NVars<1, NClasses<2) | -//| * 1, if task has been solved | -//| * 2, if there was a multicollinearity in | -//| training set, but task has been solved.| -//| W - linear combination coefficients, | -//| array[0..NVars-1] | -//+------------------------------------------------------------------+ -static void CLDA::FisherLDA(CMatrixDouble &xy,const int npoints, - const int nvars,const int nclasses, - int &info,double &w[]) - { -//--- create a variable - int i_=0; -//--- create matrix - CMatrixDouble w2; -//--- initialization - info=0; -//--- function call - FisherLDAN(xy,npoints,nvars,nclasses,info,w2); -//--- check - if(info>0) - { - //--- allocation - ArrayResizeAL(w,nvars); - //--- copy - for(i_=0;i_<=nvars-1;i_++) - w[i_]=w2[i_][0]; - } - } -//+------------------------------------------------------------------+ -//| N-dimensional multiclass Fisher LDA | -//| Subroutine finds coefficients of linear combinations which | -//| optimally separates | -//| training set on classes. It returns N-dimensional basis whose | -//| vector are sorted | -//| by quality of training set separation (in descending order). | -//| INPUT PARAMETERS: | -//| XY - training set, array[0..NPoints-1,0..NVars]. | -//| First NVars columns store values of | -//| independent variables, next column stores | -//| number of class (from 0 to NClasses-1) which | -//| dataset element belongs to. Fractional values| -//| are rounded to nearest integer. | -//| NPoints - training set size, NPoints>=0 | -//| NVars - number of independent variables, NVars>=1 | -//| NClasses - number of classes, NClasses>=2 | -//| OUTPUT PARAMETERS: | -//| Info - return code: | -//| * -4, if internal EVD subroutine hasn't | -//| converged | -//| * -2, if there is a point with class number | -//| outside of [0..NClasses-1]. | -//| * -1, if incorrect parameters was passed | -//| (NPoints<0, NVars<1, NClasses<2) | -//| * 1, if task has been solved | -//| * 2, if there was a multicollinearity in | -//| training set, but task has been solved.| -//| W - basis, array[0..NVars-1,0..NVars-1] | -//| columns of matrix stores basis vectors, | -//| sorted by quality of training set separation | -//| (in descending order) | -//+------------------------------------------------------------------+ -static void CLDA::FisherLDAN(CMatrixDouble &xy,const int npoints,const int nvars, - const int nclasses,int &info,CMatrixDouble &w) - { -//--- create variables - int i=0; - int j=0; - int k=0; - int m=0; - double v=0; - int i_=0; -//--- creating arrays - int c[]; - double mu[]; - int nc[]; - double tf[]; - double d[]; - double d2[]; - double work[]; -//--- create matrix - CMatrixDouble muc; - CMatrixDouble sw; - CMatrixDouble st; - CMatrixDouble z; - CMatrixDouble z2; - CMatrixDouble tm; - CMatrixDouble sbroot; - CMatrixDouble a; - CMatrixDouble xyproj; - CMatrixDouble wproj; -//--- initialization - info=0; -//--- Test data - if((npoints<0 || nvars<1) || nclasses<2) - { - info=-1; - return; - } - for(i=0;i<=npoints-1;i++) - { - //--- check - if((int)MathRound(xy[i][nvars])<0 || (int)MathRound(xy[i][nvars])>=nclasses) - { - info=-2; - return; - } - } -//--- change value - info=1; -//--- Special case: NPoints<=1 -//--- Degenerate task. - if(npoints<=1) - { - info=2; - //--- allocation - w.Resize(nvars,nvars); - //--- initialization - for(i=0;i<=nvars-1;i++) - { - for(j=0;j<=nvars-1;j++) - { - //--- check - if(i==j) - w[i].Set(j,1); - else - w[i].Set(j,0); - } - } - //--- exit the function - return; - } -//--- Prepare temporaries - ArrayResizeAL(tf,nvars); - ArrayResizeAL(work,MathMax(nvars,npoints)+1); -//--- Convert class labels from reals to integers (just for convenience) - ArrayResizeAL(c,npoints); - for(i=0;i<=npoints-1;i++) - c[i]=(int)MathRound(xy[i][nvars]); -//--- Calculate class sizes and means - ArrayResizeAL(mu,nvars); - muc.Resize(nclasses,nvars); - ArrayResizeAL(nc,nclasses); - for(j=0;j<=nvars-1;j++) - mu[j]=0; - for(i=0;i<=nclasses-1;i++) - { - nc[i]=0; - for(j=0;j<=nvars-1;j++) - muc[i].Set(j,0); - } -//--- calculation - for(i=0;i<=npoints-1;i++) - { - for(i_=0;i_<=nvars-1;i_++) - mu[i_]=mu[i_]+xy[i][i_]; - for(i_=0;i_<=nvars-1;i_++) - muc[c[i]].Set(i_,muc[c[i]][i_]+xy[i][i_]); - nc[c[i]]=nc[c[i]]+1; - } - for(i=0;i<=nclasses-1;i++) - { - v=1.0/(double)nc[i]; - for(i_=0;i_<=nvars-1;i_++) - muc[i].Set(i_,v*muc[i][i_]); - } -//--- change values - v=1.0/(double)npoints; - for(i_=0;i_<=nvars-1;i_++) - mu[i_]=v*mu[i_]; -//--- Create ST matrix - st.Resize(nvars,nvars); - for(i=0;i<=nvars-1;i++) - { - for(j=0;j<=nvars-1;j++) - st[i].Set(j,0); - } -//--- calculation - for(k=0;k<=npoints-1;k++) - { - for(i_=0;i_<=nvars-1;i_++) - tf[i_]=xy[k][i_]; - for(i_=0;i_<=nvars-1;i_++) - tf[i_]=tf[i_]-mu[i_]; - for(i=0;i<=nvars-1;i++) - { - v=tf[i]; - for(i_=0;i_<=nvars-1;i_++) - st[i].Set(i_,st[i][i_]+v*tf[i_]); - } - } -//--- Create SW matrix - sw.Resize(nvars,nvars); - for(i=0;i<=nvars-1;i++) - { - for(j=0;j<=nvars-1;j++) - sw[i].Set(j,0); - } -//--- calculation - for(k=0;k<=npoints-1;k++) - { - for(i_=0;i_<=nvars-1;i_++) - tf[i_]=xy[k][i_]; - for(i_=0;i_<=nvars-1;i_++) - tf[i_]=tf[i_]-muc[c[k]][i_]; - for(i=0;i<=nvars-1;i++) - { - v=tf[i]; - for(i_=0;i_<=nvars-1;i_++) - sw[i].Set(i_,sw[i][i_]+v*tf[i_]); - } - } -//--- Maximize ratio J=(w'*ST*w)/(w'*SW*w). -//--- First,make transition from w to v such that w'*ST*w becomes v'*v: -//--- v=root(ST)*w=R*w -//--- R=root(D)*Z' -//--- w=(root(ST)^-1)*v=RI*v -//--- RI=Z*inv(root(D)) -//--- J=(v'*v)/(v'*(RI'*SW*RI)*v) -//--- ST=Z*D*Z' -//--- so we have -//--- J=(v'*v) / (v'*(inv(root(D))*Z'*SW*Z*inv(root(D)))*v)= -//=(v'*v) / (v'*A*v) - if(!CEigenVDetect::SMatrixEVD(st,nvars,1,true,d,z)) - { - info=-4; - return; - } -//--- allocation - w.Resize(nvars,nvars); -//--- check - if(d[nvars-1]<=0.0 || d[0]<=1000*CMath::m_machineepsilon*d[nvars-1]) - { - //--- Special case: D[NVars-1]<=0 - //--- Degenerate task (all variables takes the same value). - if(d[nvars-1]<=0.0) - { - info=2; - for(i=0;i<=nvars-1;i++) - { - for(j=0;j<=nvars-1;j++) - { - //--- check - if(i==j) - w[i].Set(j,1); - else - w[i].Set(j,0); - } - } - //--- exit the function - return; - } - //--- Special case: degenerate ST matrix,multicollinearity found. - //--- Since we know ST eigenvalues/vectors we can translate task to - //--- non-degenerate form. - //--- Let WG is orthogonal basis of the non zero variance subspace - //--- of the ST and let WZ is orthogonal basis of the zero variance - //--- subspace. - //--- Projection on WG allows us to use LDA on reduced M-dimensional - //--- subspace,N-M vectors of WZ allows us to update reduced LDA - //--- factors to full N-dimensional subspace. - m=0; - for(k=0;k<=nvars-1;k++) - { - //--- check - if(d[k]<=1000*CMath::m_machineepsilon*d[nvars-1]) - m=k+1; - } - //--- check - if(!CAp::Assert(m!=0,__FUNCTION__+": internal error #1")) - return; - //--- allocation - xyproj.Resize(npoints,nvars-m+1); - //--- function call - CBlas::MatrixMatrixMultiply(xy,0,npoints-1,0,nvars-1,false,z,0,nvars-1,m,nvars-1,false,1.0,xyproj,0,npoints-1,0,nvars-m-1,0.0,work); - for(i=0;i<=npoints-1;i++) - xyproj[i].Set(nvars-m,xy[i][nvars]); - //--- function call - FisherLDAN(xyproj,npoints,nvars-m,nclasses,info,wproj); - //--- check - if(info<0) - return; - //--- function call - CBlas::MatrixMatrixMultiply(z,0,nvars-1,m,nvars-1,false,wproj,0,nvars-m-1,0,nvars-m-1,false,1.0,w,0,nvars-1,0,nvars-m-1,0.0,work); - //--- change values - for(k=nvars-m;k<=nvars-1;k++) - { - for(i_=0;i_<=nvars-1;i_++) - w[i_].Set(k,z[i_][k-nvars+m]); - } - info=2; - } - else - { - //--- General case: no multicollinearity - tm.Resize(nvars,nvars); - a.Resize(nvars,nvars); - //--- function call - CBlas::MatrixMatrixMultiply(sw,0,nvars-1,0,nvars-1,false,z,0,nvars-1,0,nvars-1,false,1.0,tm,0,nvars-1,0,nvars-1,0.0,work); - CBlas::MatrixMatrixMultiply(z,0,nvars-1,0,nvars-1,true,tm,0,nvars-1,0,nvars-1,false,1.0,a,0,nvars-1,0,nvars-1,0.0,work); - //--- change values - for(i=0;i<=nvars-1;i++) - { - for(j=0;j<=nvars-1;j++) - a[i].Set(j,a[i][j]/MathSqrt(d[i]*d[j])); - } - //--- check - if(!CEigenVDetect::SMatrixEVD(a,nvars,1,true,d2,z2)) - { - info=-4; - return; - } - //--- calculation - for(k=0;k<=nvars-1;k++) - { - for(i=0;i<=nvars-1;i++) - tf[i]=z2[i][k]/MathSqrt(d[i]); - for(i=0;i<=nvars-1;i++) - { - v=0.0; - for(i_=0;i_<=nvars-1;i_++) - v+=z[i][i_]*tf[i_]; - w[i].Set(k,v); - } - } - } -//--- Post-processing: -//--- * normalization -//--- * converting to non-negative form,if possible - for(k=0;k<=nvars-1;k++) - { - //--- calculation - v=0.0; - for(i_=0;i_<=nvars-1;i_++) - v+=w[i_][k]*w[i_][k]; - v=1/MathSqrt(v); - for(i_=0;i_<=nvars-1;i_++) - w[i_].Set(k,v*w[i_][k]); - v=0; - for(i=0;i<=nvars-1;i++) - v=v+w[i][k]; - //--- check - if(v<0.0) - { - for(i_=0;i_<=nvars-1;i_++) - w[i_].Set(k,-1*w[i_][k]); - } - } - } -//+------------------------------------------------------------------+ -//| Auxiliary class for CLinReg | -//+------------------------------------------------------------------+ -class CLinearModel - { -public: - double m_w[]; - //--- constructor, destructor - CLinearModel(void); - ~CLinearModel(void); - //--- copy - void Copy(CLinearModel &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CLinearModel::CLinearModel(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CLinearModel::~CLinearModel(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CLinearModel::Copy(CLinearModel &obj) - { -//--- copy array - ArrayCopy(m_w,obj.m_w); - } -//+------------------------------------------------------------------+ -//| This class is a shell for class CLinearModel | -//+------------------------------------------------------------------+ -class CLinearModelShell - { -private: - CLinearModel m_innerobj; -public: - //--- constructors, destructor - CLinearModelShell(void); - CLinearModelShell(CLinearModel &obj); - ~CLinearModelShell(void); - //--- method - CLinearModel *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CLinearModelShell::CLinearModelShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CLinearModelShell::CLinearModelShell(CLinearModel &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CLinearModelShell::~CLinearModelShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CLinearModel *CLinearModelShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| LRReport structure contains additional information about linear | -//| model: | -//| * C - covariation matrix, array[0..NVars,0..NVars].| -//| C[i,j] = Cov(A[i],A[j]) | -//| * RMSError - root mean square error on a training set | -//| * AvgError - average error on a training set | -//| * AvgRelError - average relative error on a training set | -//| (excluding observations with zero function | -//| value). | -//| * CVRMSError - leave-one-out cross-validation estimate of | -//| generalization error. Calculated using fast | -//| algorithm with O(NVars*NPoints) complexity. | -//| * CVAvgError - cross-validation estimate of average error | -//| * CVAvgRelError - cross-validation estimate of average relative| -//| error | -//| All other fields of the structure are intended for internal use | -//| and should not be used outside ALGLIB. | -//+------------------------------------------------------------------+ -class CLRReport - { -public: - //--- variables - double m_rmserror; - double m_avgerror; - double m_avgrelerror; - double m_cvrmserror; - double m_cvavgerror; - double m_cvavgrelerror; - int m_ncvdefects; - //--- array - int m_cvdefects[]; - //--- matrix - CMatrixDouble m_c; - //--- constructor, destructor - CLRReport(void); - ~CLRReport(void); - //--- copy - void Copy(CLRReport &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CLRReport::CLRReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CLRReport::~CLRReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CLRReport::Copy(CLRReport &obj) - { -//--- copy variables - m_rmserror=obj.m_rmserror; - m_avgerror=obj.m_avgerror; - m_avgrelerror=obj.m_avgrelerror; - m_cvrmserror=obj.m_cvrmserror; - m_cvavgerror=obj.m_cvavgerror; - m_cvavgrelerror=obj.m_cvavgrelerror; - m_ncvdefects=obj.m_ncvdefects; -//--- copy array - ArrayCopy(m_cvdefects,obj.m_cvdefects); -//--- copy matrix - m_c=obj.m_c; - } -//+------------------------------------------------------------------+ -//| LRReport structure contains additional information about linear | -//| model: | -//| * C - covariation matrix, array[0..NVars,0..NVars].| -//| C[i,j]=Cov(A[i],A[j]) | -//| * RMSError - root mean square error on a training set | -//| * AvgError - average error on a training set | -//| * AvgRelError - average relative error on a training set | -//| (excluding observations with zero function | -//| value). | -//| * CVRMSError - leave-one-out cross-validation estimate of | -//| generalization error. Calculated using fast | -//| algorithm with O(NVars*NPoints) complexity. | -//| * CVAvgError - cross-validation estimate of average error | -//| * CVAvgRelError - cross-validation estimate of average relative| -//| error | -//| All other fields of the structure are intended for internal use | -//| and should not be used outside ALGLIB. | -//+------------------------------------------------------------------+ -class CLRReportShell - { -private: - CLRReport m_innerobj; -public: - //--- constructors, destructor - CLRReportShell(void); - CLRReportShell(CLRReport &obj); - ~CLRReportShell(void); - //--- methods - double GetRMSError(void); - void SetRMSError(const double d); - double GetAvgError(void); - void SetAvgError(const double d); - double GetAvgRelError(void); - void SetAvgRelError(const double d); - double GetCVRMSError(void); - void SetCVRMSError(const double d); - double GetCVAvgError(void); - void SetCVAvgError(const double d); - double GetCVAvgRelError(void); - void SetCVAvgRelError(const double d); - int GetNCVDEfects(void); - void SetNCVDEfects(const int i); - CLRReport *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CLRReportShell::CLRReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CLRReportShell::CLRReportShell(CLRReport &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CLRReportShell::~CLRReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable rmserror | -//+------------------------------------------------------------------+ -double CLRReportShell::GetRMSError(void) - { -//--- return result - return(m_innerobj.m_rmserror); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable rmserror | -//+------------------------------------------------------------------+ -void CLRReportShell::SetRMSError(const double d) - { -//--- change value - m_innerobj.m_rmserror=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable avgerror | -//+------------------------------------------------------------------+ -double CLRReportShell::GetAvgError(void) - { -//--- return result - return(m_innerobj.m_avgerror); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable avgerror | -//+------------------------------------------------------------------+ -void CLRReportShell::SetAvgError(const double d) - { -//--- change value - m_innerobj.m_avgerror=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable avgrelerror | -//+------------------------------------------------------------------+ -double CLRReportShell::GetAvgRelError(void) - { -//--- return result - return(m_innerobj.m_avgrelerror); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable avgrelerror | -//+------------------------------------------------------------------+ -void CLRReportShell::SetAvgRelError(const double d) - { -//--- change value - m_innerobj.m_avgrelerror=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable cvrmserror | -//+------------------------------------------------------------------+ -double CLRReportShell::GetCVRMSError(void) - { -//--- return result - return(m_innerobj.m_cvrmserror); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable cvrmserror | -//+------------------------------------------------------------------+ -void CLRReportShell::SetCVRMSError(const double d) - { -//--- change value - m_innerobj.m_cvrmserror=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable cvavgerror | -//+------------------------------------------------------------------+ -double CLRReportShell::GetCVAvgError(void) - { -//--- return result - return(m_innerobj.m_cvavgerror); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable cvavgerror | -//+------------------------------------------------------------------+ -void CLRReportShell::SetCVAvgError(const double d) - { -//--- change value - m_innerobj.m_cvavgerror=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable cvavgrelerror | -//+------------------------------------------------------------------+ -double CLRReportShell::GetCVAvgRelError(void) - { -//--- return result - return(m_innerobj.m_cvavgrelerror); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable cvavgrelerror | -//+------------------------------------------------------------------+ -void CLRReportShell::SetCVAvgRelError(const double d) - { -//--- change value - m_innerobj.m_cvavgrelerror=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable ncvdefects | -//+------------------------------------------------------------------+ -int CLRReportShell::GetNCVDEfects(void) - { -//--- return result - return(m_innerobj.m_ncvdefects); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable ncvdefects | -//+------------------------------------------------------------------+ -void CLRReportShell::SetNCVDEfects(const int i) - { -//--- change value - m_innerobj.m_ncvdefects=i; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CLRReport *CLRReportShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Linear regression class | -//+------------------------------------------------------------------+ -class CLinReg - { -private: - //--- private method - static void LRInternal(CMatrixDouble &xy,double &s[],const int npoints,const int nvars,int &info,CLinearModel &lm,CLRReport &ar); -public: - //--- constant - static const int m_lrvnum; - //--- constructor, destructor - CLinReg(void); - ~CLinReg(void); - //--- public methods - static void LRBuild(CMatrixDouble &xy,const int npoints,const int nvars,int &info,CLinearModel &lm,CLRReport &ar); - static void LRBuildS(CMatrixDouble &xy,double &s[],const int npoints,const int nvars,int &info,CLinearModel &lm,CLRReport &ar); - static void LRBuildZS(CMatrixDouble &xy,double &s[],const int npoints,const int nvars,int &info,CLinearModel &lm,CLRReport &ar); - static void LRBuildZ(CMatrixDouble &xy,const int npoints,const int nvars,int &info,CLinearModel &lm,CLRReport &ar); - static void LRUnpack(CLinearModel &lm,double &v[],int &nvars); - static void LRPack(double &v[],const int nvars,CLinearModel &lm); - static double LRProcess(CLinearModel &lm,double &x[]); - static double LRRMSError(CLinearModel &lm,CMatrixDouble &xy,const int npoints); - static double LRAvgError(CLinearModel &lm,CMatrixDouble &xy,const int npoints); - static double LRAvgRelError(CLinearModel &lm,CMatrixDouble &xy,const int npoints); - static void LRCopy(CLinearModel &lm1,CLinearModel &lm2); - static void LRLines(CMatrixDouble &xy,double &s[],const int n,int &info,double &a,double &b,double &vara,double &varb,double &covab,double &corrab,double &p); - static void LRLine(CMatrixDouble &xy,const int n,int &info,double &a,double &b); - }; -//+------------------------------------------------------------------+ -//| Initialize constant | -//+------------------------------------------------------------------+ -const int CLinReg::m_lrvnum=5; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CLinReg::CLinReg(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CLinReg::~CLinReg(void) - { - - } -//+------------------------------------------------------------------+ -//| Linear regression | -//| Subroutine builds model: | -//| Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + A(N) | -//| and model found in ALGLIB format, covariation matrix, training | -//| set errors (rms, average, average relative) and leave-one-out | -//| cross-validation estimate of the generalization error. CV | -//| estimate calculated using fast algorithm with O(NPoints*NVars) | -//| complexity. | -//| When covariation matrix is calculated standard deviations of| -//| function values are assumed to be equal to RMS error on the | -//| training set. | -//| INPUT PARAMETERS: | -//| XY - training set, array [0..NPoints-1,0..NVars]: | -//| * NVars columns - independent variables | -//| * last column - dependent variable | -//| NPoints - training set size, NPoints>NVars+1 | -//| NVars - number of independent variables | -//| OUTPUT PARAMETERS: | -//| Info - return code: | -//| * -255, in case of unknown internal error | -//| * -4, if internal SVD subroutine haven't | -//| converged | -//| * -1, if incorrect parameters was passed | -//| (NPoints0. | -//| NPoints - training set size, NPoints>NVars+1 | -//| NVars - number of independent variables | -//| OUTPUT PARAMETERS: | -//| Info - return code: | -//| * -255, in case of unknown internal error | -//| * -4, if internal SVD subroutine haven't | -//| converged | -//| * -1, if incorrect parameters was passed | -//| (NPointsMathSqrt(variance)) - { - //--- variation is relatively small,it is better to - //--- bring mean value to 1 - c[j]=mean; - } - else - { - //--- variation is large,it is better to bring variance to 1 - if(variance==0.0) - variance=1; - c[j]=MathSqrt(variance); - } - for(i=0;i<=npoints-1;i++) - xyi[i].Set(j,xyi[i][j]/c[j]); - } -//--- Internal processing - LRInternal(xyi,s,npoints,nvars+1,info,lm,ar); -//--- check - if(info<0) - return; -//--- Un-standartization - offs=(int)MathRound(lm.m_w[3]); - for(j=0;j<=nvars-1;j++) - { - //--- J-th term is updated - lm.m_w[offs+j]=lm.m_w[offs+j]/c[j]; - v=1/c[j]; - for(i_=0;i_<=nvars;i_++) - ar.m_c[j].Set(i_,v*ar.m_c[j][i_]); - for(i_=0;i_<=nvars;i_++) - ar.m_c[i_].Set(j,v*ar.m_c[i_][j]); - } - } -//+------------------------------------------------------------------+ -//| Like LRBuild but builds model | -//| Y=A(0)*X[0] + ... + A(N-1)*X[N-1] | -//| i.m_e. with zero constant term. | -//+------------------------------------------------------------------+ -static void CLinReg::LRBuildZ(CMatrixDouble &xy,const int npoints,const int nvars, - int &info,CLinearModel &lm,CLRReport &ar) - { -//--- create variables - int i=0; - double sigma2=0; - int i_=0; -//--- create array - double s[]; -//--- initialization - info=0; -//--- check - if(npoints<=nvars+1 || nvars<1) - { - info=-1; - return; - } -//--- allocation - ArrayResizeAL(s,npoints); - for(i=0;i<=npoints-1;i++) - s[i]=1; -//--- function call - LRBuildZS(xy,s,npoints,nvars,info,lm,ar); -//--- check - if(info<0) - return; -//--- calculation - sigma2=CMath::Sqr(ar.m_rmserror)*npoints/(npoints-nvars-1); - for(i=0;i<=nvars;i++) - { - for(i_=0;i_<=nvars;i_++) - ar.m_c[i].Set(i_,sigma2*ar.m_c[i][i_]); - } - } -//+------------------------------------------------------------------+ -//| Unpacks coefficients of linear model. | -//| INPUT PARAMETERS: | -//| LM - linear model in ALGLIB format | -//| OUTPUT PARAMETERS: | -//| V - coefficients,array[0..NVars] | -//| constant term (intercept) is stored in the | -//| V[NVars]. | -//| NVars - number of independent variables (one less | -//| than number of coefficients) | -//+------------------------------------------------------------------+ -static void CLinReg::LRUnpack(CLinearModel &lm,double &v[],int &nvars) - { -//--- create variables - int offs=0; - int i_=0; - int i1_=0; -//--- initialization - nvars=0; -//--- check - if(!CAp::Assert((int)MathRound(lm.m_w[1])==m_lrvnum,__FUNCTION__+": Incorrect LINREG version!")) - return; -//--- change values - nvars=(int)MathRound(lm.m_w[2]); - offs=(int)MathRound(lm.m_w[3]); -//--- allocation - ArrayResizeAL(v,nvars+1); -//--- calculation - i1_=offs; - for(i_=0;i_<=nvars;i_++) - v[i_]=lm.m_w[i_+i1_]; - } -//+------------------------------------------------------------------+ -//| "Packs" coefficients and creates linear model in ALGLIB format | -//| (LRUnpack reversed). | -//| INPUT PARAMETERS: | -//| V - coefficients, array[0..NVars] | -//| NVars - number of independent variables | -//| OUTPUT PAREMETERS: | -//| LM - linear model. | -//+------------------------------------------------------------------+ -static void CLinReg::LRPack(double &v[],const int nvars,CLinearModel &lm) - { -//--- create variables - int offs=0; - int i_=0; - int i1_=0; -//--- allocation - ArrayResizeAL(lm.m_w,5+nvars); -//--- change values - offs=4; - lm.m_w[0]=4+nvars+1; - lm.m_w[1]=m_lrvnum; - lm.m_w[2]=nvars; - lm.m_w[3]=offs; -//--- calculation - i1_=-offs; - for(i_=offs;i_<=offs+nvars;i_++) - lm.m_w[i_]=v[i_+i1_]; - } -//+------------------------------------------------------------------+ -//| Procesing | -//| INPUT PARAMETERS: | -//| LM - linear model | -//| X - input vector, array[0..NVars-1]. | -//| Result: | -//| value of linear model regression estimate | -//+------------------------------------------------------------------+ -static double CLinReg::LRProcess(CLinearModel &lm,double &x[]) - { -//--- create variables - double v=0; - int offs=0; - int nvars=0; - int i_=0; - int i1_=0; -//--- check - if(!CAp::Assert((int)MathRound(lm.m_w[1])==m_lrvnum,__FUNCTION__+": Incorrect LINREG version!")) - return(EMPTY_VALUE); -//--- change values - nvars=(int)MathRound(lm.m_w[2]); - offs=(int)MathRound(lm.m_w[3]); - i1_=offs; - v=0.0; -//--- calculation - for(i_=0;i_<=nvars-1;i_++) - v+=x[i_]*lm.m_w[i_+i1_]; -//--- return result - return(v+lm.m_w[offs+nvars]); - } -//+------------------------------------------------------------------+ -//| RMS error on the test set | -//| INPUT PARAMETERS: | -//| LM - linear model | -//| XY - test set | -//| NPoints - test set size | -//| RESULT: | -//| root mean square error. | -//+------------------------------------------------------------------+ -static double CLinReg::LRRMSError(CLinearModel &lm,CMatrixDouble &xy, - const int npoints) - { -//--- create variables - double result=0; - int i=0; - double v=0; - int offs=0; - int nvars=0; - int i_=0; - int i1_=0; -//--- check - if(!CAp::Assert((int)MathRound(lm.m_w[1])==m_lrvnum,__FUNCTION__+": Incorrect LINREG version!")) - return(EMPTY_VALUE); -//--- change values - nvars=(int)MathRound(lm.m_w[2]); - offs=(int)MathRound(lm.m_w[3]); - result=0; -//--- calculation - for(i=0;i<=npoints-1;i++) - { - i1_=offs; - v=0.0; - for(i_=0;i_<=nvars-1;i_++) - v+=xy[i][i_]*lm.m_w[i_+i1_]; - v=v+lm.m_w[offs+nvars]; - result=result+CMath::Sqr(v-xy[i][nvars]); - } -//--- return result - return(MathSqrt(result/npoints)); - } -//+------------------------------------------------------------------+ -//| Average error on the test set | -//| INPUT PARAMETERS: | -//| LM - linear model | -//| XY - test set | -//| NPoints - test set size | -//| RESULT: | -//| average error. | -//+------------------------------------------------------------------+ -static double CLinReg::LRAvgError(CLinearModel &lm,CMatrixDouble &xy, - const int npoints) - { -//--- create variables - double result=0; - int i=0; - double v=0; - int offs=0; - int nvars=0; - int i_=0; - int i1_=0; -//--- check - if(!CAp::Assert((int)MathRound(lm.m_w[1])==m_lrvnum,__FUNCTION__+": Incorrect LINREG version!")) - return(EMPTY_VALUE); -//--- initialization - nvars=(int)MathRound(lm.m_w[2]); - offs=(int)MathRound(lm.m_w[3]); - result=0; -//--- calculation - for(i=0;i<=npoints-1;i++) - { - i1_=offs; - v=0.0; - for(i_=0;i_<=nvars-1;i_++) - v+=xy[i][i_]*lm.m_w[i_+i1_]; - v=v+lm.m_w[offs+nvars]; - result=result+MathAbs(v-xy[i][nvars]); - } -//--- return result - return(result/npoints); - } -//+------------------------------------------------------------------+ -//| RMS error on the test set | -//| INPUT PARAMETERS: | -//| LM - linear model | -//| XY - test set | -//| NPoints - test set size | -//| RESULT: | -//| average relative error. | -//+------------------------------------------------------------------+ -static double CLinReg::LRAvgRelError(CLinearModel &lm,CMatrixDouble &xy, - const int npoints) - { -//--- create variables - double result=0; - int i=0; - int k=0; - double v=0; - int offs=0; - int nvars=0; - int i_=0; - int i1_=0; -//--- check - if(!CAp::Assert((int)MathRound(lm.m_w[1])==m_lrvnum,__FUNCTION__+": Incorrect LINREG version!")) - return(EMPTY_VALUE); -//--- initialization - nvars=(int)MathRound(lm.m_w[2]); - offs=(int)MathRound(lm.m_w[3]); - result=0; - k=0; -//--- calculation - for(i=0;i<=npoints-1;i++) - { - //--- check - if(xy[i][nvars]!=0.0) - { - i1_=offs; - v=0.0; - for(i_=0;i_<=nvars-1;i_++) - v+=xy[i][i_]*lm.m_w[i_+i1_]; - v=v+lm.m_w[offs+nvars]; - //--- get result - result=result+MathAbs((v-xy[i][nvars])/xy[i][nvars]); - k=k+1; - } - } -//--- check - if(k!=0) - result=result/k; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Copying of LinearModel strucure | -//| INPUT PARAMETERS: | -//| LM1 - original | -//| OUTPUT PARAMETERS: | -//| LM2 - copy | -//+------------------------------------------------------------------+ -static void CLinReg::LRCopy(CLinearModel &lm1,CLinearModel &lm2) - { -//--- create variables - int k=0; - int i_=0; -//--- initialization - k=(int)MathRound(lm1.m_w[0]); -//--- allocation - ArrayResizeAL(lm2.m_w,k); -//--- copy - for(i_=0;i_<=k-1;i_++) - lm2.m_w[i_]=lm1.m_w[i_]; - } -//+------------------------------------------------------------------+ -//| Class method | -//+------------------------------------------------------------------+ -static void CLinReg::LRLines(CMatrixDouble &xy,double &s[],const int n, - int &info,double &a,double &b,double &vara, - double &varb,double &covab,double &corrab, - double &p) - { -//--- create variables - int i=0; - double ss=0; - double sx=0; - double sxx=0; - double sy=0; - double stt=0; - double e1=0; - double e2=0; - double t=0; - double chi2=0; -//--- initialization - info=0; - a=0; - b=0; - vara=0; - varb=0; - covab=0; - corrab=0; - p=0; -//--- check - if(n<2) - { - info=-1; - return; - } - for(i=0;i<=n-1;i++) - { - //--- check - if((double)(s[i])<=0.0) - { - info=-2; - return; - } - } -//--- change value - info=1; -//--- Calculate S,SX,SY,SXX - ss=0; - sx=0; - sy=0; - sxx=0; -//--- calculation - for(i=0;i<=n-1;i++) - { - t=CMath::Sqr(s[i]); - ss=ss+1/t; - sx=sx+xy[i][0]/t; - sy=sy+xy[i][1]/t; - sxx=sxx+CMath::Sqr(xy[i][0])/t; - } -//--- Test for condition number - t=MathSqrt(4*CMath::Sqr(sx)+CMath::Sqr(ss-sxx)); - e1=0.5*(ss+sxx+t); - e2=0.5*(ss+sxx-t); -//--- check - if(MathMin(e1,e2)<=1000*CMath::m_machineepsilon*MathMax(e1,e2)) - { - info=-3; - return; - } -//--- Calculate A,B - a=0; - b=0; - stt=0; -//--- calculation - for(i=0;i<=n-1;i++) - { - t=(xy[i][0]-sx/ss)/s[i]; - b=b+t*xy[i][1]/s[i]; - stt=stt+CMath::Sqr(t); - } - b=b/stt; - a=(sy-sx*b)/ss; -//--- Calculate goodness-of-fit - if(n>2) - { - chi2=0; - for(i=0;i<=n-1;i++) - chi2=chi2+CMath::Sqr((xy[i][1]-a-b*xy[i][0])/s[i]); - //--- function call - p=CIncGammaF::IncompleteGammaC((double)(n-2)/(double)2,chi2/2); - } - else - p=1; -//--- Calculate other parameters - vara=(1+CMath::Sqr(sx)/(ss*stt))/ss; - varb=1/stt; - covab=-(sx/(ss*stt)); - corrab=covab/MathSqrt(vara*varb); - } -//+------------------------------------------------------------------+ -//| Class method | -//+------------------------------------------------------------------+ -static void CLinReg::LRLine(CMatrixDouble &xy,const int n,int &info, - double &a,double &b) - { -//--- create variables - int i=0; - double vara=0; - double varb=0; - double covab=0; - double corrab=0; - double p=0; -//--- create array - double s[]; -//--- initialization - info=0; - a=0; - b=0; -//--- check - if(n<2) - { - info=-1; - return; - } -//--- allocation - ArrayResizeAL(s,n); - for(i=0;i<=n-1;i++) - s[i]=1; -//--- function call - LRLines(xy,s,n,info,a,b,vara,varb,covab,corrab,p); - } -//+------------------------------------------------------------------+ -//| Internal linear regression subroutine | -//+------------------------------------------------------------------+ -static void CLinReg::LRInternal(CMatrixDouble &xy,double &s[],const int npoints, - const int nvars,int &info,CLinearModel &lm, - CLRReport &ar) - { -//--- create variables - int i=0; - int j=0; - int k=0; - int ncv=0; - int na=0; - int nacv=0; - double r=0; - double p=0; - double epstol=0; - int offs=0; - int i_=0; - int i1_=0; -//--- creating arrays - double b[]; - double sv[]; - double t[]; - double svi[]; - double work[]; -//--- create matrix - CMatrixDouble a; - CMatrixDouble u; - CMatrixDouble vt; - CMatrixDouble vm; - CMatrixDouble xym; -//--- create objects of classes - CLRReport ar2; - CLinearModel tlm; -//--- initialization - info=0; - epstol=1000; -//--- Check for errors in data - if(npoints=1;k--) - { - //--- check - if(sv[k-1]>epstol*CMath::m_machineepsilon*sv[0]) - { - //--- Reduce - xym.Resize(npoints,k+1); - for(i=0;i<=npoints-1;i++) - { - for(j=0;j<=k-1;j++) - { - //--- calculation - r=0.0; - for(i_=0;i_<=nvars-1;i_++) - r+=xy[i][i_]*vt[j][i_]; - xym[i].Set(j,r); - } - xym[i].Set(k,xy[i][nvars]); - } - //--- Solve - LRInternal(xym,s,npoints,k,info,tlm,ar2); - //--- check - if(info!=1) - return; - //--- Convert back to un-reduced format - for(j=0;j<=nvars-1;j++) - lm.m_w[offs+j]=0; - for(j=0;j<=k-1;j++) - { - r=tlm.m_w[offs+j]; - i1_=-offs; - for(i_=offs;i_<=offs+nvars-1;i_++) - lm.m_w[i_]=lm.m_w[i_]+r*vt[j][i_+i1_]; - } - //--- change values - ar.m_rmserror=ar2.m_rmserror; - ar.m_avgerror=ar2.m_avgerror; - ar.m_avgrelerror=ar2.m_avgrelerror; - ar.m_cvrmserror=ar2.m_cvrmserror; - ar.m_cvavgerror=ar2.m_cvavgerror; - ar.m_cvavgrelerror=ar2.m_cvavgrelerror; - ar.m_ncvdefects=ar2.m_ncvdefects; - //--- allocation - ArrayResizeAL(ar.m_cvdefects,nvars); - for(j=0;j<=ar.m_ncvdefects-1;j++) - ar.m_cvdefects[j]=ar2.m_cvdefects[j]; - //--- allocation - ar.m_c.Resize(nvars,nvars); - ArrayResizeAL(work,nvars+1); - //--- function calls - CBlas::MatrixMatrixMultiply(ar2.m_c,0,k-1,0,k-1,false,vt,0,k-1,0,nvars-1,false,1.0,vm,0,k-1,0,nvars-1,0.0,work); - CBlas::MatrixMatrixMultiply(vt,0,k-1,0,nvars-1,true,vm,0,k-1,0,nvars-1,false,1.0,ar.m_c,0,nvars-1,0,nvars-1,0.0,work); - //--- exit the function - return; - } - } - //--- change value - info=-255; - //--- exit the function - return; - } -//--- change values - for(i=0;i<=nvars-1;i++) - { - //--- check - if(sv[i]>epstol*CMath::m_machineepsilon*sv[0]) - svi[i]=1/sv[i]; - else - svi[i]=0; - } -//--- change values - for(i=0;i<=nvars-1;i++) - t[i]=0; -//--- change values - for(i=0;i<=npoints-1;i++) - { - r=b[i]; - for(i_=0;i_<=nvars-1;i_++) - t[i_]=t[i_]+r*u[i][i_]; - } - for(i=0;i<=nvars-1;i++) - lm.m_w[offs+i]=0; -//--- calculation - for(i=0;i<=nvars-1;i++) - { - r=t[i]*svi[i]; - i1_=-offs; - for(i_=offs;i_<=offs+nvars-1;i_++) - lm.m_w[i_]=lm.m_w[i_]+r*vt[i][i_+i1_]; - } -//--- calculation - for(j=0;j<=nvars-1;j++) - { - r=svi[j]; - for(i_=0;i_<=nvars-1;i_++) - vm[i_].Set(j,r*vt[j][i_]); - } -//--- calculation - for(i=0;i<=nvars-1;i++) - { - for(j=i;j<=nvars-1;j++) - { - r=0.0; - for(i_=0;i_<=nvars-1;i_++) - r+=vm[i][i_]*vm[j][i_]; - ar.m_c[i].Set(j,r); - ar.m_c[j].Set(i,r); - } - } -//--- Leave-1-out cross-validation error. -//--- NOTATIONS: -//--- A design matrix -//--- A*x = b original linear least squares task -//--- U*S*V' SVD of A -//--- ai i-th row of the A -//--- bi i-th element of the b -//--- xf solution of the original LLS task -//--- Cross-validation error of i-th element from a sample is -//--- calculated using following formula: -//--- ERRi = ai*xf - (ai*xf-bi*(ui*ui'))/(1-ui*ui') (1) -//--- This formula can be derived from normal equations of the -//--- original task -//--- (A'*A)x = A'*b (2) -//--- by applying modification (zeroing out i-th row of A) to (2): -//--- (A-ai)'*(A-ai) = (A-ai)'*b -//--- and using Sherman-Morrison formula for updating matrix inverse -//--- NOTE 1: b is not zeroed out since it is much simpler and -//--- does not influence final result. -//--- NOTE 2: some design matrices A have such ui that 1-ui*ui'=0. -//--- Formula (1) can't be applied for such cases and they are skipped -//--- from CV calculation (which distorts resulting CV estimate). -//--- But from the properties of U we can conclude that there can -//--- be no more than NVars such vectors. Usually -//--- NVars << NPoints, so in a normal case it only slightly -//--- influences result. - ncv=0; - na=0; - nacv=0; - ar.m_rmserror=0; - ar.m_avgerror=0; - ar.m_avgrelerror=0; - ar.m_cvrmserror=0; - ar.m_cvavgerror=0; - ar.m_cvavgrelerror=0; - ar.m_ncvdefects=0; -//--- allocation - ArrayResizeAL(ar.m_cvdefects,nvars); - for(i=0;i<=npoints-1;i++) - { - //--- Error on a training set - i1_=offs; - r=0.0; - for(i_=0;i_<=nvars-1;i_++) - r+=xy[i][i_]*lm.m_w[i_+i1_]; - //--- change values - ar.m_rmserror=ar.m_rmserror+CMath::Sqr(r-xy[i][nvars]); - ar.m_avgerror=ar.m_avgerror+MathAbs(r-xy[i][nvars]); - //--- check - if(xy[i][nvars]!=0.0) - { - ar.m_avgrelerror=ar.m_avgrelerror+MathAbs((r-xy[i][nvars])/xy[i][nvars]); - na=na+1; - } - //--- Error using fast leave-one-out cross-validation - p=0.0; - for(i_=0;i_<=nvars-1;i_++) - p+=u[i][i_]*u[i][i_]; - //--- check - if(p>1-epstol*CMath::m_machineepsilon) - { - ar.m_cvdefects[ar.m_ncvdefects]=i; - ar.m_ncvdefects=ar.m_ncvdefects+1; - continue; - } - //--- change values - r=s[i]*(r/s[i]-b[i]*p)/(1-p); - ar.m_cvrmserror=ar.m_cvrmserror+CMath::Sqr(r-xy[i][nvars]); - ar.m_cvavgerror=ar.m_cvavgerror+MathAbs(r-xy[i][nvars]); - //--- check - if(xy[i][nvars]!=0.0) - { - ar.m_cvavgrelerror=ar.m_cvavgrelerror+MathAbs((r-xy[i][nvars])/xy[i][nvars]); - nacv=nacv+1; - } - ncv=ncv+1; - } -//--- check - if(ncv==0) - { - //--- Something strange: ALL ui are degenerate. - //--- Unexpected... - info=-255; - //--- exit the function - return; - } -//--- change values - ar.m_rmserror=MathSqrt(ar.m_rmserror/npoints); - ar.m_avgerror=ar.m_avgerror/npoints; -//--- check - if(na!=0) - ar.m_avgrelerror=ar.m_avgrelerror/na; - ar.m_cvrmserror=MathSqrt(ar.m_cvrmserror/ncv); - ar.m_cvavgerror=ar.m_cvavgerror/ncv; -//--- check - if(nacv!=0) - ar.m_cvavgrelerror=ar.m_cvavgrelerror/nacv; - } -//+------------------------------------------------------------------+ -//| Auxiliary class for CMLPBase | -//+------------------------------------------------------------------+ -class CMultilayerPerceptron - { -public: - //--- variables - int m_hlnetworktype; - int m_hlnormtype; - //--- arrays - int m_hllayersizes[]; - int m_hlconnections[]; - int m_hlneurons[]; - int m_structinfo[]; - double m_weights[]; - double m_columnmeans[]; - double m_columnsigmas[]; - double m_neurons[]; - double m_dfdnet[]; - double m_derror[]; - double m_x[]; - double m_y[]; - double m_nwbuf[]; - int m_integerbuf[]; - //--- matrix - CMatrixDouble m_chunks; - //--- constructor, destructor - CMultilayerPerceptron(void); - ~CMultilayerPerceptron(void); - //--- copy - void Copy(CMultilayerPerceptron &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMultilayerPerceptron::CMultilayerPerceptron(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMultilayerPerceptron::~CMultilayerPerceptron(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CMultilayerPerceptron::Copy(CMultilayerPerceptron &obj) - { -//--- copy variables - m_hlnetworktype=obj.m_hlnetworktype; - m_hlnormtype=obj.m_hlnormtype; -//--- copy arrays - ArrayCopy(m_hllayersizes,obj.m_hllayersizes); - ArrayCopy(m_hlconnections,obj.m_hlconnections); - ArrayCopy(m_hlneurons,obj.m_hlneurons); - ArrayCopy(m_structinfo,obj.m_structinfo); - ArrayCopy(m_weights,obj.m_weights); - ArrayCopy(m_columnmeans,obj.m_columnmeans); - ArrayCopy(m_columnsigmas,obj.m_columnsigmas); - ArrayCopy(m_neurons,obj.m_neurons); - ArrayCopy(m_dfdnet,obj.m_dfdnet); - ArrayCopy(m_derror,obj.m_derror); - ArrayCopy(m_x,obj.m_x); - ArrayCopy(m_y,obj.m_y); - ArrayCopy(m_nwbuf,obj.m_nwbuf); - ArrayCopy(m_integerbuf,obj.m_integerbuf); -//--- copy matrix - m_chunks=obj.m_chunks; - } -//+------------------------------------------------------------------+ -//| This class is a shell for class CMultilayerPerceptron | -//+------------------------------------------------------------------+ -class CMultilayerPerceptronShell - { -private: - CMultilayerPerceptron m_innerobj; -public: - //--- constructors, destructor - CMultilayerPerceptronShell(void); - CMultilayerPerceptronShell(CMultilayerPerceptron &obj); - ~CMultilayerPerceptronShell(void); - //--- method - CMultilayerPerceptron *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMultilayerPerceptronShell::CMultilayerPerceptronShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CMultilayerPerceptronShell::CMultilayerPerceptronShell(CMultilayerPerceptron &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMultilayerPerceptronShell::~CMultilayerPerceptronShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CMultilayerPerceptron *CMultilayerPerceptronShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Multilayer perceptron class | -//+------------------------------------------------------------------+ -class CMLPBase - { -private: - //--- private methods - static void AddInputLayer(const int ncount,int &lsizes[],int <ypes[],int &lconnfirst[],int &lconnlast[],int &lastproc); - static void AddBiasedSummatorLayer(const int ncount,int &lsizes[],int <ypes[],int &lconnfirst[],int &lconnlast[],int &lastproc); - static void AddActivationLayer(const int functype,int &lsizes[],int <ypes[],int &lconnfirst[],int &lconnlast[],int &lastproc); - static void AddZeroLayer(int &lsizes[],int <ypes[],int &lconnfirst[],int &lconnlast[],int &lastproc); - static void HLAddInputLayer(CMultilayerPerceptron &network,int &connidx,int &neuroidx,int &structinfoidx,int nin); - static void HLAddOutputLayer(CMultilayerPerceptron &network,int &connidx,int &neuroidx,int &structinfoidx,int &weightsidx,const int k,const int nprev,const int nout,const bool iscls,const bool islinearout); - static void HLAddHiddenLayer(CMultilayerPerceptron &network,int &connidx,int &neuroidx,int &structinfoidx,int &weightsidx,const int k,const int nprev,const int ncur); - static void FillHighLevelInformation(CMultilayerPerceptron &network,const int nin,const int nhid1,const int nhid2,const int nout,const bool iscls,const bool islinearout); - static void MLPCreate(const int nin,const int nout,int &lsizes[],int <ypes[],int &lconnfirst[],int &lconnlast[],const int layerscount,const bool isclsnet,CMultilayerPerceptron &network); - static void MLPHessianBatchInternal(CMultilayerPerceptron &network,CMatrixDouble &xy,const int ssize,const bool naturalerr,double &e,double &grad[],CMatrixDouble &h); - static void MLPInternalCalculateGradient(CMultilayerPerceptron &network,double &neurons[],double &weights[],double &derror[],double &grad[],const bool naturalerrorfunc); - static void MLPChunkedGradient(CMultilayerPerceptron &network,CMatrixDouble &xy,const int cstart,const int csize,double &e,double &grad[],const bool naturalerrorfunc); - static double SafeCrossEntropy(const double t,const double z); -public: - //--- variables - static const int m_mlpvnum; - static const int m_mlpfirstversion; - static const int m_nfieldwidth; - static const int m_hlconm_nfieldwidth; - static const int m_hlm_nfieldwidth; - static const int m_chunksize; - //--- constructor, destructor - CMLPBase(void); - ~CMLPBase(void); - //--- public methods - static void MLPCreate0(const int nin,const int nout,CMultilayerPerceptron &network); - static void MLPCreate1(const int nin,const int nhid,const int nout,CMultilayerPerceptron &network); - static void MLPCreate2(const int nin,const int nhid1,const int nhid2,const int nout,CMultilayerPerceptron &network); - static void MLPCreateB0(const int nin,const int nout,const double b,double d,CMultilayerPerceptron &network); - static void MLPCreateB1(const int nin,const int nhid,const int nout,const double b,double d,CMultilayerPerceptron &network); - static void MLPCreateB2(const int nin,const int nhid1,const int nhid2,const int nout,const double b,double d,CMultilayerPerceptron &network); - static void MLPCreateR0(const int nin,const int nout,const double a,const double b,CMultilayerPerceptron &network); - static void MLPCreateR1(const int nin,const int nhid,const int nout,const double a,const double b,CMultilayerPerceptron &network); - static void MLPCreateR2(const int nin,const int nhid1,const int nhid2,const int nout,const double a,const double b,CMultilayerPerceptron &network); - static void MLPCreateC0(const int nin,const int nout,CMultilayerPerceptron &network); - static void MLPCreateC1(const int nin,const int nhid,const int nout,CMultilayerPerceptron &network); - static void MLPCreateC2(const int nin,const int nhid1,const int nhid2,const int nout,CMultilayerPerceptron &network); - static void MLPCopy(CMultilayerPerceptron &network1,CMultilayerPerceptron &network2); - static void MLPSerializeOld(CMultilayerPerceptron &network,double &ra[],int &rlen); - static void MLPUnserializeOld(double &ra[],CMultilayerPerceptron &network); - static void MLPRandomize(CMultilayerPerceptron &network); - static void MLPRandomizeFull(CMultilayerPerceptron &network); - static void MLPInitPreprocessor(CMultilayerPerceptron &network,CMatrixDouble &xy,const int ssize); - static void MLPProperties(CMultilayerPerceptron &network,int &nin,int &nout,int &wcount); - static bool MLPIsSoftMax(CMultilayerPerceptron &network); - static int MLPGetLayersCount(CMultilayerPerceptron &network); - static int MLPGetLayerSize(CMultilayerPerceptron &network,const int k); - static void MLPGetInputScaling(CMultilayerPerceptron &network,const int i,double &mean,double &sigma); - static void MLPGetOutputScaling(CMultilayerPerceptron &network,const int i,double &mean,double &sigma); - static void MLPGetNeuronInfo(CMultilayerPerceptron &network,const int k,const int i,int &fkind,double &threshold); - static double MLPGetWeight(CMultilayerPerceptron &network,const int k0,const int i0,const int k1,const int i1); - static void MLPSetInputScaling(CMultilayerPerceptron &network,const int i,const double mean,double sigma); - static void MLPSetOutputScaling(CMultilayerPerceptron &network,const int i,const double mean,double sigma); - static void MLPSetNeuronInfo(CMultilayerPerceptron &network,const int k,const int i,const int fkind,const double threshold); - static void MLPSetWeight(CMultilayerPerceptron &network,const int k0,const int i0,const int k1,const int i1,const double w); - static void MLPActivationFunction(double net,const int k,double &f,double &df,double &d2f); - static void MLPProcess(CMultilayerPerceptron &network,double &x[],double &y[]); - static void MLPProcessI(CMultilayerPerceptron &network,double &x[],double &y[]); - static double MLPError(CMultilayerPerceptron &network,CMatrixDouble &xy,const int ssize); - static double MLPErrorN(CMultilayerPerceptron &network,CMatrixDouble &xy,const int ssize); - static int MLPClsError(CMultilayerPerceptron &network,CMatrixDouble &xy,const int ssize); - static double MLPRelClsError(CMultilayerPerceptron &network,CMatrixDouble &xy,const int npoints); - static double MLPAvgCE(CMultilayerPerceptron &network,CMatrixDouble &xy,const int npoints); - static double MLPRMSError(CMultilayerPerceptron &network,CMatrixDouble &xy,const int npoints); - static double MLPAvgError(CMultilayerPerceptron &network,CMatrixDouble &xy,const int npoints); - static double MLPAvgRelError(CMultilayerPerceptron &network,CMatrixDouble &xy,const int npoints); - static void MLPGrad(CMultilayerPerceptron &network,double &x[],double &desiredy[],double &e,double &grad[]); - static void MLPGradN(CMultilayerPerceptron &network,double &x[],double &desiredy[],double &e,double &grad[]); - static void MLPGradBatch(CMultilayerPerceptron &network,CMatrixDouble &xy,const int ssize,double &e,double &grad[]); - static void MLPGradNBatch(CMultilayerPerceptron &network,CMatrixDouble &xy,const int ssize,double &e,double &grad[]); - static void MLPHessianNBatch(CMultilayerPerceptron &network,CMatrixDouble &xy,const int ssize,double &e,double &grad[],CMatrixDouble &h); - static void MLPHessianBatch(CMultilayerPerceptron &network,CMatrixDouble &xy,const int ssize,double &e,double &grad[],CMatrixDouble &h); - static void MLPInternalProcessVector(int &structinfo[],double &weights[],double &columnmeans[],double &columnsigmas[],double &neurons[],double &dfdnet[],double &x[],double &y[]); - static void MLPAlloc(CSerializer &s,CMultilayerPerceptron &network); - static void MLPSerialize(CSerializer &s,CMultilayerPerceptron &network); - static void MLPUnserialize(CSerializer &s,CMultilayerPerceptron &network); - }; -//+------------------------------------------------------------------+ -//| Initialize constants | -//+------------------------------------------------------------------+ -const int CMLPBase::m_mlpvnum=7; -const int CMLPBase::m_mlpfirstversion=0; -const int CMLPBase::m_nfieldwidth=4; -const int CMLPBase::m_hlconm_nfieldwidth=5; -const int CMLPBase::m_hlm_nfieldwidth=4; -const int CMLPBase::m_chunksize=32; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMLPBase::CMLPBase(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMLPBase::~CMLPBase(void) - { - - } -//+------------------------------------------------------------------+ -//| Creates neural network with NIn inputs, NOut outputs, | -//| without hidden layers, with linear output layer. Network weights | -//| are filled with small random values. | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPCreate0(const int nin,const int nout, - CMultilayerPerceptron &network) - { -//--- create variables - int layerscount=0; - int lastproc=0; -//--- creating arrays - int lsizes[]; - int ltypes[]; - int lconnfirst[]; - int lconnlast[]; -//--- initialization - layerscount=4; -//--- Allocate arrays - ArrayResizeAL(lsizes,layerscount); - ArrayResizeAL(ltypes,layerscount); - ArrayResizeAL(lconnfirst,layerscount); - ArrayResizeAL(lconnlast,layerscount); -//--- Layers - AddInputLayer(nin,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nout,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddActivationLayer(-5,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- Create - MLPCreate(nin,nout,lsizes,ltypes,lconnfirst,lconnlast,layerscount,false,network); -//--- function call - FillHighLevelInformation(network,nin,0,0,nout,false,true); - } -//+------------------------------------------------------------------+ -//| Same as MLPCreate0, but with one hidden layer (NHid neurons) with| -//| non-linear activation function. Output layer is linear. | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPCreate1(const int nin,const int nhid,const int nout, - CMultilayerPerceptron &network) - { -//--- create variables - int layerscount=0; - int lastproc=0; -//--- creating arrays - int lsizes[]; - int ltypes[]; - int lconnfirst[]; - int lconnlast[]; -//--- create variables - layerscount=7; -//--- Allocate arrays - ArrayResizeAL(lsizes,layerscount); - ArrayResizeAL(ltypes,layerscount); - ArrayResizeAL(lconnfirst,layerscount); - ArrayResizeAL(lconnlast,layerscount); -//--- Layers - AddInputLayer(nin,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nhid,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddActivationLayer(1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nout,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddActivationLayer(-5,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- Create - MLPCreate(nin,nout,lsizes,ltypes,lconnfirst,lconnlast,layerscount,false,network); -//--- function call - FillHighLevelInformation(network,nin,nhid,0,nout,false,true); - } -//+------------------------------------------------------------------+ -//| Same as MLPCreate0,but with two hidden layers (NHid1 and NHid2 | -//| neurons) with non-linear activation function. Output layer is | -//| linear. | -//| $ALL | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPCreate2(const int nin,const int nhid1,const int nhid2, - const int nout,CMultilayerPerceptron &network) - { -//--- create variables - int layerscount=0; - int lastproc=0; -//--- creating arrays - int lsizes[]; - int ltypes[]; - int lconnfirst[]; - int lconnlast[]; -//--- initialization - layerscount=10; -//--- Allocate arrays - ArrayResizeAL(lsizes,layerscount); - ArrayResizeAL(ltypes,layerscount); - ArrayResizeAL(lconnfirst,layerscount); - ArrayResizeAL(lconnlast,layerscount); -//--- Layers - AddInputLayer(nin,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nhid1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddActivationLayer(1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nhid2,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddActivationLayer(1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nout,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddActivationLayer(-5,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- Create - MLPCreate(nin,nout,lsizes,ltypes,lconnfirst,lconnlast,layerscount,false,network); -//--- function call - FillHighLevelInformation(network,nin,nhid1,nhid2,nout,false,true); - } -//+------------------------------------------------------------------+ -//| Creates neural network with NIn inputs, NOut outputs, without | -//| hidden layers with non-linear output layer. Network weights are | -//| filled with small random values. | -//| Activation function of the output layer takes values: | -//| (B, +INF), if D>=0 | -//| or | -//| (-INF, B), if D<0. | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPCreateB0(const int nin,const int nout,const double b, - double d,CMultilayerPerceptron &network) - { -//--- create variables - int layerscount=0; - int lastproc=0; - int i=0; -//--- creating arrays - int lsizes[]; - int ltypes[]; - int lconnfirst[]; - int lconnlast[]; -//--- initialization - layerscount=4; -//--- check - if(d>=0.0) - d=1; - else - d=-1; -//--- Allocate arrays - ArrayResizeAL(lsizes,layerscount); - ArrayResizeAL(ltypes,layerscount); - ArrayResizeAL(lconnfirst,layerscount); - ArrayResizeAL(lconnlast,layerscount); -//--- Layers - AddInputLayer(nin,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nout,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddActivationLayer(3,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- Create - MLPCreate(nin,nout,lsizes,ltypes,lconnfirst,lconnlast,layerscount,false,network); -//--- function call - FillHighLevelInformation(network,nin,0,0,nout,false,false); -//--- Turn on ouputs shift/scaling. - for(i=nin;i<=nin+nout-1;i++) - { - network.m_columnmeans[i]=b; - network.m_columnsigmas[i]=d; - } - } -//+------------------------------------------------------------------+ -//| Same as MLPCreateB0 but with non-linear hidden layer. | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPCreateB1(const int nin,const int nhid,const int nout, - const double b,double d,CMultilayerPerceptron &network) - { -//--- create variables - int layerscount=0; - int lastproc=0; - int i=0; -//--- creating arrays - int lsizes[]; - int ltypes[]; - int lconnfirst[]; - int lconnlast[]; - layerscount=7; -//--- check - if(d>=0.0) - d=1; - else - d=-1; -//--- Allocate arrays - ArrayResizeAL(lsizes,layerscount); - ArrayResizeAL(ltypes,layerscount); - ArrayResizeAL(lconnfirst,layerscount); - ArrayResizeAL(lconnlast,layerscount); -//--- Layers - AddInputLayer(nin,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nhid,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddActivationLayer(1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nout,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddActivationLayer(3,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- Create - MLPCreate(nin,nout,lsizes,ltypes,lconnfirst,lconnlast,layerscount,false,network); -//--- function call - FillHighLevelInformation(network,nin,nhid,0,nout,false,false); -//--- Turn on ouputs shift/scaling. - for(i=nin;i<=nin+nout-1;i++) - { - network.m_columnmeans[i]=b; - network.m_columnsigmas[i]=d; - } - } -//+------------------------------------------------------------------+ -//| Same as MLPCreateB0 but with two non-linear hidden layers. | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPCreateB2(const int nin,const int nhid1,const int nhid2, - const int nout,const double b,double d, - CMultilayerPerceptron &network) - { -//--- create variables - int layerscount=0; - int lastproc=0; - int i=0; -//--- creating arrays - int lsizes[]; - int ltypes[]; - int lconnfirst[]; - int lconnlast[]; -//--- initialization - layerscount=10; -//--- check - if(d>=0.0) - d=1; - else - d=-1; -//--- Allocate arrays - ArrayResizeAL(lsizes,layerscount); - ArrayResizeAL(ltypes,layerscount); - ArrayResizeAL(lconnfirst,layerscount); - ArrayResizeAL(lconnlast,layerscount); -//--- Layers - AddInputLayer(nin,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nhid1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddActivationLayer(1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nhid2,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddActivationLayer(1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nout,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddActivationLayer(3,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- Create - MLPCreate(nin,nout,lsizes,ltypes,lconnfirst,lconnlast,layerscount,false,network); -//--- function call - FillHighLevelInformation(network,nin,nhid1,nhid2,nout,false,false); -//--- Turn on ouputs shift/scaling. - for(i=nin;i<=nin+nout-1;i++) - { - network.m_columnmeans[i]=b; - network.m_columnsigmas[i]=d; - } - } -//+------------------------------------------------------------------+ -//| Creates neural network with NIn inputs, NOut outputs, | -//| without hidden layers with non-linear output layer. Network | -//| weights are filled with small random values. Activation function | -//| of the output layer takes values [A,B]. | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPCreateR0(const int nin,const int nout,const double a, - const double b,CMultilayerPerceptron &network) - { -//--- create variables - int layerscount=0; - int lastproc=0; - int i=0; -//--- creating arrays - int lsizes[]; - int ltypes[]; - int lconnfirst[]; - int lconnlast[]; -//--- initialization - layerscount=1+3; -//--- Allocate arrays - ArrayResizeAL(lsizes,layerscount); - ArrayResizeAL(ltypes,layerscount); - ArrayResizeAL(lconnfirst,layerscount); - ArrayResizeAL(lconnlast,layerscount); -//--- Layers - AddInputLayer(nin,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nout,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddActivationLayer(1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- Create - MLPCreate(nin,nout,lsizes,ltypes,lconnfirst,lconnlast,layerscount,false,network); -//--- function call - FillHighLevelInformation(network,nin,0,0,nout,false,false); -//--- Turn on outputs shift/scaling. - for(i=nin;i<=nin+nout-1;i++) - { - network.m_columnmeans[i]=0.5*(a+b); - network.m_columnsigmas[i]=0.5*(a-b); - } - } -//+------------------------------------------------------------------+ -//| Same as MLPCreateR0,but with non-linear hidden layer. | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPCreateR1(const int nin,const int nhid,const int nout, - const double a,const double b, - CMultilayerPerceptron &network) - { -//--- create variables - int layerscount=0; - int lastproc=0; - int i=0; -//--- creating arrays - int lsizes[]; - int ltypes[]; - int lconnfirst[]; - int lconnlast[]; -//--- initialization - layerscount=7; -//--- Allocate arrays - ArrayResizeAL(lsizes,layerscount); - ArrayResizeAL(ltypes,layerscount); - ArrayResizeAL(lconnfirst,layerscount); - ArrayResizeAL(lconnlast,layerscount); -//--- Layers - AddInputLayer(nin,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nhid,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddActivationLayer(1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nout,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddActivationLayer(1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- Create - MLPCreate(nin,nout,lsizes,ltypes,lconnfirst,lconnlast,layerscount,false,network); -//--- function call - FillHighLevelInformation(network,nin,nhid,0,nout,false,false); -//--- Turn on outputs shift/scaling. - for(i=nin;i<=nin+nout-1;i++) - { - network.m_columnmeans[i]=0.5*(a+b); - network.m_columnsigmas[i]=0.5*(a-b); - } - } -//+------------------------------------------------------------------+ -//| Same as MLPCreateR0,but with two non-linear hidden layers. | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPCreateR2(const int nin,const int nhid1,const int nhid2, - const int nout,const double a,const double b, - CMultilayerPerceptron &network) - { -//--- create variables - int layerscount=0; - int lastproc=0; - int i=0; -//--- creating arrays - int lsizes[]; - int ltypes[]; - int lconnfirst[]; - int lconnlast[]; -//--- initialization - layerscount=10; -//--- Allocate arrays - ArrayResizeAL(lsizes,layerscount); - ArrayResizeAL(ltypes,layerscount); - ArrayResizeAL(lconnfirst,layerscount); - ArrayResizeAL(lconnlast,layerscount); -//--- Layers - AddInputLayer(nin,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nhid1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddActivationLayer(1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nhid2,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddActivationLayer(1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nout,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddActivationLayer(1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- Create - MLPCreate(nin,nout,lsizes,ltypes,lconnfirst,lconnlast,layerscount,false,network); -//--- function call - FillHighLevelInformation(network,nin,nhid1,nhid2,nout,false,false); -//--- Turn on outputs shift/scaling. - for(i=nin;i<=nin+nout-1;i++) - { - network.m_columnmeans[i]=0.5*(a+b); - network.m_columnsigmas[i]=0.5*(a-b); - } - } -//+------------------------------------------------------------------+ -//| Creates classifier network with NIn inputs and NOut possible | -//| classes. | -//| Network contains no hidden layers and linear output layer with | -//| SOFTMAX-normalization (so outputs sums up to 1.0 and converge to | -//| posterior probabilities). | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPCreateC0(const int nin,const int nout, - CMultilayerPerceptron &network) - { -//--- create variables - int layerscount=0; - int lastproc=0; -//--- creating arrays - int lsizes[]; - int ltypes[]; - int lconnfirst[]; - int lconnlast[]; -//--- check - if(!CAp::Assert(nout>=2,__FUNCTION__+": NOut<2!")) - return; -//--- initialization - layerscount=4; -//--- Allocate arrays - ArrayResizeAL(lsizes,layerscount); - ArrayResizeAL(ltypes,layerscount); - ArrayResizeAL(lconnfirst,layerscount); - ArrayResizeAL(lconnlast,layerscount); -//--- Layers - AddInputLayer(nin,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nout-1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddZeroLayer(lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- Create - MLPCreate(nin,nout,lsizes,ltypes,lconnfirst,lconnlast,layerscount,true,network); -//--- function call - FillHighLevelInformation(network,nin,0,0,nout,true,true); - } -//+------------------------------------------------------------------+ -//| Same as MLPCreateC0,but with one non-linear hidden layer. | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPCreateC1(const int nin,const int nhid,const int nout, - CMultilayerPerceptron &network) - { -//--- create variables - int layerscount=0; - int lastproc=0; -//--- creating arrays - int lsizes[]; - int ltypes[]; - int lconnfirst[]; - int lconnlast[]; -//--- check - if(!CAp::Assert(nout>=2,__FUNCTION__+": NOut<2!")) - return; -//--- initialization - layerscount=7; -//--- Allocate arrays - ArrayResizeAL(lsizes,layerscount); - ArrayResizeAL(ltypes,layerscount); - ArrayResizeAL(lconnfirst,layerscount); - ArrayResizeAL(lconnlast,layerscount); -//--- Layers - AddInputLayer(nin,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nhid,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddActivationLayer(1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nout-1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddZeroLayer(lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- Create - MLPCreate(nin,nout,lsizes,ltypes,lconnfirst,lconnlast,layerscount,true,network); -//--- function call - FillHighLevelInformation(network,nin,nhid,0,nout,true,true); - } -//+------------------------------------------------------------------+ -//| Same as MLPCreateC0, but with two non-linear hidden layers. | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPCreateC2(const int nin,const int nhid1,const int nhid2, - const int nout,CMultilayerPerceptron &network) - { -//--- create variables - int layerscount=0; - int lastproc=0; -//--- creating arrays - int lsizes[]; - int ltypes[]; - int lconnfirst[]; - int lconnlast[]; -//--- check - if(!CAp::Assert(nout>=2,__FUNCTION__+": NOut<2!")) - return; -//--- initialization - layerscount=10; -//--- Allocate arrays - ArrayResizeAL(lsizes,layerscount); - ArrayResizeAL(ltypes,layerscount); - ArrayResizeAL(lconnfirst,layerscount); - ArrayResizeAL(lconnlast,layerscount); -//--- Layers - AddInputLayer(nin,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nhid1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddActivationLayer(1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nhid2,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddActivationLayer(1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddBiasedSummatorLayer(nout-1,lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- function call - AddZeroLayer(lsizes,ltypes,lconnfirst,lconnlast,lastproc); -//--- Create - MLPCreate(nin,nout,lsizes,ltypes,lconnfirst,lconnlast,layerscount,true,network); -//--- function call - FillHighLevelInformation(network,nin,nhid1,nhid2,nout,true,true); - } -//+------------------------------------------------------------------+ -//| Copying of neural network | -//| INPUT PARAMETERS: | -//| Network1 - original | -//| OUTPUT PARAMETERS: | -//| Network2 - copy | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPCopy(CMultilayerPerceptron &network1, - CMultilayerPerceptron &network2) - { -//--- copy - network2.m_hlnetworktype=network1.m_hlnetworktype; - network2.m_hlnormtype=network1.m_hlnormtype; -//--- function calls - CApServ::CopyIntegerArray(network1.m_hllayersizes,network2.m_hllayersizes); - CApServ::CopyIntegerArray(network1.m_hlconnections,network2.m_hlconnections); - CApServ::CopyIntegerArray(network1.m_hlneurons,network2.m_hlneurons); - CApServ::CopyIntegerArray(network1.m_structinfo,network2.m_structinfo); - CApServ::CopyRealArray(network1.m_weights,network2.m_weights); - CApServ::CopyRealArray(network1.m_columnmeans,network2.m_columnmeans); - CApServ::CopyRealArray(network1.m_columnsigmas,network2.m_columnsigmas); - CApServ::CopyRealArray(network1.m_neurons,network2.m_neurons); - CApServ::CopyRealArray(network1.m_dfdnet,network2.m_dfdnet); - CApServ::CopyRealArray(network1.m_derror,network2.m_derror); - CApServ::CopyRealArray(network1.m_x,network2.m_x); - CApServ::CopyRealArray(network1.m_y,network2.m_y); - CApServ::CopyRealMatrix(network1.m_chunks,network2.m_chunks); - CApServ::CopyRealArray(network1.m_nwbuf,network2.m_nwbuf); - CApServ::CopyIntegerArray(network1.m_integerbuf,network2.m_integerbuf); - } -//+------------------------------------------------------------------+ -//| Serialization of MultiLayerPerceptron strucure | -//| INPUT PARAMETERS: | -//| Network - original | -//| OUTPUT PARAMETERS: | -//| RA - array of real numbers which stores network, | -//| array[0..RLen-1] | -//| RLen - RA lenght | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPSerializeOld(CMultilayerPerceptron &network, - double &ra[],int &rlen) - { -//--- create variables - int i=0; - int ssize=0; - int ntotal=0; - int nin=0; - int nout=0; - int wcount=0; - int sigmalen=0; - int offs=0; - int i_=0; - int i1_=0; -//--- initialization - rlen=0; -//--- Unload info - ssize=network.m_structinfo[0]; - nin=network.m_structinfo[1]; - nout=network.m_structinfo[2]; - ntotal=network.m_structinfo[3]; - wcount=network.m_structinfo[4]; -//--- check - if(MLPIsSoftMax(network)) - sigmalen=nin; - else - sigmalen=nin+nout; -//--- RA format: -//--- LEN DESRC. -//--- 1 RLen -//--- 1 version (MLPVNum) -//--- 1 StructInfo size -//--- SSize StructInfo -//--- WCount Weights -//--- SigmaLen ColumnMeans -//--- SigmaLen ColumnSigmas - rlen=3+ssize+wcount+2*sigmalen; -//--- allocation - ArrayResizeAL(ra,rlen); -//--- change values - ra[0]=rlen; - ra[1]=m_mlpvnum; - ra[2]=ssize; -//--- calculation - offs=3; - for(i=0;i<=ssize-1;i++) - ra[offs+i]=network.m_structinfo[i]; -//--- calculation - offs=offs+ssize; - i1_=-offs; - for(i_=offs;i_<=offs+wcount-1;i_++) - ra[i_]=network.m_weights[i_+i1_]; -//--- calculation - offs=offs+wcount; - i1_=-offs; - for(i_=offs;i_<=offs+sigmalen-1;i_++) - ra[i_]=network.m_columnmeans[i_+i1_]; -//--- calculation - offs=offs+sigmalen; - i1_=-offs; - for(i_=offs;i_<=offs+sigmalen-1;i_++) - ra[i_]=network.m_columnsigmas[i_+i1_]; - offs=offs+sigmalen; - } -//+------------------------------------------------------------------+ -//| Unserialization of MultiLayerPerceptron strucure | -//| INPUT PARAMETERS: | -//| RA - real array which stores network | -//| OUTPUT PARAMETERS: | -//| Network - restored network | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPUnserializeOld(double &ra[],CMultilayerPerceptron &network) - { -//--- create variables - int i=0; - int ssize=0; - int ntotal=0; - int nin=0; - int nout=0; - int wcount=0; - int sigmalen=0; - int offs=0; - int i_=0; - int i1_=0; -//--- check - if(!CAp::Assert((int)MathRound(ra[1])==m_mlpvnum,__FUNCTION__+": incorrect array!")) - return; -//--- Unload StructInfo from IA - offs=3; - ssize=(int)MathRound(ra[2]); -//--- allocation - ArrayResizeAL(network.m_structinfo,ssize); - for(i=0;i<=ssize-1;i++) - network.m_structinfo[i]=(int)MathRound(ra[offs+i]); - offs=offs+ssize; -//--- Unload info from StructInfo - ssize=network.m_structinfo[0]; - nin=network.m_structinfo[1]; - nout=network.m_structinfo[2]; - ntotal=network.m_structinfo[3]; - wcount=network.m_structinfo[4]; -//--- check - if(network.m_structinfo[6]==0) - sigmalen=nin+nout; - else - sigmalen=nin; -//--- Allocate space for other fields - ArrayResizeAL(network.m_weights,wcount); - ArrayResizeAL(network.m_columnmeans,sigmalen); - ArrayResizeAL(network.m_columnsigmas,sigmalen); - ArrayResizeAL(network.m_neurons,ntotal); - network.m_chunks.Resize(3*ntotal+1,m_chunksize); - ArrayResizeAL(network.m_nwbuf,MathMax(wcount,2*nout)); - ArrayResizeAL(network.m_dfdnet,ntotal); - ArrayResizeAL(network.m_x,nin); - ArrayResizeAL(network.m_y,nout); - ArrayResizeAL(network.m_derror,ntotal); -//--- Copy parameters from RA - i1_=offs; - for(i_=0;i_<=wcount-1;i_++) - network.m_weights[i_]=ra[i_+i1_]; -//--- calculation - offs=offs+wcount; - i1_=offs; - for(i_=0;i_<=sigmalen-1;i_++) - network.m_columnmeans[i_]=ra[i_+i1_]; -//--- calculation - offs=offs+sigmalen; - i1_=offs; - for(i_=0;i_<=sigmalen-1;i_++) - network.m_columnsigmas[i_]=ra[i_+i1_]; - offs=offs+sigmalen; - } -//+------------------------------------------------------------------+ -//| Randomization of neural network weights | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPRandomize(CMultilayerPerceptron &network) - { -//--- create variables - int i=0; - int nin=0; - int nout=0; - int wcount=0; -//--- function call - MLPProperties(network,nin,nout,wcount); -//--- change values - for(i=0;i<=wcount-1;i++) - network.m_weights[i]=CMath::RandomReal()-0.5; - } -//+------------------------------------------------------------------+ -//| Randomization of neural network weights and standartisator | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPRandomizeFull(CMultilayerPerceptron &network) - { -//--- create variables - int i=0; - int nin=0; - int nout=0; - int wcount=0; - int ntotal=0; - int istart=0; - int offs=0; - int ntype=0; -//--- function call - MLPProperties(network,nin,nout,wcount); -//--- initialization - ntotal=network.m_structinfo[3]; - istart=network.m_structinfo[5]; -//--- Process network - for(i=0;i<=wcount-1;i++) - network.m_weights[i]=CMath::RandomReal()-0.5; - for(i=0;i<=nin-1;i++) - { - network.m_columnmeans[i]=2*CMath::RandomReal()-1; - network.m_columnsigmas[i]=1.5*CMath::RandomReal()+0.5; - } -//--- check - if(!MLPIsSoftMax(network)) - { - for(i=0;i<=nout-1;i++) - { - offs=istart+(ntotal-nout+i)*m_nfieldwidth; - ntype=network.m_structinfo[offs+0]; - //--- check - if(ntype==0) - { - //--- Shifts are changed only for linear outputs neurons - network.m_columnmeans[nin+i]=2*CMath::RandomReal()-1; - } - //--- check - if(ntype==0 || ntype==3) - { - //--- Scales are changed only for linear or bounded outputs neurons. - //--- Note that scale randomization preserves sign. - network.m_columnsigmas[nin+i]=MathSign(network.m_columnsigmas[nin+i])*(1.5*CMath::RandomReal()+0.5); - } - } - } - } -//+------------------------------------------------------------------+ -//| Internal subroutine. | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPInitPreprocessor(CMultilayerPerceptron &network, - CMatrixDouble &xy,const int ssize) - { -//--- create variables - int i=0; - int j=0; - int jmax=0; - int nin=0; - int nout=0; - int wcount=0; - int ntotal=0; - int istart=0; - int offs=0; - int ntype=0; - double s=0; -//--- creating arrays - double means[]; - double sigmas[]; -//--- function call - MLPProperties(network,nin,nout,wcount); -//--- initialization - ntotal=network.m_structinfo[3]; - istart=network.m_structinfo[5]; -//--- Means/Sigmas - if(MLPIsSoftMax(network)) - jmax=nin-1; - else - jmax=nin+nout-1; -//--- allocation - ArrayResizeAL(means,jmax+1); - ArrayResizeAL(sigmas,jmax+1); -//--- calculation - for(j=0;j<=jmax;j++) - { - //--- means - means[j]=0; - for(i=0;i<=ssize-1;i++) - means[j]=means[j]+xy[i][j]; - means[j]=means[j]/ssize; - //--- sigmas - sigmas[j]=0; - for(i=0;i<=ssize-1;i++) - sigmas[j]=sigmas[j]+CMath::Sqr(xy[i][j]-means[j]); - sigmas[j]=MathSqrt(sigmas[j]/ssize); - } -//--- Inputs - for(i=0;i<=nin-1;i++) - { - network.m_columnmeans[i]=means[i]; - network.m_columnsigmas[i]=sigmas[i]; - //--- check - if(network.m_columnsigmas[i]==0.0) - network.m_columnsigmas[i]=1; - } -//--- Outputs - if(!MLPIsSoftMax(network)) - { - for(i=0;i<=nout-1;i++) - { - offs=istart+(ntotal-nout+i)*m_nfieldwidth; - ntype=network.m_structinfo[offs+0]; - //--- Linear outputs - if(ntype==0) - { - network.m_columnmeans[nin+i]=means[nin+i]; - network.m_columnsigmas[nin+i]=sigmas[nin+i]; - //--- check - if(network.m_columnsigmas[nin+i]==0.0) - network.m_columnsigmas[nin+i]=1; - } - //--- Bounded outputs (half-interval) - if(ntype==3) - { - s=means[nin+i]-network.m_columnmeans[nin+i]; - //--- check - if(s==0.0) - s=MathSign(network.m_columnsigmas[nin+i]); - //--- check - if(s==0.0) - s=1.0; - //--- change value - network.m_columnsigmas[nin+i]=MathSign(network.m_columnsigmas[nin+i])*MathAbs(s); - //--- check - if((double)(network.m_columnsigmas[nin+i])==0.0) - network.m_columnsigmas[nin+i]=1; - } - } - } - } -//+------------------------------------------------------------------+ -//| Returns information about initialized network: number of inputs, | -//| outputs, weights. | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPProperties(CMultilayerPerceptron &network,int &nin, - int &nout,int &wcount) - { -//--- change values - nin=network.m_structinfo[1]; - nout=network.m_structinfo[2]; - wcount=network.m_structinfo[4]; - } -//+------------------------------------------------------------------+ -//| Tells whether network is SOFTMAX-normalized (i.m_e. classifier) | -//| or not. | -//+------------------------------------------------------------------+ -static bool CMLPBase::MLPIsSoftMax(CMultilayerPerceptron &network) - { -//--- check - if(network.m_structinfo[6]==1) - return(true); -//--- return result - return(false); - } -//+------------------------------------------------------------------+ -//| This function returns total number of layers (including input, | -//| hidden and output layers). | -//+------------------------------------------------------------------+ -static int CMLPBase::MLPGetLayersCount(CMultilayerPerceptron &network) - { -//--- return result - return(CAp::Len(network.m_hllayersizes)); - } -//+------------------------------------------------------------------+ -//| This function returns size of K-th layer. | -//| K=0 corresponds to input layer, K=CNT-1 corresponds to output | -//| layer. | -//| Size of the output layer is always equal to the number of | -//| outputs, although when we have softmax-normalized network, last | -//| neuron doesn't have any connections - it is just zero. | -//+------------------------------------------------------------------+ -static int CMLPBase::MLPGetLayerSize(CMultilayerPerceptron &network, - const int k) - { -//--- check - if(!CAp::Assert(k>=0 && k=0 && i=0 && i=0,__FUNCTION__+": incorrect (nonexistent) layer or neuron index")) - return; -//--- 1. find offset of the activation function record in the - if(network.m_hlneurons[highlevelidx*m_hlm_nfieldwidth+2]>=0) - { - activationoffset=istart+network.m_hlneurons[highlevelidx*m_hlm_nfieldwidth+2]*m_nfieldwidth; - fkind=network.m_structinfo[activationoffset+0]; - } - else - fkind=0; -//--- check - if(network.m_hlneurons[highlevelidx*m_hlm_nfieldwidth+3]>=0) - threshold=network.m_weights[network.m_hlneurons[highlevelidx*m_hlm_nfieldwidth+3]]; - else - threshold=0; - } -//+------------------------------------------------------------------+ -//| This function returns information about connection from I0-th | -//| neuron of K0-th layer to I1-th neuron of K1-th layer. | -//| INPUT PARAMETERS: | -//| Network - network | -//| K0 - layer index | -//| I0 - neuron index (within layer) | -//| K1 - layer index | -//| I1 - neuron index (within layer) | -//| RESULT: | -//| connection weight (zero for non-existent connections) | -//| This function: | -//| 1. throws exception if layer or neuron with given index do not | -//| exists. | -//| 2. returns zero if neurons exist, but there is no connection | -//| between them | -//+------------------------------------------------------------------+ -static double CMLPBase::MLPGetWeight(CMultilayerPerceptron &network, - const int k0,const int i0, - const int k1,const int i1) - { -//--- create variables - double result=0; - int ccnt=0; - int highlevelidx=0; -//--- initialization - ccnt=CAp::Len(network.m_hlconnections)/m_hlconm_nfieldwidth; -//--- check params - if(!CAp::Assert(k0>=0 && k0=0 && i0=0 && k1=0 && i1=0) - result=network.m_weights[network.m_hlconnections[highlevelidx*m_hlconm_nfieldwidth+4]]; - else - result=0; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| This function sets offset/scaling coefficients for I-th input of | -//| the network. | -//| INPUT PARAMETERS: | -//| Network - network | -//| I - input index | -//| Mean - mean term | -//| Sigma - sigma term (if zero,will be replaced by 1.0) | -//| NTE: I-th input is passed through linear transformation | -//| IN[i]=(IN[i]-Mean)/Sigma | -//| before feeding to the network. This function sets Mean and Sigma.| -//+------------------------------------------------------------------+ -static void CMLPBase::MLPSetInputScaling(CMultilayerPerceptron &network, - const int i,const double mean, - double sigma) - { -//--- check - if(!CAp::Assert(i>=0 && i=0 && i=0,__FUNCTION__+": incorrect (nonexistent) layer or neuron index")) - return; -//--- activation function - if(network.m_hlneurons[highlevelidx*m_hlm_nfieldwidth+2]>=0) - { - activationoffset=istart+network.m_hlneurons[highlevelidx*m_hlm_nfieldwidth+2]*m_nfieldwidth; - network.m_structinfo[activationoffset+0]=fkind; - } - else - { - //--- check - if(!CAp::Assert(fkind==0,__FUNCTION__+": you try to set activation function for neuron which can not have one")) - return; - } -//--- Threshold - if(network.m_hlneurons[highlevelidx*m_hlm_nfieldwidth+3]>=0) - network.m_weights[network.m_hlneurons[highlevelidx*m_hlm_nfieldwidth+3]]=threshold; - else - { - //--- check - if(!CAp::Assert(threshold==0.0,__FUNCTION__+": you try to set non-zero threshold for neuron which can not have one")) - return; - } - } -//+------------------------------------------------------------------+ -//| This function modifies information about connection from I0-th | -//| neuron of K0-th layer to I1-th neuron of K1-th layer. | -//| INPUT PARAMETERS: | -//| Network - network | -//| K0 - layer index | -//| I0 - neuron index (within layer) | -//| K1 - layer index | -//| I1 - neuron index (within layer) | -//| W - connection weight (must be zero for | -//| non-existent connections) | -//| This function: | -//| 1. throws exception if layer or neuron with given index do not | -//| exists. | -//| 2. throws exception if you try to set non-zero weight for | -//| non-existent connection | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPSetWeight(CMultilayerPerceptron &network,const int k0, - const int i0,const int k1, - const int i1,const double w) - { -//--- create variables - int ccnt=0; - int highlevelidx=0; -//--- initialization - ccnt=CAp::Len(network.m_hlconnections)/m_hlconm_nfieldwidth; -//--- check params - if(!CAp::Assert(k0>=0 && k0=0 && i0=0 && k1=0 && i1=0) - network.m_weights[network.m_hlconnections[highlevelidx*m_hlconm_nfieldwidth+4]]=w; - else - { - //--- check - if(!CAp::Assert(w==0.0,__FUNCTION__+": you try to set non-zero weight for non-existent connection")) - return; - } - } -//+------------------------------------------------------------------+ -//| Neural network activation function | -//| INPUT PARAMETERS: | -//| NET - neuron input | -//| K - function index (zero for linear function) | -//| OUTPUT PARAMETERS: | -//| F - function | -//| DF - its derivative | -//| D2F - its second derivative | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPActivationFunction(double net,const int k,double &f, - double &df,double &d2f) - { -//--- create variables - double net2=0; - double arg=0; - double root=0; - double r=0; -//--- initialization - f=0; - df=0; - d2f=0; -//--- check - if(k==0 || k==-5) - { - f=net; - df=1; - d2f=0; - //--- exit the function - return; - } -//--- check - if(k==1) - { - //--- TanH activation function - if(MathAbs(net)<100.0) - f=MathTanh(net); - else - f=MathSign(net); - //--- change values - df=1-CMath::Sqr(f); - d2f=-(2*f*df); - //--- exit the function - return; - } -//--- check - if(k==3) - { - //--- EX activation function - if(net>=0.0) - { - //--- change values - net2=net*net; - arg=net2+1; - root=MathSqrt(arg); - f=net+root; - r=net/root; - df=1+r; - d2f=(root-net*r)/arg; - } - else - { - //--- change values - f=MathExp(net); - df=f; - d2f=f; - } - //--- exit the function - return; - } -//--- check - if(k==2) - { - //--- calculation - f=MathExp(-CMath::Sqr(net)); - df=-(2*net*f); - d2f=-(2*(f+df*net)); - //--- exit the function - return; - } -//--- change values - f=0; - df=0; - d2f=0; - } -//+------------------------------------------------------------------+ -//| Procesing | -//| INPUT PARAMETERS: | -//| Network - neural network | -//| X - input vector, array[0..NIn-1]. | -//| OUTPUT PARAMETERS: | -//| Y - result. Regression estimate when solving | -//| regression task, vector of posterior | -//| probabilities for classification task. | -//| See also MLPProcessI | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPProcess(CMultilayerPerceptron &network,double &x[], - double &y[]) - { -//--- check - if(CAp::Len(y)=0 && k=0 && kworky[nmax]) - nmax=j; - } - nn=nmax; - //--- Right answer - if(MLPIsSoftMax(network)) - ns=(int)MathRound(xy[i][nin]); - else - { - nmax=0; - for(j=0;j<=nout-1;j++) - { - //--- check - if(xy[i][nin+j]>xy[i][nin+nmax]) - nmax=j; - } - ns=nmax; - } - //--- compare - if(nn!=ns) - result=result+1; - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Relative classification error on the test set | -//| INPUT PARAMETERS: | -//| Network - network | -//| XY - test set | -//| NPoints - test set size | -//| RESULT: | -//| percent of incorrectly classified cases. Works both for | -//| classifier networks and general purpose networks used as | -//| classifiers. | -//+------------------------------------------------------------------+ -static double CMLPBase::MLPRelClsError(CMultilayerPerceptron &network, - CMatrixDouble &xy,const int npoints) - { -//--- return result - return((double)MLPClsError(network,xy,npoints)/(double)npoints); - } -//+------------------------------------------------------------------+ -//| Average cross-entropy (in bits per element) on the test set | -//| INPUT PARAMETERS: | -//| Network - neural network | -//| XY - test set | -//| NPoints - test set size | -//| RESULT: | -//| CrossEntropy/(NPoints*LN(2)). | -//| Zero if network solves regression task. | -//+------------------------------------------------------------------+ -static double CMLPBase::MLPAvgCE(CMultilayerPerceptron &network,CMatrixDouble &xy, - const int npoints) - { -//--- create variables - double result=0; - int nin=0; - int nout=0; - int wcount=0; -//--- check - if(MLPIsSoftMax(network)) - { - //--- function call - MLPProperties(network,nin,nout,wcount); - //--- get result - result=MLPErrorN(network,xy,npoints)/(npoints*MathLog(2)); - } - else - result=0; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| RMS error on the test set | -//| INPUT PARAMETERS: | -//| Network - neural network | -//| XY - test set | -//| NPoints - test set size | -//| RESULT: | -//| root mean square error. | -//| Its meaning for regression task is obvious. As for | -//| classification task,RMS error means error when estimating | -//| posterior probabilities. | -//+------------------------------------------------------------------+ -static double CMLPBase::MLPRMSError(CMultilayerPerceptron &network, - CMatrixDouble &xy,const int npoints) - { -//--- create variables - int nin=0; - int nout=0; - int wcount=0; -//--- function call - MLPProperties(network,nin,nout,wcount); -//--- return result - return(MathSqrt(2*MLPError(network,xy,npoints)/(npoints*nout))); - } -//+------------------------------------------------------------------+ -//| Average error on the test set | -//| INPUT PARAMETERS: | -//| Network - neural network | -//| XY - test set | -//| NPoints - test set size | -//| RESULT: | -//| Its meaning for regression task is obvious. As for | -//| classification task,it means average error when estimating | -//| posterior probabilities. | -//+------------------------------------------------------------------+ -static double CMLPBase::MLPAvgError(CMultilayerPerceptron &network, - CMatrixDouble &xy,const int npoints) - { -//--- create variables - double result=0; - int i=0; - int j=0; - int k=0; - int nin=0; - int nout=0; - int wcount=0; - int i_=0; -//--- function call - MLPProperties(network,nin,nout,wcount); -//--- calculation - for(i=0;i<=npoints-1;i++) - { - for(i_=0;i_<=nin-1;i_++) - network.m_x[i_]=xy[i][i_]; - //--- function call - MLPProcess(network,network.m_x,network.m_y); - //--- check - if(MLPIsSoftMax(network)) - { - //--- class labels - k=(int)MathRound(xy[i][nin]); - for(j=0;j<=nout-1;j++) - { - //--- check - if(j==k) - result=result+MathAbs(1-network.m_y[j]); - else - result=result+MathAbs(network.m_y[j]); - } - } - else - { - //--- real outputs - for(j=0;j<=nout-1;j++) - result=result+MathAbs(xy[i][nin+j]-network.m_y[j]); - } - } -//--- return result - return(result/(npoints*nout)); - } -//+------------------------------------------------------------------+ -//| Average relative error on the test set | -//| INPUT PARAMETERS: | -//| Network - neural network | -//| XY - test set | -//| NPoints - test set size | -//| RESULT: | -//| Its meaning for regression task is obvious. As for | -//| classification task, it means average relative error when | -//| estimating posterior probability of belonging to the correct | -//| class. | -//+------------------------------------------------------------------+ -static double CMLPBase::MLPAvgRelError(CMultilayerPerceptron &network, - CMatrixDouble &xy,const int npoints) - { -//--- create variables - double result=0; - int i=0; - int j=0; - int k=0; - int lk=0; - int nin=0; - int nout=0; - int wcount=0; - int i_=0; -//--- function call - MLPProperties(network,nin,nout,wcount); -//--- initialization - result=0; - k=0; -//--- calculation - for(i=0;i<=npoints-1;i++) - { - for(i_=0;i_<=nin-1;i_++) - network.m_x[i_]=xy[i][i_]; - //--- function call - MLPProcess(network,network.m_x,network.m_y); - //--- check - if(MLPIsSoftMax(network)) - { - //--- class labels - lk=(int)MathRound(xy[i][nin]); - for(j=0;j<=nout-1;j++) - { - //--- check - if(j==lk) - { - result=result+MathAbs(1-network.m_y[j]); - k=k+1; - } - } - } - else - { - //--- real outputs - for(j=0;j<=nout-1;j++) - { - //--- check - if(xy[i][nin+j]!=0.0) - { - result=result+MathAbs(xy[i][nin+j]-network.m_y[j])/MathAbs(xy[i][nin+j]); - k=k+1; - } - } - } - } -//--- check - if(k!=0) - result=result/k; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Gradient calculation | -//| INPUT PARAMETERS: | -//| Network - network initialized with one of the network | -//| creation funcs | -//| X - input vector, length of array must be at least | -//| NIn | -//| DesiredY- desired outputs, length of array must be at least| -//| NOut | -//| Grad - possibly preallocated array. If size of array is | -//| smaller than WCount, it will be reallocated. It | -//| is recommended to reuse previously allocated | -//| array to reduce allocation overhead. | -//| OUTPUT PARAMETERS: | -//| E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) | -//| Grad - gradient of E with respect to weights of network,| -//| array[WCount] | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPGrad(CMultilayerPerceptron &network,double &x[], - double &desiredy[],double &e,double &grad[]) - { -//--- create variables - int i=0; - int nout=0; - int ntotal=0; -//--- Alloc - if(CAp::Len(grad)0 || structinfo[offs+0]==-5) - { - //--- Activation function - MLPActivationFunction(neurons[structinfo[offs+2]],structinfo[offs+0],f,df,d2f); - //--- change values - neurons[i]=f; - dfdnet[i]=df; - continue; - } - //--- check - if(structinfo[offs+0]==0) - { - //--- Adaptive summator - n1=structinfo[offs+2]; - n2=n1+structinfo[offs+1]-1; - w1=structinfo[offs+3]; - w2=w1+structinfo[offs+1]-1; - i1_=(n1)-(w1); - net=0.0; - //--- calculation - for(i_=w1;i_<=w2;i_++) - net+=weights[i_]*neurons[i_+i1_]; - neurons[i]=net; - dfdnet[i]=1.0; - continue; - } - //--- check - if(structinfo[offs+0]<0) - { - perr=true; - //--- check - if(structinfo[offs+0]==-2) - { - //--- input neuron,left unchanged - perr=false; - } - //--- check - if(structinfo[offs+0]==-3) - { - //--- "-1" neuron - neurons[i]=-1; - perr=false; - } - //--- check - if(structinfo[offs+0]==-4) - { - //--- "0" neuron - neurons[i]=0; - perr=false; - } - //--- check - if(!CAp::Assert(!perr,__FUNCTION__+": internal error - unknown neuron type!")) - return; - continue; - } - } -//--- Extract result - i1_=ntotal-nout; - for(i_=0;i_<=nout-1;i_++) - y[i_]=neurons[i_+i1_]; -//--- Softmax post-processing or standardisation if needed - if(!CAp::Assert(structinfo[6]==0 || structinfo[6]==1,__FUNCTION__+": unknown normalization type!")) - return; -//--- check - if(structinfo[6]==1) - { - //--- Softmax - mx=y[0]; - for(i=1;i<=nout-1;i++) - mx=MathMax(mx,y[i]); - //--- calculation - net=0; - for(i=0;i<=nout-1;i++) - { - y[i]=MathExp(y[i]-mx); - net=net+y[i]; - } - for(i=0;i<=nout-1;i++) - y[i]=y[i]/net; - } - else - { - //--- Standardisation - for(i=0;i<=nout-1;i++) - y[i]=y[i]*columnsigmas[nin+i]+columnmeans[nin+i]; - } - } -//+------------------------------------------------------------------+ -//| Serializer: allocation | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPAlloc(CSerializer &s,CMultilayerPerceptron &network) - { -//--- create variables - int i=0; - int j=0; - int k=0; - int fkind=0; - double threshold=0; - double v0=0; - double v1=0; - int nin=0; - int nout=0; -//--- initialization - nin=network.m_hllayersizes[0]; - nout=network.m_hllayersizes[CAp::Len(network.m_hllayersizes)-1]; -//--- preparation to serialize - s.Alloc_Entry(); - s.Alloc_Entry(); - s.Alloc_Entry(); -//--- function call - CApServ::AllocIntegerArray(s,network.m_hllayersizes,-1); - for(i=1;i<=CAp::Len(network.m_hllayersizes)-1;i++) - { - for(j=0;j<=network.m_hllayersizes[i]-1;j++) - { - //--- function call - MLPGetNeuronInfo(network,i,j,fkind,threshold); - //--- preparation to serialize - s.Alloc_Entry(); - s.Alloc_Entry(); - for(k=0;k<=network.m_hllayersizes[i-1]-1;k++) - s.Alloc_Entry(); - } - } - for(j=0;j<=nin-1;j++) - { - //--- function call - MLPGetInputScaling(network,j,v0,v1); - //--- preparation to serialize - s.Alloc_Entry(); - s.Alloc_Entry(); - } - for(j=0;j<=nout-1;j++) - { - //--- function call - MLPGetOutputScaling(network,j,v0,v1); - //--- preparation to serialize - s.Alloc_Entry(); - s.Alloc_Entry(); - } - } -//+------------------------------------------------------------------+ -//| Serializer: serialization | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPSerialize(CSerializer &s,CMultilayerPerceptron &network) - { -//--- create variables - int i=0; - int j=0; - int k=0; - int fkind=0; - double threshold=0; - double v0=0; - double v1=0; - int nin=0; - int nout=0; -//--- change values - nin=network.m_hllayersizes[0]; - nout=network.m_hllayersizes[CAp::Len(network.m_hllayersizes)-1]; -//--- serializetion - s.Serialize_Int(CSCodes::GetMLPSerializationCode()); - s.Serialize_Int(m_mlpfirstversion); - s.Serialize_Bool(MLPIsSoftMax(network)); -//--- function call - CApServ::SerializeIntegerArray(s,network.m_hllayersizes,-1); - for(i=1;i<=CAp::Len(network.m_hllayersizes)-1;i++) - { - for(j=0;j<=network.m_hllayersizes[i]-1;j++) - { - //--- function call - MLPGetNeuronInfo(network,i,j,fkind,threshold); - //--- serializetion - s.Serialize_Int(fkind); - s.Serialize_Double(threshold); - for(k=0;k<=network.m_hllayersizes[i-1]-1;k++) - s.Serialize_Double(MLPGetWeight(network,i-1,k,i,j)); - } - } - for(j=0;j<=nin-1;j++) - { - //--- function call - MLPGetInputScaling(network,j,v0,v1); - //--- serializetion - s.Serialize_Double(v0); - s.Serialize_Double(v1); - } - for(j=0;j<=nout-1;j++) - { - //--- function call - MLPGetOutputScaling(network,j,v0,v1); - //--- serializetion - s.Serialize_Double(v0); - s.Serialize_Double(v1); - } - } -//+------------------------------------------------------------------+ -//| Serializer: unserialization | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPUnserialize(CSerializer &s,CMultilayerPerceptron &network) - { -//--- create variables - int i0=0; - int i1=0; - int i=0; - int j=0; - int k=0; - int fkind=0; - double threshold=0; - double v0=0; - double v1=0; - int nin=0; - int nout=0; - bool issoftmax; -//--- create array - int layersizes[]; -//--- check correctness of header - i0=s.Unserialize_Int(); -//--- check - if(!CAp::Assert(i0==CSCodes::GetMLPSerializationCode(),__FUNCTION__+": stream header corrupted")) - return; -//--- unserializetion - i1=s.Unserialize_Int(); -//--- check - if(!CAp::Assert(i1==m_mlpfirstversion,__FUNCTION__+": stream header corrupted")) - return; -//--- Create network - issoftmax=s.Unserialize_Bool(); -//--- function call - CApServ::UnserializeIntegerArray(s,layersizes); -//--- check - if(!CAp::Assert((CAp::Len(layersizes)==2 || CAp::Len(layersizes)==3) || CAp::Len(layersizes)==4,__FUNCTION__+": too many hidden layers!")) - return; -//--- change values - nin=layersizes[0]; - nout=layersizes[CAp::Len(layersizes)-1]; -//--- check - if(CAp::Len(layersizes)==2) - { - //--- check - if(issoftmax) - MLPCreateC0(layersizes[0],layersizes[1],network); - else - MLPCreate0(layersizes[0],layersizes[1],network); - } -//--- check - if(CAp::Len(layersizes)==3) - { - //--- check - if(issoftmax) - MLPCreateC1(layersizes[0],layersizes[1],layersizes[2],network); - else - MLPCreate1(layersizes[0],layersizes[1],layersizes[2],network); - } -//--- check - if(CAp::Len(layersizes)==4) - { - //--- check - if(issoftmax) - MLPCreateC2(layersizes[0],layersizes[1],layersizes[2],layersizes[3],network); - else - MLPCreate2(layersizes[0],layersizes[1],layersizes[2],layersizes[3],network); - } -//--- Load neurons and weights - for(i=1;i<=CAp::Len(layersizes)-1;i++) - { - for(j=0;j<=layersizes[i]-1;j++) - { - //--- unserializetion - fkind=s.Unserialize_Int(); - threshold=s.Unserialize_Double(); - //--- function call - MLPSetNeuronInfo(network,i,j,fkind,threshold); - //--- unserializetion - for(k=0;k<=layersizes[i-1]-1;k++) - { - v0=s.Unserialize_Double(); - //--- function call - MLPSetWeight(network,i-1,k,i,j,v0); - } - } - } - -// -//--- Load standartizator -// - for(j=0;j<=nin-1;j++) - { - //--- unserializetion - v0=s.Unserialize_Double(); - v1=s.Unserialize_Double(); - //--- function call - MLPSetInputScaling(network,j,v0,v1); - } - for(j=0;j<=nout-1;j++) - { - //--- unserializetion - v0=s.Unserialize_Double(); - v1=s.Unserialize_Double(); - //--- function call - MLPSetOutputScaling(network,j,v0,v1); - } - } -//+------------------------------------------------------------------+ -//| Internal subroutine: adding new input layer to network | -//+------------------------------------------------------------------+ -static void CMLPBase::AddInputLayer(const int ncount,int &lsizes[], - int <ypes[],int &lconnfirst[], - int &lconnlast[],int &lastproc) - { -//--- change values - lsizes[0]=ncount; - ltypes[0]=-2; - lconnfirst[0]=0; - lconnlast[0]=0; - lastproc=0; - } -//+------------------------------------------------------------------+ -//| Internal subroutine: adding new summator layer to network | -//+------------------------------------------------------------------+ -static void CMLPBase::AddBiasedSummatorLayer(const int ncount,int &lsizes[], - int <ypes[],int &lconnfirst[], - int &lconnlast[],int &lastproc) - { -//--- change values - lsizes[lastproc+1]=1; - ltypes[lastproc+1]=-3; - lconnfirst[lastproc+1]=0; - lconnlast[lastproc+1]=0; - lsizes[lastproc+2]=ncount; - ltypes[lastproc+2]=0; - lconnfirst[lastproc+2]=lastproc; - lconnlast[lastproc+2]=lastproc+1; - lastproc=lastproc+2; - } -//+------------------------------------------------------------------+ -//| Internal subroutine: adding new summator layer to network | -//+------------------------------------------------------------------+ -static void CMLPBase::AddActivationLayer(const int functype,int &lsizes[], - int <ypes[],int &lconnfirst[], - int &lconnlast[],int &lastproc) - { -//--- check - if(!CAp::Assert(functype>0 || functype==-5,__FUNCTION__+": incorrect function type")) - return; -//--- change values - lsizes[lastproc+1]=lsizes[lastproc]; - ltypes[lastproc+1]=functype; - lconnfirst[lastproc+1]=lastproc; - lconnlast[lastproc+1]=lastproc; - lastproc=lastproc+1; - } -//+------------------------------------------------------------------+ -//| Internal subroutine: adding new zero layer to network | -//+------------------------------------------------------------------+ -static void CMLPBase::AddZeroLayer(int &lsizes[],int <ypes[], - int &lconnfirst[],int &lconnlast[], - int &lastproc) - { -//--- change values - lsizes[lastproc+1]=1; - ltypes[lastproc+1]=-4; - lconnfirst[lastproc+1]=0; - lconnlast[lastproc+1]=0; - lastproc=lastproc+1; - } -//+------------------------------------------------------------------+ -//| This routine adds input layer to the high-level description of | -//| the network. | -//| It modifies Network.HLConnections and Network.HLNeurons and | -//| assumes that these arrays have enough place to store data. | -//| It accepts following parameters: | -//| Network - network | -//| ConnIdx - index of the first free entry in the | -//| HLConnections | -//| NeuroIdx - index of the first free entry in the | -//| HLNeurons | -//| StructInfoIdx- index of the first entry in the low level | -//| description of the current layer (in the | -//| StructInfo array) | -//| NIn - number of inputs | -//| It modified Network and indices. | -//+------------------------------------------------------------------+ -static void CMLPBase::HLAddInputLayer(CMultilayerPerceptron &network, - int &connidx,int &neuroidx, - int &structinfoidx,int nin) - { -//--- create variables - int i=0; - int offs=0; -//--- initialization - offs=m_hlm_nfieldwidth*neuroidx; -//--- change values - for(i=0;i<=nin-1;i++) - { - network.m_hlneurons[offs+0]=0; - network.m_hlneurons[offs+1]=i; - network.m_hlneurons[offs+2]=-1; - network.m_hlneurons[offs+3]=-1; - offs=offs+m_hlm_nfieldwidth; - } -//--- change values - neuroidx=neuroidx+nin; - structinfoidx=structinfoidx+nin; - } -//+------------------------------------------------------------------+ -//| This routine adds output layer to the high-level description of | -//| the network. | -//| It modifies Network.HLConnections and Network. HLNeurons and | -//| assumes that these arrays have enough place to store data. It | -//| accepts following parameters: | -//| Network - network | -//| ConnIdx - index of the first free entry in the | -//| HLConnections | -//| NeuroIdx - index of the first free entry in the | -//| HLNeurons | -//| StructInfoIdx- index of the first entry in the low level | -//| description of the current layer (in the | -//| StructInfo array) | -//| WeightsIdx - index of the first entry in the Weights | -//| array which corresponds to the current layer | -//| K - current layer index | -//| NPrev - number of neurons in the previous layer | -//| NOut - number of outputs | -//| IsCls - is it classifier network? | -//| IsLinear - is it network with linear output? | -//| It modified Network and ConnIdx/NeuroIdx/StructInfoIdx/WeightsIdx| -//+------------------------------------------------------------------+ -static void CMLPBase::HLAddOutputLayer(CMultilayerPerceptron &network, - int &connidx,int &neuroidx, - int &structinfoidx,int &weightsidx, - const int k,const int nprev, - const int nout,const bool iscls, - const bool islinearout) - { -//--- create variables - int i=0; - int j=0; - int neurooffs=0; - int connoffs=0; -//--- check - if(!CAp::Assert((iscls && islinearout) || !iscls,__FUNCTION__+": internal error")) - return; -//--- initialization - neurooffs=m_hlm_nfieldwidth*neuroidx; - connoffs=m_hlconm_nfieldwidth*connidx; -//--- check - if(!iscls) - { - //--- Regression network - for(i=0;i<=nout-1;i++) - { - //--- change values - network.m_hlneurons[neurooffs+0]=k; - network.m_hlneurons[neurooffs+1]=i; - network.m_hlneurons[neurooffs+2]=structinfoidx+1+nout+i; - network.m_hlneurons[neurooffs+3]=weightsidx+nprev+(nprev+1)*i; - neurooffs=neurooffs+m_hlm_nfieldwidth; - } - for(i=0;i<=nprev-1;i++) - { - for(j=0;j<=nout-1;j++) - { - //--- change values - network.m_hlconnections[connoffs+0]=k-1; - network.m_hlconnections[connoffs+1]=i; - network.m_hlconnections[connoffs+2]=k; - network.m_hlconnections[connoffs+3]=j; - network.m_hlconnections[connoffs+4]=weightsidx+i+j*(nprev+1); - connoffs=connoffs+m_hlconm_nfieldwidth; - } - } - //--- change values - connidx=connidx+nprev*nout; - neuroidx=neuroidx+nout; - structinfoidx=structinfoidx+2*nout+1; - weightsidx=weightsidx+nout*(nprev+1); - } - else - { - //--- Classification network - for(i=0;i<=nout-2;i++) - { - //--- change values - network.m_hlneurons[neurooffs+0]=k; - network.m_hlneurons[neurooffs+1]=i; - network.m_hlneurons[neurooffs+2]=-1; - network.m_hlneurons[neurooffs+3]=weightsidx+nprev+(nprev+1)*i; - neurooffs=neurooffs+m_hlm_nfieldwidth; - } - //--- change values - network.m_hlneurons[neurooffs+0]=k; - network.m_hlneurons[neurooffs+1]=i; - network.m_hlneurons[neurooffs+2]=-1; - network.m_hlneurons[neurooffs+3]=-1; - for(i=0;i<=nprev-1;i++) - { - for(j=0;j<=nout-2;j++) - { - //--- change values - network.m_hlconnections[connoffs+0]=k-1; - network.m_hlconnections[connoffs+1]=i; - network.m_hlconnections[connoffs+2]=k; - network.m_hlconnections[connoffs+3]=j; - network.m_hlconnections[connoffs+4]=weightsidx+i+j*(nprev+1); - connoffs=connoffs+m_hlconm_nfieldwidth; - } - } - //--- change values - connidx=connidx+nprev*(nout-1); - neuroidx=neuroidx+nout; - structinfoidx=structinfoidx+nout+2; - weightsidx=weightsidx+(nout-1)*(nprev+1); - } - } -//+------------------------------------------------------------------+ -//| This routine adds hidden layer to the high-level description of | -//| the network. | -//| It modifies Network.HLConnections and Network.HLNeurons and | -//| assumes that these arrays have enough place to store data. It | -//| accepts following parameters: | -//| Network - network | -//| ConnIdx - index of the first free entry in the | -//| HLConnections | -//| NeuroIdx - index of the first free entry in the | -//| HLNeurons | -//| StructInfoIdx- index of the first entry in the low level | -//| description of the current layer (in the | -//| StructInfo array) | -//| WeightsIdx - index of the first entry in the Weights | -//| array which corresponds to the current layer | -//| K - current layer index | -//| NPrev - number of neurons in the previous layer | -//| NCur - number of neurons in the current layer | -//| It modified Network and ConnIdx/NeuroIdx/StructInfoIdx/WeightsIdx| -//+------------------------------------------------------------------+ -static void CMLPBase::HLAddHiddenLayer(CMultilayerPerceptron &network, - int &connidx,int &neuroidx, - int &structinfoidx,int &weightsidx, - const int k,const int nprev, - const int ncur) - { -//--- create variables - int i=0; - int j=0; - int neurooffs=0; - int connoffs=0; -//--- change values - neurooffs=m_hlm_nfieldwidth*neuroidx; - connoffs=m_hlconm_nfieldwidth*connidx; - for(i=0;i<=ncur-1;i++) - { - //--- change values - network.m_hlneurons[neurooffs+0]=k; - network.m_hlneurons[neurooffs+1]=i; - network.m_hlneurons[neurooffs+2]=structinfoidx+1+ncur+i; - network.m_hlneurons[neurooffs+3]=weightsidx+nprev+(nprev+1)*i; - neurooffs=neurooffs+m_hlm_nfieldwidth; - } - for(i=0;i<=nprev-1;i++) - { - for(j=0;j<=ncur-1;j++) - { - //--- change values - network.m_hlconnections[connoffs+0]=k-1; - network.m_hlconnections[connoffs+1]=i; - network.m_hlconnections[connoffs+2]=k; - network.m_hlconnections[connoffs+3]=j; - network.m_hlconnections[connoffs+4]=weightsidx+i+j*(nprev+1); - connoffs=connoffs+m_hlconm_nfieldwidth; - } - } -//--- change values - connidx=connidx+nprev*ncur; - neuroidx=neuroidx+ncur; - structinfoidx=structinfoidx+2*ncur+1; - weightsidx=weightsidx+ncur*(nprev+1); - } -//+------------------------------------------------------------------+ -//| This function fills high level information about network created | -//| using internal MLPCreate() function. | -//| This function does NOT examine StructInfo for low level | -//| information, it just expects that network has following | -//| structure: | -//| input neuron \ | -//| ... | input layer | -//| input neuron / | -//| "-1" neuron \ | -//| biased summator | | -//| ... | | -//| biased summator | hidden layer(s), if there are | -//| activation function | exists any | -//| ... | | -//| activation function / | -//| "-1" neuron \ | -//| biased summator | output layer: | -//| ... | * we have NOut summators/activators| -//| biased summator | for regression networks | -//| activation function | * we have only NOut-1 summators and| -//| ... | no activators for classifiers | -//| activation function | * we have "0" neuron only when we | -//| "0" neuron / have classifier | -//+------------------------------------------------------------------+ -static void CMLPBase::FillHighLevelInformation(CMultilayerPerceptron &network, - const int nin,const int nhid1, - const int nhid2,const int nout, - const bool iscls,const bool islinearout) - { -//--- create variables - int idxweights=0; - int idxstruct=0; - int idxneuro=0; - int idxconn=0; -//--- check - if(!CAp::Assert((iscls && islinearout) || !iscls,__FUNCTION__+": internal error")) - return; -//--- Preparations common to all types of networks - idxweights=0; - idxneuro=0; - idxstruct=0; - idxconn=0; - network.m_hlnetworktype=0; -//--- network without hidden layers - if(nhid1==0) - { - //--- allocation - ArrayResizeAL(network.m_hllayersizes,2); - //--- change values - network.m_hllayersizes[0]=nin; - network.m_hllayersizes[1]=nout; - //--- check - if(!iscls) - { - //--- allocation - ArrayResizeAL(network.m_hlconnections,m_hlconm_nfieldwidth*nin*nout); - ArrayResizeAL(network.m_hlneurons,m_hlm_nfieldwidth*(nin+nout)); - network.m_hlnormtype=0; - } - else - { - //--- allocation - ArrayResizeAL(network.m_hlconnections,m_hlconm_nfieldwidth*nin*(nout-1)); - ArrayResizeAL(network.m_hlneurons,m_hlm_nfieldwidth*(nin+nout)); - network.m_hlnormtype=1; - } - //--- function call - HLAddInputLayer(network,idxconn,idxneuro,idxstruct,nin); - //--- function call - HLAddOutputLayer(network,idxconn,idxneuro,idxstruct,idxweights,1,nin,nout,iscls,islinearout); - //--- exit the function - return; - } -//--- network with one hidden layers - if(nhid2==0) - { - //--- allocation - ArrayResizeAL(network.m_hllayersizes,3); - //--- change values - network.m_hllayersizes[0]=nin; - network.m_hllayersizes[1]=nhid1; - network.m_hllayersizes[2]=nout; - //--- check - if(!iscls) - { - //--- allocation - ArrayResizeAL(network.m_hlconnections,m_hlconm_nfieldwidth*(nin*nhid1+nhid1*nout)); - ArrayResizeAL(network.m_hlneurons,m_hlm_nfieldwidth*(nin+nhid1+nout)); - network.m_hlnormtype=0; - } - else - { - //--- allocation - ArrayResizeAL(network.m_hlconnections,m_hlconm_nfieldwidth*(nin*nhid1+nhid1*(nout-1))); - ArrayResizeAL(network.m_hlneurons,m_hlm_nfieldwidth*(nin+nhid1+nout)); - network.m_hlnormtype=1; - } - //--- function call - HLAddInputLayer(network,idxconn,idxneuro,idxstruct,nin); - //--- function call - HLAddHiddenLayer(network,idxconn,idxneuro,idxstruct,idxweights,1,nin,nhid1); - //--- function call - HLAddOutputLayer(network,idxconn,idxneuro,idxstruct,idxweights,2,nhid1,nout,iscls,islinearout); - //--- exit the function - return; - } -//--- Two hidden layers - ArrayResizeAL(network.m_hllayersizes,4); -//--- change values - network.m_hllayersizes[0]=nin; - network.m_hllayersizes[1]=nhid1; - network.m_hllayersizes[2]=nhid2; - network.m_hllayersizes[3]=nout; -//--- check - if(!iscls) - { - //--- allocation - ArrayResizeAL(network.m_hlconnections,m_hlconm_nfieldwidth*(nin*nhid1+nhid1*nhid2+nhid2*nout)); - ArrayResizeAL(network.m_hlneurons,m_hlm_nfieldwidth*(nin+nhid1+nhid2+nout)); - network.m_hlnormtype=0; - } - else - { - //--- allocation - ArrayResizeAL(network.m_hlconnections,m_hlconm_nfieldwidth*(nin*nhid1+nhid1*nhid2+nhid2*(nout-1))); - ArrayResizeAL(network.m_hlneurons,m_hlm_nfieldwidth*(nin+nhid1+nhid2+nout)); - network.m_hlnormtype=1; - } -//--- function call - HLAddInputLayer(network,idxconn,idxneuro,idxstruct,nin); -//--- function call - HLAddHiddenLayer(network,idxconn,idxneuro,idxstruct,idxweights,1,nin,nhid1); -//--- function call - HLAddHiddenLayer(network,idxconn,idxneuro,idxstruct,idxweights,2,nhid1,nhid2); -//--- function call - HLAddOutputLayer(network,idxconn,idxneuro,idxstruct,idxweights,3,nhid2,nout,iscls,islinearout); - } -//+------------------------------------------------------------------+ -//| Internal subroutine. | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPCreate(const int nin,const int nout,int &lsizes[], - int <ypes[],int &lconnfirst[],int &lconnlast[], - const int layerscount,const bool isclsnet, - CMultilayerPerceptron &network) - { -//--- create variables - int i=0; - int j=0; - int ssize=0; - int ntotal=0; - int wcount=0; - int offs=0; - int nprocessed=0; - int wallocated=0; -//--- creating arrays - int localtemp[]; - int lnfirst[]; - int lnsyn[]; -//--- Check - if(!CAp::Assert(layerscount>0,__FUNCTION__+": wrong parameters!")) - return; -//--- check - if(!CAp::Assert(ltypes[0]==-2,__FUNCTION__+": wrong LTypes[0] (must be -2)!")) - return; - for(i=0;i<=layerscount-1;i++) - { - //--- check - if(!CAp::Assert(lsizes[i]>0,__FUNCTION__+": wrong LSizes!")) - return; - //--- check - if(!CAp::Assert(lconnfirst[i]>=0 &&(lconnfirst[i]=lconnfirst[i]&&(lconnlast[i]=0 || ltypes[i]==-5) - { - lnsyn[i]=0; - for(j=lconnfirst[i];j<=lconnlast[i];j++) - lnsyn[i]=lnsyn[i]+lsizes[j]; - } - else - { - //--- check - if((ltypes[i]==-2 || ltypes[i]==-3) || ltypes[i]==-4) - lnsyn[i]=0; - } - //--- check - if(!CAp::Assert(lnsyn[i]>=0,__FUNCTION__+": internal error #0!")) - return; - //--- Other info - lnfirst[i]=ntotal; - ntotal=ntotal+lsizes[i]; - //--- check - if(ltypes[i]==0) - wcount=wcount+lnsyn[i]*lsizes[i]; - } - ssize=7+ntotal*m_nfieldwidth; -//--- Allocate - ArrayResizeAL(network.m_structinfo,ssize); - ArrayResizeAL(network.m_weights,wcount); -//--- check - if(isclsnet) - { - //--- allocation - ArrayResizeAL(network.m_columnmeans,nin); - ArrayResizeAL(network.m_columnsigmas,nin); - } - else - { - //--- allocation - ArrayResizeAL(network.m_columnmeans,nin+nout); - ArrayResizeAL(network.m_columnsigmas,nin+nout); - } -//--- allocation - ArrayResizeAL(network.m_neurons,ntotal); - network.m_chunks.Resize(3*ntotal+1,m_chunksize); - ArrayResizeAL(network.m_nwbuf,MathMax(wcount,2*nout)); - ArrayResizeAL(network.m_integerbuf,4); - ArrayResizeAL(network.m_dfdnet,ntotal); - ArrayResizeAL(network.m_x,nin); - ArrayResizeAL(network.m_y,nout); - ArrayResizeAL(network.m_derror,ntotal); -//--- Fill structure: global info - network.m_structinfo[0]=ssize; - network.m_structinfo[1]=nin; - network.m_structinfo[2]=nout; - network.m_structinfo[3]=ntotal; - network.m_structinfo[4]=wcount; - network.m_structinfo[5]=7; -//--- check - if(isclsnet) - network.m_structinfo[6]=1; - else - network.m_structinfo[6]=0; -//--- Fill structure: neuron connections - nprocessed=0; - wallocated=0; -//--- calculation - for(i=0;i<=layerscount-1;i++) - { - for(j=0;j<=lsizes[i]-1;j++) - { - offs=network.m_structinfo[5]+nprocessed*m_nfieldwidth; - network.m_structinfo[offs+0]=ltypes[i]; - //--- check - if(ltypes[i]==0) - { - //--- Adaptive summator: - //--- * connections with weights to previous neurons - network.m_structinfo[offs+1]=lnsyn[i]; - network.m_structinfo[offs+2]=lnfirst[lconnfirst[i]]; - network.m_structinfo[offs+3]=wallocated; - wallocated=wallocated+lnsyn[i]; - nprocessed=nprocessed+1; - } - //--- check - if(ltypes[i]>0 || ltypes[i]==-5) - { - //--- Activation layer: - //--- * each neuron connected to one (only one) of previous neurons. - //--- * no weights - network.m_structinfo[offs+1]=1; - network.m_structinfo[offs+2]=lnfirst[lconnfirst[i]]+j; - network.m_structinfo[offs+3]=-1; - nprocessed=nprocessed+1; - } - //--- check - if((ltypes[i]==-2 || ltypes[i]==-3) || ltypes[i]==-4) - nprocessed=nprocessed+1; - } - } -//--- check - if(!CAp::Assert(wallocated==wcount,__FUNCTION__+": internal error #1!")) - return; -//--- check - if(!CAp::Assert(nprocessed==ntotal,__FUNCTION__+": internal error #2!")) - return; -//--- Fill weights by small random values -//--- Initialize means and sigmas - for(i=0;i<=wcount-1;i++) - network.m_weights[i]=CMath::RandomReal()-0.5; - for(i=0;i<=nin-1;i++) - { - network.m_columnmeans[i]=0; - network.m_columnsigmas[i]=1; - } -//--- check - if(!isclsnet) - { - for(i=0;i<=nout-1;i++) - { - network.m_columnmeans[nin+i]=0; - network.m_columnsigmas[nin+i]=1; - } - } - } -//+------------------------------------------------------------------+ -//| Internal subroutine for Hessian calculation. | -//| WARNING!!! Unspeakable math far beyong human capabilities :) | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPHessianBatchInternal(CMultilayerPerceptron &network, - CMatrixDouble &xy,const int ssize, - const bool naturalerr,double &e, - double &grad[],CMatrixDouble &h) - { -//--- create variables - int nin=0; - int nout=0; - int wcount=0; - int ntotal=0; - int istart=0; - int i=0; - int j=0; - int k=0; - int kl=0; - int offs=0; - int n1=0; - int n2=0; - int w1=0; - int w2=0; - double s=0; - double t=0; - double v=0; - double et=0; - bool bflag; - double f=0; - double df=0; - double d2f=0; - double deidyj=0; - double mx=0; - double q=0; - double z=0; - double s2=0; - double expi=0; - double expj=0; - int i_=0; - int i1_=0; -//--- creating arrays - double x[]; - double desiredy[]; - double gt[]; - double zeros[]; -//--- create matrix - CMatrixDouble rx; - CMatrixDouble ry; - CMatrixDouble rdx; - CMatrixDouble rdy; -//--- initialization - e=0; -//--- function call - MLPProperties(network,nin,nout,wcount); -//--- initialization - ntotal=network.m_structinfo[3]; - istart=network.m_structinfo[5]; -//--- Prepare - ArrayResizeAL(x,nin); - ArrayResizeAL(desiredy,nout); - ArrayResizeAL(zeros,wcount); - ArrayResizeAL(gt,wcount); - rx.Resize(ntotal+nout,wcount); - ry.Resize(ntotal+nout,wcount); - rdx.Resize(ntotal+nout,wcount); - rdy.Resize(ntotal+nout,wcount); -//--- initialization - e=0; - for(i=0;i<=wcount-1;i++) - zeros[i]=0; - for(i_=0;i_<=wcount-1;i_++) - grad[i_]=zeros[i_]; - for(i=0;i<=wcount-1;i++) - { - for(i_=0;i_<=wcount-1;i_++) - h[i].Set(i_,zeros[i_]); - } -//--- Process - for(k=0;k<=ssize-1;k++) - { - //--- Process vector with MLPGradN. - //--- Now Neurons,DFDNET and DError contains results of the last run. - for(i_=0;i_<=nin-1;i_++) - x[i_]=xy[k][i_]; - //--- check - if(MLPIsSoftMax(network)) - { - //--- class labels outputs - kl=(int)MathRound(xy[k][nin]); - for(i=0;i<=nout-1;i++) - { - //--- check - if(i==kl) - desiredy[i]=1; - else - desiredy[i]=0; - } - } - else - { - //--- real outputs - i1_=nin; - for(i_=0;i_<=nout-1;i_++) - desiredy[i_]=xy[k][i_+i1_]; - } - //--- check - if(naturalerr) - MLPGradN(network,x,desiredy,et,gt); - else - MLPGrad(network,x,desiredy,et,gt); - //--- grad,error - e=e+et; - for(i_=0;i_<=wcount-1;i_++) - grad[i_]=grad[i_]+gt[i_]; - //--- Hessian. - //--- Forward pass of the R-algorithm - for(i=0;i<=ntotal-1;i++) - { - offs=istart+i*m_nfieldwidth; - for(i_=0;i_<=wcount-1;i_++) - rx[i].Set(i_,zeros[i_]); - for(i_=0;i_<=wcount-1;i_++) - ry[i].Set(i_,zeros[i_]); - //--- check - if(network.m_structinfo[offs+0]>0 || network.m_structinfo[offs+0]==-5) - { - //--- Activation function - n1=network.m_structinfo[offs+2]; - for(i_=0;i_<=wcount-1;i_++) - rx[i].Set(i_,ry[n1][i_]); - //--- calculation - v=network.m_dfdnet[i]; - for(i_=0;i_<=wcount-1;i_++) - ry[i].Set(i_,v*rx[i][i_]); - continue; - } - //--- check - if(network.m_structinfo[offs+0]==0) - { - //--- Adaptive summator - n1=network.m_structinfo[offs+2]; - n2=n1+network.m_structinfo[offs+1]-1; - w1=network.m_structinfo[offs+3]; - w2=w1+network.m_structinfo[offs+1]-1; - //--- calculation - for(j=n1;j<=n2;j++) - { - v=network.m_weights[w1+j-n1]; - for(i_=0;i_<=wcount-1;i_++) - rx[i].Set(i_,rx[i][i_]+v*ry[j][i_]); - rx[i].Set(w1+j-n1,rx[i][w1+j-n1]+network.m_neurons[j]); - } - for(i_=0;i_<=wcount-1;i_++) - ry[i].Set(i_,rx[i][i_]); - continue; - } - //--- check - if(network.m_structinfo[offs+0]<0) - { - bflag=true; - //--- check - if(network.m_structinfo[offs+0]==-2) - { - //--- input neuron,left unchanged - bflag=false; - } - //--- check - if(network.m_structinfo[offs+0]==-3) - { - //--- "-1" neuron,left unchanged - bflag=false; - } - //--- check - if(network.m_structinfo[offs+0]==-4) - { - //--- "0" neuron,left unchanged - bflag=false; - } - //--- check - if(!CAp::Assert(!bflag,__FUNCTION__+": internal error - unknown neuron type!")) - return; - continue; - } - } - //--- Hessian. Backward pass of the R-algorithm. - //--- Stage 1. Initialize RDY - for(i=0;i<=ntotal+nout-1;i++) - { - for(i_=0;i_<=wcount-1;i_++) - rdy[i].Set(i_,zeros[i_]); - } - //--- check - if(network.m_structinfo[6]==0) - { - //--- Standardisation. - //--- In context of the Hessian calculation standardisation - //--- is considered as additional layer with weightless - //--- activation function: - //--- F(NET) :=Sigma*NET - //--- So we add one more layer to forward pass,and - //--- make forward/backward pass through this layer. - for(i=0;i<=nout-1;i++) - { - n1=ntotal-nout+i; - n2=ntotal+i; - //--- Forward pass from N1 to N2 - for(i_=0;i_<=wcount-1;i_++) - rx[n2].Set(i_,ry[n1][i_]); - v=network.m_columnsigmas[nin+i]; - for(i_=0;i_<=wcount-1;i_++) - ry[n2].Set(i_,v*rx[n2][i_]); - //--- Initialization of RDY - for(i_=0;i_<=wcount-1;i_++) - rdy[n2].Set(i_,ry[n2][i_]); - //--- Backward pass from N2 to N1: - //--- 1. Calculate R(dE/dX). - //--- 2. No R(dE/dWij) is needed since weight of activation neuron - //--- is fixed to 1. So we can update R(dE/dY) for - //--- the connected neuron (note that Vij=0,Wij=1) - df=network.m_columnsigmas[nin+i]; - for(i_=0;i_<=wcount-1;i_++) - rdx[n2].Set(i_,df*rdy[n2][i_]); - for(i_=0;i_<=wcount-1;i_++) - rdy[n1].Set(i_,rdy[n1][i_]+rdx[n2][i_]); - } - } - else - { - //--- Softmax. - //--- Initialize RDY using generalized expression for ei'(yi) - //--- (see expression (9) from p. 5 of "Fast Exact Multiplication by the Hessian"). - //--- When we are working with softmax network,generalized - //--- expression for ei'(yi) is used because softmax - //--- normalization leads to ei,which depends on all y's - if(naturalerr) - { - //--- softmax + cross-entropy. - //--- We have: - //--- S=sum(exp(yk)), - //--- ei=sum(trn)*exp(yi)/S-trn_i - //--- j=i: d(ei)/d(yj)=T*exp(yi)*(S-exp(yi))/S^2 - //--- j<>i: d(ei)/d(yj)=-T*exp(yi)*exp(yj)/S^2 - t=0; - for(i=0;i<=nout-1;i++) - t=t+desiredy[i]; - mx=network.m_neurons[ntotal-nout]; - //--- calculation - for(i=0;i<=nout-1;i++) - mx=MathMax(mx,network.m_neurons[ntotal-nout+i]); - s=0; - for(i=0;i<=nout-1;i++) - { - network.m_nwbuf[i]=MathExp(network.m_neurons[ntotal-nout+i]-mx); - s=s+network.m_nwbuf[i]; - } - //--- calculation - for(i=0;i<=nout-1;i++) - { - for(j=0;j<=nout-1;j++) - { - //--- check - if(j==i) - { - deidyj=t*network.m_nwbuf[i]*(s-network.m_nwbuf[i])/CMath::Sqr(s); - for(i_=0;i_<=wcount-1;i_++) - rdy[ntotal-nout+i].Set(i_,rdy[ntotal-nout+i][i_]+deidyj*ry[ntotal-nout+i][i_]); - } - else - { - deidyj=-(t*network.m_nwbuf[i]*network.m_nwbuf[j]/CMath::Sqr(s)); - for(i_=0;i_<=wcount-1;i_++) - rdy[ntotal-nout+i].Set(i_,rdy[ntotal-nout+i][i_]+deidyj*ry[ntotal-nout+j][i_]); - } - } - } - } - else - { - //--- For a softmax + squared error we have expression - //--- far beyond human imagination so we dont even try - //--- to comment on it. Just enjoy the code... - //--- P.S. That's why "natural error" is called "natural" - - //--- compact beatiful expressions,fast code.... - mx=network.m_neurons[ntotal-nout]; - for(i=0;i<=nout-1;i++) - mx=MathMax(mx,network.m_neurons[ntotal-nout+i]); - //--- calculation - s=0; - s2=0; - for(i=0;i<=nout-1;i++) - { - network.m_nwbuf[i]=MathExp(network.m_neurons[ntotal-nout+i]-mx); - s=s+network.m_nwbuf[i]; - s2=s2+CMath::Sqr(network.m_nwbuf[i]); - } - //--- calculation - q=0; - for(i=0;i<=nout-1;i++) - q=q+(network.m_y[i]-desiredy[i])*network.m_nwbuf[i]; - for(i=0;i<=nout-1;i++) - { - //--- change values - z=-q+(network.m_y[i]-desiredy[i])*s; - expi=network.m_nwbuf[i]; - for(j=0;j<=nout-1;j++) - { - expj=network.m_nwbuf[j]; - //--- check - if(j==i) - deidyj=expi/CMath::Sqr(s)*((z+expi)*(s-2*expi)/s+expi*s2/CMath::Sqr(s)); - else - deidyj=expi*expj/CMath::Sqr(s)*(s2/CMath::Sqr(s)-2*z/s-(expi+expj)/s+(network.m_y[i]-desiredy[i])-(network.m_y[j]-desiredy[j])); - for(i_=0;i_<=wcount-1;i_++) - rdy[ntotal-nout+i].Set(i_,rdy[ntotal-nout+i][i_]+deidyj*ry[ntotal-nout+j][i_]); - } - } - } - } - //--- Hessian. Backward pass of the R-algorithm - //--- Stage 2. Process. - for(i=ntotal-1;i>=0;i--) - { - //--- Possible variants: - //--- 1. Activation function - //--- 2. Adaptive summator - //--- 3. Special neuron - offs=istart+i*m_nfieldwidth; - //--- check - if(network.m_structinfo[offs+0]>0 || network.m_structinfo[offs+0]==-5) - { - n1=network.m_structinfo[offs+2]; - //--- First,calculate R(dE/dX). - MLPActivationFunction(network.m_neurons[n1],network.m_structinfo[offs+0],f,df,d2f); - v=d2f*network.m_derror[i]; - for(i_=0;i_<=wcount-1;i_++) - rdx[i].Set(i_,df*rdy[i][i_]); - for(i_=0;i_<=wcount-1;i_++) - rdx[i].Set(i_,rdx[i][i_]+v*rx[i][i_]); - //--- No R(dE/dWij) is needed since weight of activation neuron - //--- is fixed to 1. - //--- So we can update R(dE/dY) for the connected neuron. - //--- (note that Vij=0,Wij=1) - for(i_=0;i_<=wcount-1;i_++) - rdy[n1].Set(i_,rdy[n1][i_]+rdx[i][i_]); - continue; - } - //--- check - if(network.m_structinfo[offs+0]==0) - { - //--- Adaptive summator - n1=network.m_structinfo[offs+2]; - n2=n1+network.m_structinfo[offs+1]-1; - w1=network.m_structinfo[offs+3]; - w2=w1+network.m_structinfo[offs+1]-1; - //--- First,calculate R(dE/dX). - for(i_=0;i_<=wcount-1;i_++) - rdx[i].Set(i_,rdy[i][i_]); - //--- Then,calculate R(dE/dWij) - for(j=w1;j<=w2;j++) - { - v=network.m_neurons[n1+j-w1]; - for(i_=0;i_<=wcount-1;i_++) - h[j].Set(i_,h[j][i_]+v*rdx[i][i_]); - //--- calculation - v=network.m_derror[i]; - for(i_=0;i_<=wcount-1;i_++) - h[j].Set(i_,h[j][i_]+v*ry[n1+j-w1][i_]); - } - //--- And finally,update R(dE/dY) for connected neurons. - for(j=w1;j<=w2;j++) - { - v=network.m_weights[j]; - for(i_=0;i_<=wcount-1;i_++) - rdy[n1+j-w1].Set(i_,rdy[n1+j-w1][i_]+v*rdx[i][i_]); - rdy[n1+j-w1].Set(j,rdy[n1+j-w1][j]+network.m_derror[i]); - } - continue; - } - //--- check - if(network.m_structinfo[offs+0]<0) - { - bflag=false; - //--- check - if((network.m_structinfo[offs+0]==-2 || network.m_structinfo[offs+0]==-3) || network.m_structinfo[offs+0]==-4) - { - //--- Special neuron type,no back-propagation required - bflag=true; - } - //--- check - if(!CAp::Assert(bflag,__FUNCTION__+": unknown neuron type!")) - return; - continue; - } - } - } - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//| Network must be processed by MLPProcess on X | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPInternalCalculateGradient(CMultilayerPerceptron &network, - double &neurons[], - double &weights[], - double &derror[], - double &grad[], - const bool naturalerrorfunc) - { -//--- create variables - int i=0; - int n1=0; - int n2=0; - int w1=0; - int w2=0; - int ntotal=0; - int istart=0; - int nin=0; - int nout=0; - int offs=0; - double dedf=0; - double dfdnet=0; - double v=0; - double fown=0; - double deown=0; - double net=0; - double mx=0; - bool bflag; - int i_=0; - int i1_=0; -//--- Read network geometry - nin=network.m_structinfo[1]; - nout=network.m_structinfo[2]; - ntotal=network.m_structinfo[3]; - istart=network.m_structinfo[5]; -//--- Pre-processing of dError/dOut: -//--- from dError/dOut(normalized) to dError/dOut(non-normalized) - if(!CAp::Assert(network.m_structinfo[6]==0 || network.m_structinfo[6]==1,__FUNCTION__+": unknown normalization type!")) - return; -//--- check - if(network.m_structinfo[6]==1) - { - //--- Softmax - if(!naturalerrorfunc) - { - mx=network.m_neurons[ntotal-nout]; - for(i=0;i<=nout-1;i++) - mx=MathMax(mx,network.m_neurons[ntotal-nout+i]); - net=0; - for(i=0;i<=nout-1;i++) - { - network.m_nwbuf[i]=MathExp(network.m_neurons[ntotal-nout+i]-mx); - net=net+network.m_nwbuf[i]; - } - //--- calculation - i1_=-(ntotal-nout); - v=0.0; - for(i_=ntotal-nout;i_<=ntotal-1;i_++) - v+=network.m_derror[i_]*network.m_nwbuf[i_+i1_]; - for(i=0;i<=nout-1;i++) - { - fown=network.m_nwbuf[i]; - deown=network.m_derror[ntotal-nout+i]; - network.m_nwbuf[nout+i]=(-v+deown*fown+deown*(net-fown))*fown/CMath::Sqr(net); - } - for(i=0;i<=nout-1;i++) - network.m_derror[ntotal-nout+i]=network.m_nwbuf[nout+i]; - } - } - else - { - //--- Un-standardisation - for(i=0;i<=nout-1;i++) - network.m_derror[ntotal-nout+i]=network.m_derror[ntotal-nout+i]*network.m_columnsigmas[nin+i]; - } -//--- Backpropagation - for(i=ntotal-1;i>=0;i--) - { - //--- Extract info - offs=istart+i*m_nfieldwidth; - //--- check - if(network.m_structinfo[offs+0]>0 || network.m_structinfo[offs+0]==-5) - { - //--- Activation function - dedf=network.m_derror[i]; - dfdnet=network.m_dfdnet[i]; - derror[network.m_structinfo[offs+2]]=derror[network.m_structinfo[offs+2]]+dedf*dfdnet; - continue; - } - //--- check - if(network.m_structinfo[offs+0]==0) - { - //--- Adaptive summator - n1=network.m_structinfo[offs+2]; - n2=n1+network.m_structinfo[offs+1]-1; - w1=network.m_structinfo[offs+3]; - w2=w1+network.m_structinfo[offs+1]-1; - dedf=network.m_derror[i]; - dfdnet=1.0; - v=dedf*dfdnet; - i1_=n1-w1; - //--- calculation - for(i_=w1;i_<=w2;i_++) - grad[i_]=v*neurons[i_+i1_]; - i1_=w1-n1; - for(i_=n1;i_<=n2;i_++) - derror[i_]=derror[i_]+v*weights[i_+i1_]; - continue; - } - //--- check - if(network.m_structinfo[offs+0]<0) - { - bflag=false; - //--- check - if((network.m_structinfo[offs+0]==-2 || network.m_structinfo[offs+0]==-3) || network.m_structinfo[offs+0]==-4) - { - //--- Special neuron type,no back-propagation required - bflag=true; - } - //--- check - if(!CAp::Assert(bflag,__FUNCTION__+": unknown neuron type!")) - return; - continue; - } - } - } -//+------------------------------------------------------------------+ -//| Internal subroutine, chunked gradient | -//+------------------------------------------------------------------+ -static void CMLPBase::MLPChunkedGradient(CMultilayerPerceptron &network, - CMatrixDouble &xy,const int cstart, - const int csize,double &e, - double &grad[],const bool naturalerrorfunc) - { -//--- create variables - int i=0; - int j=0; - int k=0; - int kl=0; - int n1=0; - int n2=0; - int w1=0; - int w2=0; - int c1=0; - int c2=0; - int ntotal=0; - int nin=0; - int nout=0; - int offs=0; - double f=0; - double df=0; - double d2f=0; - double v=0; - double s=0; - double fown=0; - double deown=0; - double net=0; - double lnnet=0; - double mx=0; - bool bflag; - int istart=0; - int ineurons=0; - int idfdnet=0; - int iderror=0; - int izeros=0; - int i_=0; - int i1_=0; -//--- Read network geometry,prepare data - nin=network.m_structinfo[1]; - nout=network.m_structinfo[2]; - ntotal=network.m_structinfo[3]; - istart=network.m_structinfo[5]; - c1=cstart; - c2=cstart+csize-1; - ineurons=0; - idfdnet=ntotal; - iderror=2*ntotal; - izeros=3*ntotal; - for(j=0;j<=csize-1;j++) - network.m_chunks[izeros].Set(j,0); -//--- Forward pass: -//--- 1. Load inputs from XY to Chunks[0:NIn-1,0:CSize-1] -//--- 2. Forward pass - for(i=0;i<=nin-1;i++) - { - for(j=0;j<=csize-1;j++) - { - //--- check - if(network.m_columnsigmas[i]!=0.0) - network.m_chunks[i].Set(j,(xy[c1+j][i]-network.m_columnmeans[i])/network.m_columnsigmas[i]); - else - network.m_chunks[i].Set(j,xy[c1+j][i]-network.m_columnmeans[i]); - } - } - for(i=0;i<=ntotal-1;i++) - { - offs=istart+i*m_nfieldwidth; - //--- check - if(network.m_structinfo[offs+0]>0 || network.m_structinfo[offs+0]==-5) - { - //--- Activation function: - //--- * calculate F vector,F(i)=F(NET(i)) - n1=network.m_structinfo[offs+2]; - for(i_=0;i_<=csize-1;i_++) - network.m_chunks[i].Set(i_,network.m_chunks[n1][i_]); - for(j=0;j<=csize-1;j++) - { - //--- function call - MLPActivationFunction(network.m_chunks[i][j],network.m_structinfo[offs+0],f,df,d2f); - //--- change values - network.m_chunks[i].Set(j,f); - network.m_chunks[idfdnet+i].Set(j,df); - } - continue; - } - //--- check - if(network.m_structinfo[offs+0]==0) - { - //--- Adaptive summator: - //--- * calculate NET vector,NET(i)=SUM(W(j,i)*Neurons(j),j=N1..N2) - n1=network.m_structinfo[offs+2]; - n2=n1+network.m_structinfo[offs+1]-1; - w1=network.m_structinfo[offs+3]; - w2=w1+network.m_structinfo[offs+1]-1; - //--- calculation - for(i_=0;i_<=csize-1;i_++) - network.m_chunks[i].Set(i_,network.m_chunks[izeros][i_]); - for(j=n1;j<=n2;j++) - { - v=network.m_weights[w1+j-n1]; - for(i_=0;i_<=csize-1;i_++) - network.m_chunks[i].Set(i_,network.m_chunks[i][i_]+v*network.m_chunks[j][i_]); - } - continue; - } - //--- check - if(network.m_structinfo[offs+0]<0) - { - bflag=false; - //--- check - if(network.m_structinfo[offs+0]==-2) - { - //--- input neuron,left unchanged - bflag=true; - } - //--- check - if(network.m_structinfo[offs+0]==-3) - { - //--- "-1" neuron - for(k=0;k<=csize-1;k++) - network.m_chunks[i].Set(k,-1); - bflag=true; - } - //--- check - if(network.m_structinfo[offs+0]==-4) - { - //--- "0" neuron - for(k=0;k<=csize-1;k++) - network.m_chunks[i].Set(k,0); - bflag=true; - } - //--- check - if(!CAp::Assert(bflag,__FUNCTION__+": internal error - unknown neuron type!")) - return; - continue; - } - } -//--- Post-processing,error,dError/dOut - for(i=0;i<=ntotal-1;i++) - { - for(i_=0;i_<=csize-1;i_++) - network.m_chunks[iderror+i].Set(i_,network.m_chunks[izeros][i_]); - } -//--- check - if(!CAp::Assert(network.m_structinfo[6]==0 || network.m_structinfo[6]==1,__FUNCTION__+": unknown normalization type!")) - return; -//--- check - if(network.m_structinfo[6]==1) - { - //--- Softmax output,classification network. - //--- For each K=0..CSize-1 do: - //--- 1. place exp(outputs[k]) to NWBuf[0:NOut-1] - //--- 2. place sum(exp(..)) to NET - //--- 3. calculate dError/dOut and place it to the second block of Chunks - for(k=0;k<=csize-1;k++) - { - //--- Normalize - mx=network.m_chunks[ntotal-nout][k]; - for(i=1;i<=nout-1;i++) - mx=MathMax(mx,network.m_chunks[ntotal-nout+i][k]); - net=0; - for(i=0;i<=nout-1;i++) - { - network.m_nwbuf[i]=MathExp(network.m_chunks[ntotal-nout+i][k]-mx); - net=net+network.m_nwbuf[i]; - } - //--- Calculate error function and dError/dOut - if(naturalerrorfunc) - { - //--- Natural error func. - s=1; - lnnet=MathLog(net); - kl=(int)MathRound(xy[cstart+k][nin]); - //--- calculation - for(i=0;i<=nout-1;i++) - { - //--- check - if(i==kl) - v=1; - else - v=0; - network.m_chunks[iderror+ntotal-nout+i].Set(k,s*network.m_nwbuf[i]/net-v); - e=e+SafeCrossEntropy(v,network.m_nwbuf[i]/net); - } - } - else - { - //--- Least squares error func - //--- Error,dError/dOut(normalized) - kl=(int)MathRound(xy[cstart+k][nin]); - for(i=0;i<=nout-1;i++) - { - //--- check - if(i==kl) - v=network.m_nwbuf[i]/net-1; - else - v=network.m_nwbuf[i]/net; - network.m_nwbuf[nout+i]=v; - e=e+CMath::Sqr(v)/2; - } - //--- From dError/dOut(normalized) to dError/dOut(non-normalized) - i1_=-nout; - v=0.0; - for(i_=nout;i_<=2*nout-1;i_++) - v+=network.m_nwbuf[i_]*network.m_nwbuf[i_+i1_]; - //--- calculation - for(i=0;i<=nout-1;i++) - { - fown=network.m_nwbuf[i]; - deown=network.m_nwbuf[nout+i]; - network.m_chunks[iderror+ntotal-nout+i].Set(k,(-v+deown*fown+deown*(net-fown))*fown/CMath::Sqr(net)); - } - } - } - } - else - { - //--- Normal output,regression network - //--- For each K=0..CSize-1 do: - //--- 1. calculate dError/dOut and place it to the second block of Chunks - for(i=0;i<=nout-1;i++) - { - for(j=0;j<=csize-1;j++) - { - v=network.m_chunks[ntotal-nout+i][j]*network.m_columnsigmas[nin+i]+network.m_columnmeans[nin+i]-xy[cstart+j][nin+i]; - network.m_chunks[iderror+ntotal-nout+i].Set(j,v*network.m_columnsigmas[nin+i]); - e=e+CMath::Sqr(v)/2; - } - } - } -//--- Backpropagation - for(i=ntotal-1;i>=0;i--) - { - //--- Extract info - offs=istart+i*m_nfieldwidth; - //--- check - if(network.m_structinfo[offs+0]>0 || network.m_structinfo[offs+0]==-5) - { - //--- Activation function - n1=network.m_structinfo[offs+2]; - for(k=0;k<=csize-1;k++) - network.m_chunks[iderror+i].Set(k,network.m_chunks[iderror+i][k]*network.m_chunks[idfdnet+i][k]); - for(i_=0;i_<=csize-1;i_++) - network.m_chunks[iderror+n1].Set(i_,network.m_chunks[iderror+n1][i_]+network.m_chunks[iderror+i][i_]); - continue; - } - //--- check - if(network.m_structinfo[offs+0]==0) - { - //--- "Normal" activation function - n1=network.m_structinfo[offs+2]; - n2=n1+network.m_structinfo[offs+1]-1; - w1=network.m_structinfo[offs+3]; - w2=w1+network.m_structinfo[offs+1]-1; - //--- calculation - for(j=w1;j<=w2;j++) - { - v=0.0; - for(i_=0;i_<=csize-1;i_++) - v+=network.m_chunks[n1+j-w1][i_]*network.m_chunks[iderror+i][i_]; - grad[j]=grad[j]+v; - } - //--- calculation - for(j=n1;j<=n2;j++) - { - v=network.m_weights[w1+j-n1]; - for(i_=0;i_<=csize-1;i_++) - network.m_chunks[iderror+j].Set(i_,network.m_chunks[iderror+j][i_]+v*network.m_chunks[iderror+i][i_]); - } - continue; - } - //--- check - if(network.m_structinfo[offs+0]<0) - { - bflag=false; - //--- check - if((network.m_structinfo[offs+0]==-2 || network.m_structinfo[offs+0]==-3) || network.m_structinfo[offs+0]==-4) - { - //--- Special neuron type,no back-propagation required - bflag=true; - } - //--- check - if(!CAp::Assert(bflag,__FUNCTION__+": unknown neuron type!")) - return; - continue; - } - } - } -//+------------------------------------------------------------------+ -//| Returns T*Ln(T/Z), guarded against overflow/underflow. | -//| Internal subroutine. | -//+------------------------------------------------------------------+ -static double CMLPBase::SafeCrossEntropy(const double t,const double z) - { -//--- create variables - double result=0; - double r=0; -//--- check - if(t==0.0) - result=0; - else - { - //--- check - if(MathAbs(z)>1.0) - { - //--- Shouldn't be the case with softmax, - //--- but we just want to be sure. - if(t/z==0.0) - r=CMath::m_minrealnumber; - else - r=t/z; - } - else - { - //--- Normal case - if(z==0.0 || MathAbs(t)>=CMath::m_maxrealnumber*MathAbs(z)) - r=CMath::m_maxrealnumber; - else - r=t/z; - } - //--- get result - result=t*MathLog(r); - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Auxiliary class for CLogit | -//+------------------------------------------------------------------+ -class CLogitModel - { -public: - double m_w[]; - //--- constructor, destructor - CLogitModel(void); - ~CLogitModel(void); - //--- copy - void Copy(CLogitModel &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CLogitModel::CLogitModel(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CLogitModel::~CLogitModel(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CLogitModel::Copy(CLogitModel &obj) - { -//--- copy array - ArrayCopy(m_w,obj.m_w); - } -//+------------------------------------------------------------------+ -//| This class is a shell for class CLogitModel | -//+------------------------------------------------------------------+ -class CLogitModelShell - { -private: - CLogitModel m_innerobj; -public: - //--- constructors, destructor - CLogitModelShell(void); - CLogitModelShell(CLogitModel &obj); - ~CLogitModelShell(void); - //--- method - CLogitModel *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CLogitModelShell::CLogitModelShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CLogitModelShell::CLogitModelShell(CLogitModel &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CLogitModelShell::~CLogitModelShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CLogitModel *CLogitModelShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Auxiliary class for CLogit | -//+------------------------------------------------------------------+ -class CLogitMCState - { -public: - //--- variables - bool m_brackt; - bool m_stage1; - int m_infoc; - double m_dg; - double m_dgm; - double m_dginit; - double m_dgtest; - double m_dgx; - double m_dgxm; - double m_dgy; - double m_dgym; - double m_finit; - double m_ftest1; - double m_fm; - double m_fx; - double m_fxm; - double m_fy; - double m_fym; - double m_stx; - double m_sty; - double m_stmin; - double m_stmax; - double m_width; - double m_width1; - double m_xtrapf; - //--- constructor, destructor - CLogitMCState(void); - ~CLogitMCState(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CLogitMCState::CLogitMCState(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CLogitMCState::~CLogitMCState(void) - { - - } -//+------------------------------------------------------------------+ -//| MNLReport structure contains information about training process: | -//| * NGrad - number of gradient calculations | -//| * NHess - number of Hessian calculations | -//+------------------------------------------------------------------+ -class CMNLReport - { -public: - //--- variables - int m_ngrad; - int m_nhess; - //--- constructor, destructor - CMNLReport(void); - ~CMNLReport(void); - //--- copy - void Copy(CMNLReport &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMNLReport::CMNLReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMNLReport::~CMNLReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CMNLReport::Copy(CMNLReport &obj) - { -//--- copy variables - m_ngrad=obj.m_ngrad; - m_nhess=obj.m_nhess; - } -//+------------------------------------------------------------------+ -//| MNLReport structure contains information about training process: | -//| * NGrad - number of gradient calculations | -//| * NHess - number of Hessian calculations | -//+------------------------------------------------------------------+ -class CMNLReportShell - { -private: - CMNLReport m_innerobj; -public: - //--- constructors, destructor - CMNLReportShell(void); - CMNLReportShell(CMNLReport &obj); - ~CMNLReportShell(void); - //--- methods - int GetNGrad(void); - void SetNGrad(const int i); - int GetNHess(void); - void SetNHess(const int i); - CMNLReport *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMNLReportShell::CMNLReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CMNLReportShell::CMNLReportShell(CMNLReport &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMNLReportShell::~CMNLReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable ngrad | -//+------------------------------------------------------------------+ -int CMNLReportShell::GetNGrad(void) - { -//--- return result - return(m_innerobj.m_ngrad); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable ngrad | -//+------------------------------------------------------------------+ -void CMNLReportShell::SetNGrad(const int i) - { -//--- change value - m_innerobj.m_ngrad=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable nhess | -//+------------------------------------------------------------------+ -int CMNLReportShell::GetNHess(void) - { -//--- return result - return(m_innerobj.m_nhess); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable nhess | -//+------------------------------------------------------------------+ -void CMNLReportShell::SetNHess(const int i) - { -//--- change value - m_innerobj.m_nhess=i; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CMNLReport *CMNLReportShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Class logit model | -//+------------------------------------------------------------------+ -class CLogit - { -private: - //--- private methods - static void MNLIExp(double &w[],double &x[]); - static void MNLAllErrors(CLogitModel &lm,CMatrixDouble &xy,const int npoints,double &relcls,double &avgce,double &rms,double &avg,double &avgrel); - static void MNLMCSrch(const int n,double &x[],double &f,double &g[],double &s[],double &stp,int &info,int &nfev,double &wa[],CLogitMCState &state,int &stage); - static void MNLMCStep(double &stx,double &fx,double &dx,double &sty,double &fy,double &dy,double &stp,const double fp,const double dp,bool &brackt,const double stmin,const double stmax,int &info); -public: - //--- variables - static const double m_xtol; - static const double m_ftol; - static const double m_gtol; - static const int m_maxfev; - static const double m_stpmin; - static const double m_stpmax; - static const int m_logitvnum; - //--- constructor, destructor - CLogit(void); - ~CLogit(void); - //--- public methods - static void MNLTrainH(CMatrixDouble &xy,const int npoints,const int nvars,const int nclasses,int &info,CLogitModel &lm,CMNLReport &rep); - static void MNLProcess(CLogitModel &lm,double &x[],double &y[]); - static void MNLProcessI(CLogitModel &lm,double &x[],double &y[]); - static void MNLUnpack(CLogitModel &lm,CMatrixDouble &a,int &nvars,int &nclasses); - static void MNLPack(CMatrixDouble &a,const int nvars,const int nclasses,CLogitModel &lm); - static void MNLCopy(CLogitModel &lm1,CLogitModel &lm2); - static double MNLAvgCE(CLogitModel &lm,CMatrixDouble &xy,const int npoints); - static double MNLRelClsError(CLogitModel &lm,CMatrixDouble &xy,const int npoints); - static double MNLRMSError(CLogitModel &lm,CMatrixDouble &xy,const int npoints); - static double MNLAvgError(CLogitModel &lm,CMatrixDouble &xy,const int npoints); - static double MNLAvgRelError(CLogitModel &lm,CMatrixDouble &xy,const int ssize); - static int MNLClsError(CLogitModel &lm,CMatrixDouble &xy,const int npoints); - }; -//+------------------------------------------------------------------+ -//| Initialize constants | -//+------------------------------------------------------------------+ -const double CLogit::m_xtol=100*CMath::m_machineepsilon; -const double CLogit::m_ftol=0.0001; -const double CLogit::m_gtol=0.3; -const int CLogit::m_maxfev=20; -const double CLogit::m_stpmin=1.0E-2; -const double CLogit::m_stpmax=1.0E5; -const int CLogit::m_logitvnum=6; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CLogit::CLogit(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CLogit::~CLogit(void) - { - - } -//+------------------------------------------------------------------+ -//| This subroutine trains logit model. | -//| INPUT PARAMETERS: | -//| XY - training set, array[0..NPoints-1,0..NVars] | -//| First NVars columns store values of | -//| independent variables, next column stores | -//| number of class (from 0 to NClasses-1) which | -//| dataset element belongs to. Fractional values| -//| are rounded to nearest integer. | -//| NPoints - training set size, NPoints>=1 | -//| NVars - number of independent variables, NVars>=1 | -//| NClasses - number of classes, NClasses>=2 | -//| OUTPUT PARAMETERS: | -//| Info - return code: | -//| * -2, if there is a point with class number | -//| outside of [0..NClasses-1]. | -//| * -1, if incorrect parameters was passed | -//| (NPoints=nclasses) - { - info=-2; - return; - } - } -//--- change value - info=1; -//--- Initialize data - rep.m_ngrad=0; - rep.m_nhess=0; -//--- Allocate array - wdim=(nvars+1)*(nclasses-1); - offs=5; - expoffs=offs+wdim; - ssize=5+(nvars+1)*(nclasses-1)+nclasses; -//--- allocation - ArrayResizeAL(lm.m_w,ssize); -//--- change values - lm.m_w[0]=ssize; - lm.m_w[1]=m_logitvnum; - lm.m_w[2]=nvars; - lm.m_w[3]=nclasses; - lm.m_w[4]=offs; -//--- Degenerate case: all outputs are equal - allsame=true; - for(i=1;i<=npoints-1;i++) - { - //--- check - if((int)MathRound(xy[i][nvars])!=(int)MathRound(xy[i-1][nvars])) - allsame=false; - } -//--- check - if(allsame) - { - for(i=0;i<=(nvars+1)*(nclasses-1)-1;i++) - lm.m_w[offs+i]=0; - //--- change values - v=-(2*MathLog(CMath::m_minrealnumber)); - k=(int)MathRound(xy[0][nvars]); - //--- check - if(k==nclasses-1) - { - for(i=0;i<=nclasses-2;i++) - lm.m_w[offs+i*(nvars+1)+nvars]=-v; - } - else - { - for(i=0;i<=nclasses-2;i++) - { - //--- check - if(i==k) - lm.m_w[offs+i*(nvars+1)+nvars]=v; - else - lm.m_w[offs+i*(nvars+1)+nvars]=0; - } - } - //--- exit the function - return; - } -//--- General case. -//--- Prepare task and network. Allocate space. - CMLPBase::MLPCreateC0(nvars,nclasses,network); -//--- function call - CMLPBase::MLPInitPreprocessor(network,xy,npoints); -//--- function call - CMLPBase::MLPProperties(network,nin,nout,wcount); - for(i=0;i<=wcount-1;i++) - network.m_weights[i]=(2*CMath::RandomReal()-1)/nvars; -//--- allocation - ArrayResizeAL(g,wcount); - h.Resize(wcount,wcount); - ArrayResizeAL(wbase,wcount); - ArrayResizeAL(wdir,wcount); - ArrayResizeAL(work,wcount); -//--- First stage: optimize in gradient direction. - for(k=0;k<=wcount/3+10;k++) - { - //--- Calculate gradient in starting point - CMLPBase::MLPGradNBatch(network,xy,npoints,e,g); - v=0.0; - for(i_=0;i_<=wcount-1;i_++) - v+=network.m_weights[i_]*network.m_weights[i_]; - //--- change value - e=e+0.5*decay*v; - for(i_=0;i_<=wcount-1;i_++) - g[i_]=g[i_]+decay*network.m_weights[i_]; - rep.m_ngrad=rep.m_ngrad+1; - //--- Setup optimization scheme - for(i_=0;i_<=wcount-1;i_++) - wdir[i_]=-g[i_]; - v=0.0; - for(i_=0;i_<=wcount-1;i_++) - v+=wdir[i_]*wdir[i_]; - //--- change values - wstep=MathSqrt(v); - v=1/MathSqrt(v); - for(i_=0;i_<=wcount-1;i_++) - wdir[i_]=v*wdir[i_]; - mcstage=0; - //--- function call - MNLMCSrch(wcount,network.m_weights,e,g,wdir,wstep,mcinfo,mcnfev,work,mcstate,mcstage); - //--- cycle - while(mcstage!=0) - { - //--- function call - CMLPBase::MLPGradNBatch(network,xy,npoints,e,g); - v=0.0; - for(i_=0;i_<=wcount-1;i_++) - v+=network.m_weights[i_]*network.m_weights[i_]; - //--- change value - e=e+0.5*decay*v; - for(i_=0;i_<=wcount-1;i_++) - g[i_]=g[i_]+decay*network.m_weights[i_]; - rep.m_ngrad=rep.m_ngrad+1; - //--- function call - MNLMCSrch(wcount,network.m_weights,e,g,wdir,wstep,mcinfo,mcnfev,work,mcstate,mcstage); - } - } -//--- Second stage: use Hessian when we are close to the minimum - while(true) - { - //--- Calculate and update E/G/H - CMLPBase::MLPHessianNBatch(network,xy,npoints,e,g,h); - v=0.0; - for(i_=0;i_<=wcount-1;i_++) - v+=network.m_weights[i_]*network.m_weights[i_]; - //--- change value - e=e+0.5*decay*v; - for(i_=0;i_<=wcount-1;i_++) - g[i_]=g[i_]+decay*network.m_weights[i_]; - for(k=0;k<=wcount-1;k++) - h[k].Set(k,h[k][k]+decay); - rep.m_nhess=rep.m_nhess+1; - //--- Select step direction - //--- NOTE: it is important to use lower-triangle Cholesky - //--- factorization since it is much faster than higher-triangle version. - spd=CTrFac::SPDMatrixCholesky(h,wcount,false); - //--- function call - CDenseSolver::SPDMatrixCholeskySolve(h,wcount,false,g,solverinfo,solverrep,wdir); - spd=solverinfo>0; - //--- check - if(spd) - { - //--- H is positive definite. - //--- Step in Newton direction. - for(i_=0;i_<=wcount-1;i_++) - wdir[i_]=-1*wdir[i_]; - spd=true; - } - else - { - //--- H is indefinite. - //--- Step in gradient direction. - for(i_=0;i_<=wcount-1;i_++) - wdir[i_]=-g[i_]; - spd=false; - } - //--- Optimize in WDir direction - v=0.0; - for(i_=0;i_<=wcount-1;i_++) - v+=wdir[i_]*wdir[i_]; - //--- change values - wstep=MathSqrt(v); - v=1/MathSqrt(v); - for(i_=0;i_<=wcount-1;i_++) - wdir[i_]=v*wdir[i_]; - mcstage=0; - //--- function call - MNLMCSrch(wcount,network.m_weights,e,g,wdir,wstep,mcinfo,mcnfev,work,mcstate,mcstage); - //--- cycle - while(mcstage!=0) - { - //--- function call - CMLPBase::MLPGradNBatch(network,xy,npoints,e,g); - v=0.0; - for(i_=0;i_<=wcount-1;i_++) - v+=network.m_weights[i_]*network.m_weights[i_]; - //--- change value - e=e+0.5*decay*v; - for(i_=0;i_<=wcount-1;i_++) - g[i_]=g[i_]+decay*network.m_weights[i_]; - rep.m_ngrad=rep.m_ngrad+1; - //--- function call - MNLMCSrch(wcount,network.m_weights,e,g,wdir,wstep,mcinfo,mcnfev,work,mcstate,mcstage); - } - //--- check - if(spd && ((mcinfo==2 || mcinfo==4) || mcinfo==6)) - break; - } -//--- Convert from NN format to MNL format - i1_=-offs; - for(i_=offs;i_<=offs+wcount-1;i_++) - lm.m_w[i_]=network.m_weights[i_+i1_]; - for(k=0;k<=nvars-1;k++) - { - for(i=0;i<=nclasses-2;i++) - { - s=network.m_columnsigmas[k]; - //--- check - if(s==0.0) - s=1; - //--- change values - j=offs+(nvars+1)*i; - v=lm.m_w[j+k]; - lm.m_w[j+k]=v/s; - lm.m_w[j+nvars]=lm.m_w[j+nvars]+v*network.m_columnmeans[k]/s; - } - } -//--- calculation - for(k=0;k<=nclasses-2;k++) - lm.m_w[offs+(nvars+1)*k+nvars]=-lm.m_w[offs+(nvars+1)*k+nvars]; - } -//+------------------------------------------------------------------+ -//| Procesing | -//| INPUT PARAMETERS: | -//| LM - logit model, passed by non-constant reference | -//| (some fields of structure are used as temporaries| -//| when calculating model output). | -//| X - input vector, array[0..NVars-1]. | -//| Y - (possibly) preallocated buffer; if size of Y is | -//| less than NClasses, it will be reallocated.If it | -//| is large enough, it is NOT reallocated, so we | -//| can save some time on reallocation. | -//| OUTPUT PARAMETERS: | -//| Y - result, array[0..NClasses-1] | -//| Vector of posterior probabilities for | -//| classification task. | -//+------------------------------------------------------------------+ -static void CLogit::MNLProcess(CLogitModel &lm,double &x[],double &y[]) - { -//--- create variables - int nvars=0; - int nclasses=0; - int offs=0; - int i=0; - int i1=0; - double s=0; -//--- check - if(!CAp::Assert(lm.m_w[1]==m_logitvnum,__FUNCTION__+": unexpected model version")) - return; -//--- initialization - nvars=(int)MathRound(lm.m_w[2]); - nclasses=(int)MathRound(lm.m_w[3]); - offs=(int)MathRound(lm.m_w[4]); -//--- function call - MNLIExp(lm.m_w,x); - s=0; -//--- calculation - i1=offs+(nvars+1)*(nclasses-1); - for(i=i1;i<=i1+nclasses-1;i++) - s=s+lm.m_w[i]; -//--- check - if(CAp::Len(y)=0 &&(int)MathRound(xy[i][nvars])0.0) - result=result-MathLog(worky[(int)MathRound(xy[i][nvars])]); - else - result=result-MathLog(CMath::m_minrealnumber); - } -//--- return result - return(result/(npoints*MathLog(2))); - } -//+------------------------------------------------------------------+ -//| Relative classification error on the test set | -//| INPUT PARAMETERS: | -//| LM - logit model | -//| XY - test set | -//| NPoints - test set size | -//| RESULT: | -//| percent of incorrectly classified cases. | -//+------------------------------------------------------------------+ -static double CLogit::MNLRelClsError(CLogitModel &lm,CMatrixDouble &xy, - const int npoints) - { -//--- return result - return((double)MNLClsError(lm,xy,npoints)/(double)npoints); - } -//+------------------------------------------------------------------+ -//| RMS error on the test set | -//| INPUT PARAMETERS: | -//| LM - logit model | -//| XY - test set | -//| NPoints - test set size | -//| RESULT: | -//| root mean square error (error when estimating posterior | -//| probabilities). | -//+------------------------------------------------------------------+ -static double CLogit::MNLRMSError(CLogitModel &lm,CMatrixDouble &xy, - const int npoints) - { -//--- create variables - double relcls=0; - double avgce=0; - double rms=0; - double avg=0; - double avgrel=0; -//--- check - if(!CAp::Assert((int)MathRound(lm.m_w[1])==m_logitvnum,__FUNCTION__+": Incorrect MNL version!")) - return(EMPTY_VALUE); -//--- function call - MNLAllErrors(lm,xy,npoints,relcls,avgce,rms,avg,avgrel); -//--- return result - return(rms); - } -//+------------------------------------------------------------------+ -//| Average error on the test set | -//| INPUT PARAMETERS: | -//| LM - logit model | -//| XY - test set | -//| NPoints - test set size | -//| RESULT: | -//| average error (error when estimating posterior | -//| probabilities). | -//+------------------------------------------------------------------+ -static double CLogit::MNLAvgError(CLogitModel &lm,CMatrixDouble &xy, - const int npoints) - { -//--- create variables - double relcls=0; - double avgce=0; - double rms=0; - double avg=0; - double avgrel=0; -//--- check - if(!CAp::Assert((int)MathRound(lm.m_w[1])==m_logitvnum,__FUNCTION__+": Incorrect MNL version!")) - return(EMPTY_VALUE); -//--- function call - MNLAllErrors(lm,xy,npoints,relcls,avgce,rms,avg,avgrel); -//--- return result - return(avg); - } -//+------------------------------------------------------------------+ -//| Average relative error on the test set | -//| INPUT PARAMETERS: | -//| LM - logit model | -//| XY - test set | -//| NPoints - test set size | -//| RESULT: | -//| average relative error (error when estimating posterior | -//| probabilities). | -//+------------------------------------------------------------------+ -static double CLogit::MNLAvgRelError(CLogitModel &lm,CMatrixDouble &xy, - const int ssize) - { -//--- create variables - double relcls=0; - double avgce=0; - double rms=0; - double avg=0; - double avgrel=0; -//--- check - if(!CAp::Assert((int)MathRound(lm.m_w[1])==m_logitvnum,__FUNCTION__+": Incorrect MNL version!")) - return(EMPTY_VALUE); -//--- function call - MNLAllErrors(lm,xy,ssize,relcls,avgce,rms,avg,avgrel); -//--- return result - return(avgrel); - } -//+------------------------------------------------------------------+ -//| Classification error on test set = MNLRelClsError*NPoints | -//+------------------------------------------------------------------+ -static int CLogit::MNLClsError(CLogitModel &lm,CMatrixDouble &xy,const int npoints) - { -//--- create variables - int result=0; - int nvars=0; - int nclasses=0; - int i=0; - int j=0; - int nmax=0; - int i_=0; -//--- creating arrays - double workx[]; - double worky[]; -//--- check - if(!CAp::Assert(lm.m_w[1]==m_logitvnum,__FUNCTION__+": unexpected model version")) - return(-1); -//--- initialization - nvars=(int)MathRound(lm.m_w[2]); - nclasses=(int)MathRound(lm.m_w[3]); -//--- allocation - ArrayResizeAL(workx,nvars); - ArrayResizeAL(worky,nclasses); -//--- calculation - for(i=0;i<=npoints-1;i++) - { - //--- Process - for(i_=0;i_<=nvars-1;i_++) - workx[i_]=xy[i][i_]; - //--- function call - MNLProcess(lm,workx,worky); - //--- Logit version of the answer - nmax=0; - for(j=0;j<=nclasses-1;j++) - { - //--- check - if(worky[j]>worky[nmax]) - nmax=j; - } - //--- compare - if(nmax!=(int)MathRound(xy[i][nvars])) - result=result+1; - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Internal subroutine. Places exponents of the anti-overflow | -//| shifted internal linear outputs into the service part of the W | -//| array. | -//+------------------------------------------------------------------+ -static void CLogit::MNLIExp(double &w[],double &x[]) - { -//--- create variables - int nvars=0; - int nclasses=0; - int offs=0; - int i=0; - int i1=0; - double v=0; - double mx=0; - int i_=0; - int i1_=0; -//--- check - if(!CAp::Assert(w[1]==m_logitvnum,__FUNCTION__+": unexpected model version")) - return; -//--- initialization - nvars=(int)MathRound(w[2]); - nclasses=(int)MathRound(w[3]); - offs=(int)MathRound(w[4]); -//--- calculation - i1=offs+(nvars+1)*(nclasses-1); - for(i=0;i<=nclasses-2;i++) - { - //--- change values - i1_=-(offs+i*(nvars+1)); - v=0.0; - for(i_=offs+i*(nvars+1);i_<=offs+i*(nvars+1)+nvars-1;i_++) - v+=w[i_]*x[i_+i1_]; - w[i1+i]=v+w[offs+i*(nvars+1)+nvars]; - } -//--- change values - w[i1+nclasses-1]=0; - mx=0; -//--- calculation - for(i=i1;i<=i1+nclasses-1;i++) - mx=MathMax(mx,w[i]); - for(i=i1;i<=i1+nclasses-1;i++) - w[i]=MathExp(w[i]-mx); - } -//+------------------------------------------------------------------+ -//| Calculation of all types of errors | -//+------------------------------------------------------------------+ -static void CLogit::MNLAllErrors(CLogitModel &lm,CMatrixDouble &xy, - const int npoints,double &relcls, - double &avgce,double &rms,double &avg, - double &avgrel) - { -//--- create variables - int nvars=0; - int nclasses=0; - int i=0; - int i_=0; -//--- creating arrays - double buf[]; - double workx[]; - double y[]; - double dy[]; -//--- initialization - relcls=0; - avgce=0; - rms=0; - avg=0; - avgrel=0; -//--- check - if(!CAp::Assert((int)MathRound(lm.m_w[1])==m_logitvnum,__FUNCTION__+": Incorrect MNL version!")) - return; -//--- initialization - nvars=(int)MathRound(lm.m_w[2]); - nclasses=(int)MathRound(lm.m_w[3]); -//--- allocation - ArrayResizeAL(workx,nvars); - ArrayResizeAL(y,nclasses); - ArrayResizeAL(dy,1); -//--- function call - CBdSS::DSErrAllocate(nclasses,buf); - for(i=0;i<=npoints-1;i++) - { - for(i_=0;i_<=nvars-1;i_++) - workx[i_]=xy[i][i_]; - //--- function call - MNLProcess(lm,workx,y); - //--- change value - dy[0]=xy[i][nvars]; - //--- function call - CBdSS::DSErrAccumulate(buf,y,dy); - } -//--- function call - CBdSS::DSErrFinish(buf); -//--- change values - relcls=buf[0]; - avgce=buf[1]; - rms=buf[2]; - avg=buf[3]; - avgrel=buf[4]; - } -//+------------------------------------------------------------------+ -//| The purpose of mcsrch is to find a step which satisfies a | -//| sufficient decrease condition and a curvature condition. | -//| At each stage the subroutine updates an interval of uncertainty | -//| with endpoints stx and sty. The interval of uncertainty is | -//| initially chosen so that it contains a minimizer of the modified | -//| function | -//| f(x+stp*s) - f(x) - ftol*stp*(gradf(x)'s). | -//| If a step is obtained for which the modified function has a | -//| nonpositive function value and nonnegative derivative, then the | -//| interval of uncertainty is chosen so that it contains a minimizer| -//| of f(x+stp*s). | -//| The algorithm is designed to find a step which satisfies the | -//| sufficient decrease condition | -//| f(x+stp*s) .le. f(x) + ftol*stp*(gradf(x)'s), | -//| and the curvature condition | -//| abs(gradf(x+stp*s)'s)) .le. gtol*abs(gradf(x)'s). | -//| If ftol is less than gtol and if, for example, the function is | -//| bounded below, then there is always a step which satisfies both | -//| conditions. If no step can be found which satisfies both | -//| conditions, then the algorithm usually stops when rounding | -//| errors prevent further progress. In this case stp only satisfies | -//| the sufficient decrease condition. | -//| Parameters descriprion | -//| N is a positive integer input variable set to the number of | -//| variables. | -//| X is an array of length n. on input it must contain the base | -//| point for the line search. on output it contains x+stp*s. | -//| F is a variable. on input it must contain the value of f at x. On| -//| output it contains the value of f at x + stp*s. | -//| G is an array of length n. on input it must contain the gradient | -//| of f at x. On output it contains the gradient of f at x + stp*s. | -//| s is an input array of length n which specifies the search | -//| direction. | -//| Stp is a nonnegative variable. on input stp contains an initial| -//| estimate of a satisfactory step. on output stp contains the final| -//| estimate. | -//| Ftol and gtol are nonnegative input variables. termination occurs| -//| when the sufficient decrease condition and the directional | -//| derivative condition are satisfied. | -//| Xtol is a nonnegative input variable. termination occurs when the| -//| relative width of the interval of uncertainty is at most xtol. | -//| Stpmin and stpmax are nonnegative input variables which specify | -//| lower and upper bounds for the step. | -//| Maxfev is a positive integer input variable. termination occurs | -//| when the number of calls to fcn is at least maxfev by the end of | -//| an iteration. | -//| Info is an integer output variable set as follows: | -//| info = 0 improper input parameters. | -//| info = 1 the sufficient decrease condition and the | -//| directional derivative condition hold. | -//| info = 2 relative width of the interval of uncertainty | -//| is at most xtol. | -//| info = 3 number of calls to fcn has reached maxfev. | -//| info = 4 the step is at the lower bound stpmin. | -//| info = 5 the step is at the upper bound stpmax. | -//| info = 6 rounding errors prevent further progress. | -//| there may not be a step which satisfies the | -//| sufficient decrease and curvature conditions. | -//| tolerances may be too small. | -//| Nfev is an integer output variable set to the number of calls to | -//| fcn. | -//| wa is a work array of length n. | -//| argonne national laboratory. minpack project. june 1983 | -//| Jorge J. More', David J. Thuente | -//+------------------------------------------------------------------+ -static void CLogit::MNLMCSrch(const int n,double &x[],double &f,double &g[], - double &s[],double &stp,int &info,int &nfev, - double &wa[],CLogitMCState &state,int &stage) - { -//--- create variables - double v=0; - double p5=0; - double p66=0; - double zero=0; - int i_=0; -//--- init - p5=0.5; - p66=0.66; - state.m_xtrapf=4.0; - zero=0; -//--- Main cycle - while(true) - { - //--- check - if(stage==0) - { - //--- NEXT - stage=2; - continue; - } - //--- check - if(stage==2) - { - state.m_infoc=1; - info=0; - //--- CHECK THE INPUT PARAMETERS FOR ERRORS. - if(n<=0 || stp<=0.0 || m_ftol<0.0 || m_gtol=0.0) - { - stage=0; - return; - } - //--- initialize local variables. - state.m_brackt=false; - state.m_stage1=true; - nfev=0; - state.m_finit=f; - state.m_dgtest=m_ftol*state.m_dginit; - state.m_width=m_stpmax-m_stpmin; - state.m_width1=state.m_width/p5; - for(i_=0;i_<=n-1;i_++) - wa[i_]=x[i_]; - //--- the variables stx,fx,dgx contain the values of the step, - //--- function,and directional derivative at the best step. - //--- the variables sty,fy,dgy contain the value of the step, - //--- function,and derivative at the other endpoint of - //--- the interval of uncertainty. - //--- the variables stp,f,dg contain the values of the step, - //--- function,and derivative at the current step. - state.m_stx=0; - state.m_fx=state.m_finit; - state.m_dgx=state.m_dginit; - state.m_sty=0; - state.m_fy=state.m_finit; - state.m_dgy=state.m_dginit; - //--- NEXT - stage=3; - continue; - } - //--- check - if(stage==3) - { - //--- start of iteration. - //--- set the minimum and maximum steps to correspond - //--- to the present interval of uncertainty. - if(state.m_brackt) - { - //--- check - if(state.m_stxm_stpmax) - stp=m_stpmax; - //--- check - if(stp=state.m_stmax)) || nfev>=m_maxfev-1) || state.m_infoc==0) || (state.m_brackt && state.m_stmax-state.m_stmin<=m_xtol*state.m_stmax)) - stp=state.m_stx; - //--- evaluate the function and gradient at stp - //--- and compute the directional derivative. - for(i_=0;i_<=n-1;i_++) - x[i_]=wa[i_]; - for(i_=0;i_<=n-1;i_++) - x[i_]=x[i_]+stp*s[i_]; - //--- next - stage=4; - return; - } - //--- check - if(stage==4) - { - info=0; - nfev=nfev+1; - v=0.0; - //--- calculation - for(i_=0;i_<=n-1;i_++) - v+=g[i_]*s[i_]; - state.m_dg=v; - state.m_ftest1=state.m_finit+stp*state.m_dgtest; - //--- test for convergence. - if((state.m_brackt && (stp<=state.m_stmin || stp>=state.m_stmax)) || state.m_infoc==0) - info=6; - //--- check - if((stp==m_stpmax &&f<=state.m_ftest1) &&state.m_dg<=state.m_dgtest) - info=5; - //--- check - if(stp==m_stpmin && (f>state.m_ftest1 || state.m_dg>=state.m_dgtest)) - info=4; - //--- check - if(nfev>=m_maxfev) - info=3; - //--- check - if(state.m_brackt && state.m_stmax-state.m_stmin<=m_xtol*state.m_stmax) - info=2; - //--- check - if(f<=state.m_ftest1 && MathAbs(state.m_dg)<=-(m_gtol*state.m_dginit)) - info=1; - //--- check for termination. - if(info!=0) - { - stage=0; - return; - } - //--- in the first stage we seek a step for which the modified - //--- function has a nonpositive value and nonnegative derivative. - if((state.m_stage1 && f<=state.m_ftest1) && state.m_dg>=MathMin(m_ftol,m_gtol)*state.m_dginit) - state.m_stage1=false; - //--- a modified function is used to predict the step only if - //--- we have not obtained a step for which the modified - //--- function has a nonpositive function value and nonnegative - //--- derivative,and if a lower function value has been - //--- obtained but the decrease is not sufficient. - if((state.m_stage1 && f<=state.m_fx) && f>state.m_ftest1) - { - //--- define the modified function and derivative values. - state.m_fm=f-stp*state.m_dgtest; - state.m_fxm=state.m_fx-state.m_stx*state.m_dgtest; - state.m_fym=state.m_fy-state.m_sty*state.m_dgtest; - state.m_dgm=state.m_dg-state.m_dgtest; - state.m_dgxm=state.m_dgx-state.m_dgtest; - state.m_dgym=state.m_dgy-state.m_dgtest; - //--- call cstep to update the interval of uncertainty - //--- and to compute the new step. - MNLMCStep(state.m_stx,state.m_fxm,state.m_dgxm,state.m_sty,state.m_fym,state.m_dgym,stp,state.m_fm,state.m_dgm,state.m_brackt,state.m_stmin,state.m_stmax,state.m_infoc); - //--- reset the function and gradient values for f. - state.m_fx=state.m_fxm+state.m_stx*state.m_dgtest; - state.m_fy=state.m_fym+state.m_sty*state.m_dgtest; - state.m_dgx=state.m_dgxm+state.m_dgtest; - state.m_dgy=state.m_dgym+state.m_dgtest; - } - else - { - //--- call mcstep to update the interval of uncertainty - //--- and to compute the new step. - MNLMCStep(state.m_stx,state.m_fx,state.m_dgx,state.m_sty,state.m_fy,state.m_dgy,stp,f,state.m_dg,state.m_brackt,state.m_stmin,state.m_stmax,state.m_infoc); - } - //--- force a sufficient decrease in the size of the - //--- interval of uncertainty. - if(state.m_brackt) - { - //--- check - if(MathAbs(state.m_sty-state.m_stx)>=p66*state.m_width1) - stp=state.m_stx+p5*(state.m_sty-state.m_stx); - state.m_width1=state.m_width; - state.m_width=MathAbs(state.m_sty-state.m_stx); - } - //--- next. - stage=3; - continue; - } - } - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MNLMCSrch | -//+------------------------------------------------------------------+ -static void CLogit::MNLMCStep(double &stx,double &fx,double &dx,double &sty, - double &fy,double &dy,double &stp,const double fp, - const double dp,bool &brackt,const double stmin, - const double stmax,int &info) - { -//--- create variables - bool bound; - double gamma=0; - double p=0; - double q=0; - double r=0; - double s=0; - double sgnd=0; - double stpc=0; - double stpf=0; - double stpq=0; - double theta=0; -//--- initialization - info=0; -//--- check the input parameters for errors. - if(((brackt && (stp<=MathMin(stx,sty) || stp>=MathMax(stx,sty))) || dx*(stp-stx)>=0.0) || stmaxfx) - { - //--- change value - info=1; - bound=true; - theta=3*(fx-fp)/(stp-stx)+dx+dp; - s=MathMax(MathAbs(theta),MathMax(MathAbs(dx),MathAbs(dp))); - gamma=s*MathSqrt(CMath::Sqr(theta/s)-dx/s*(dp/s)); - //--- check - if(stpstx) - gamma=-gamma; - //--- change values - p=gamma-dp+theta; - q=gamma-dp+gamma+dx; - r=p/q; - stpc=stp+r*(stx-stp); - stpq=stp+dp/(dp-dx)*(stx-stp); - //--- check - if(MathAbs(stpc-stp)>MathAbs(stpq-stp)) - stpf=stpc; - else - stpf=stpq; - brackt=true; - } - else - { - //--- check - if(MathAbs(dp)stx) - gamma=-gamma; - p=gamma-dp+theta; - q=gamma+(dx-dp)+gamma; - r=p/q; - //--- check - if(r<0.0 && gamma!=0.0) - stpc=stp+r*(stx-stp); - else - { - //--- check - if(stp>stx) - stpc=stmax; - else - stpc=stmin; - } - stpq=stp+dp/(dp-dx)*(stx-stp); - //--- check - if(brackt) - { - //--- check - if(MathAbs(stp-stpc)MathAbs(stp-stpq)) - stpf=stpc; - else - stpf=stpq; - } - } - else - { - //--- fourth case. a lower function value,derivatives of the - //--- same sign,and the magnitude of the derivative does - //--- not decrease. if the minimum is not bracketed,the step - //--- is either stpmin or stpmax,else the cubic step is taken. - info=4; - bound=false; - //--- check - if(brackt) - { - //--- change values - theta=3*(fp-fy)/(sty-stp)+dy+dp; - s=MathMax(MathAbs(theta),MathMax(MathAbs(dy),MathAbs(dp))); - gamma=s*MathSqrt(CMath::Sqr(theta/s)-dy/s*(dp/s)); - //--- check - if(stp>sty) - gamma=-gamma; - //--- change values - p=gamma-dp+theta; - q=gamma-dp+gamma+dy; - r=p/q; - stpc=stp+r*(sty-stp); - stpf=stpc; - } - else - { - //--- check - if(stp>stx) - stpf=stmax; - else - stpf=stmin; - } - } - } - } -//--- update the interval of uncertainty. this update does not -//--- depend on the new step or the case analysis above. - if(fp>fx) - { - sty=stp; - fy=fp; - dy=dp; - } - else - { - //--- check - if(sgnd<0.0) - { - sty=stx; - fy=fx; - dy=dx; - } - //--- change values - stx=stp; - fx=fp; - dx=dp; - } -//--- compute the new step and safeguard it. - stpf=MathMin(stmax,stpf); - stpf=MathMax(stmin,stpf); - stp=stpf; -//--- check - if(brackt && bound) - { - //--- check - if(sty>stx) - stp=MathMin(stx+0.66*(sty-stx),stp); - else - stp=MathMax(stx+0.66*(sty-stx),stp); - } - } -//+------------------------------------------------------------------+ -//| This structure is a MCPD (Markov Chains for Population Data) | -//| solver. You should use ALGLIB functions in order to work with | -//| this object. | -//+------------------------------------------------------------------+ -class CMCPDState - { -public: - //--- variables - int m_n; - int m_npairs; - int m_ccnt; - double m_regterm; - int m_repinneriterationscount; - int m_repouteriterationscount; - int m_repnfev; - int m_repterminationtype; - CMinBLEICState m_bs; - CMinBLEICReport m_br; - //--- arrays - int m_states[]; - int m_ct[]; - double m_pw[]; - double m_tmpp[]; - double m_effectivew[]; - double m_effectivebndl[]; - double m_effectivebndu[]; - int m_effectivect[]; - double m_h[]; - //--- matrices - CMatrixDouble m_data; - CMatrixDouble m_ec; - CMatrixDouble m_bndl; - CMatrixDouble m_bndu; - CMatrixDouble m_c; - CMatrixDouble m_priorp; - CMatrixDouble m_effectivec; - CMatrixDouble m_p; - //--- constructor, destructor - CMCPDState(void); - ~CMCPDState(void); - //--- copy - void Copy(CMCPDState &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMCPDState::CMCPDState(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMCPDState::~CMCPDState(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CMCPDState::Copy(CMCPDState &obj) - { -//--- copy variables - m_n=obj.m_n; - m_npairs=obj.m_npairs; - m_ccnt=obj.m_ccnt; - m_regterm=obj.m_regterm; - m_repinneriterationscount=obj.m_repinneriterationscount; - m_repouteriterationscount=obj.m_repouteriterationscount; - m_repnfev=obj.m_repnfev; - m_repterminationtype=obj.m_repterminationtype; - m_bs.Copy(obj.m_bs); - m_br.Copy(obj.m_br); -//--- copy arrays - ArrayCopy(m_states,obj.m_states); - ArrayCopy(m_ct,obj.m_ct); - ArrayCopy(m_pw,obj.m_pw); - ArrayCopy(m_tmpp,obj.m_tmpp); - ArrayCopy(m_effectivew,obj.m_effectivew); - ArrayCopy(m_effectivebndl,obj.m_effectivebndl); - ArrayCopy(m_effectivebndu,obj.m_effectivebndu); - ArrayCopy(m_effectivect,obj.m_effectivect); - ArrayCopy(m_h,obj.m_h); -//--- copy matrices - m_data=obj.m_data; - m_ec=obj.m_ec; - m_bndl=obj.m_bndl; - m_bndu=obj.m_bndu; - m_c=obj.m_c; - m_priorp=obj.m_priorp; - m_effectivec=obj.m_effectivec; - m_p=obj.m_p; - } -//+------------------------------------------------------------------+ -//| This structure is a MCPD (Markov Chains for Population Data) | -//| solver. | -//| You should use ALGLIB functions in order to work with this object| -//+------------------------------------------------------------------+ -class CMCPDStateShell - { -private: - CMCPDState m_innerobj; -public: - //--- constructors, destructor - CMCPDStateShell(void); - CMCPDStateShell(CMCPDState &obj); - ~CMCPDStateShell(void); - //--- method - CMCPDState *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMCPDStateShell::CMCPDStateShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CMCPDStateShell::CMCPDStateShell(CMCPDState &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMCPDStateShell::~CMCPDStateShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CMCPDState *CMCPDStateShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| This structure is a MCPD training report: | -//| InnerIterationsCount - number of inner iterations of the| -//| underlying optimization algorithm| -//| OuterIterationsCount - number of outer iterations of the| -//| underlying optimization algorithm| -//| NFEV - number of merit function | -//| evaluations | -//| TerminationType - termination type | -//| (same as for MinBLEIC optimizer, | -//| positive values denote success, | -//| negative ones - failure) | -//+------------------------------------------------------------------+ -class CMCPDReport - { -public: - //--- variables - int m_inneriterationscount; - int m_outeriterationscount; - int m_nfev; - int m_terminationtype; - //--- constructor, destructor - CMCPDReport(void); - ~CMCPDReport(void); - //--- copy - void Copy(CMCPDReport &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMCPDReport::CMCPDReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMCPDReport::~CMCPDReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CMCPDReport::Copy(CMCPDReport &obj) - { -//--- copy variables - m_inneriterationscount=obj.m_inneriterationscount; - m_outeriterationscount=obj.m_outeriterationscount; - m_nfev=obj.m_nfev; - m_terminationtype=obj.m_terminationtype; - } -//+------------------------------------------------------------------+ -//| This structure is a MCPD training report: | -//| InnerIterationsCount - number of inner iterations of the| -//| underlying optimization algorithm| -//| OuterIterationsCount - number of outer iterations of the| -//| underlying optimization algorithm| -//| NFEV - number of merit function | -//| evaluations | -//| TerminationType - termination type | -//| (same as for MinBLEIC optimizer, | -//| positive values denote success, | -//| negative ones - failure) | -//+------------------------------------------------------------------+ -class CMCPDReportShell - { -private: - CMCPDReport m_innerobj; -public: - //--- constructors, destructor - CMCPDReportShell(void); - CMCPDReportShell(CMCPDReport &obj); - ~CMCPDReportShell(void); - //--- methods - int GetInnerIterationsCount(void); - void SetInnerIterationsCount(const int i); - int GetOuterIterationsCount(void); - void SetOuterIterationsCount(const int i); - int GetNFev(void); - void SetNFev(const int i); - int GetTerminationType(void); - void SetTerminationType(const int i); - CMCPDReport *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMCPDReportShell::CMCPDReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CMCPDReportShell::CMCPDReportShell(CMCPDReport &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMCPDReportShell::~CMCPDReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable inneriterationscount | -//+------------------------------------------------------------------+ -int CMCPDReportShell::GetInnerIterationsCount(void) - { -//--- return result - return(m_innerobj.m_inneriterationscount); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable inneriterationscount | -//+------------------------------------------------------------------+ -void CMCPDReportShell::SetInnerIterationsCount(const int i) - { -//--- change value - m_innerobj.m_inneriterationscount=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable outeriterationscount | -//+------------------------------------------------------------------+ -int CMCPDReportShell::GetOuterIterationsCount(void) - { -//--- return result - return(m_innerobj.m_outeriterationscount); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable outeriterationscount | -//+------------------------------------------------------------------+ -void CMCPDReportShell::SetOuterIterationsCount(const int i) - { -//--- change value - m_innerobj.m_outeriterationscount=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable nfev | -//+------------------------------------------------------------------+ -int CMCPDReportShell::GetNFev(void) - { -//--- return result - return(m_innerobj.m_nfev); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable nfev | -//+------------------------------------------------------------------+ -void CMCPDReportShell::SetNFev(const int i) - { -//--- change value - m_innerobj.m_nfev=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable terminationtype | -//+------------------------------------------------------------------+ -int CMCPDReportShell::GetTerminationType(void) - { -//--- return result - return(m_innerobj.m_terminationtype); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable terminationtype | -//+------------------------------------------------------------------+ -void CMCPDReportShell::SetTerminationType(const int i) - { -//--- change value - m_innerobj.m_terminationtype=i; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CMCPDReport *CMCPDReportShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Markov chains class | -//+------------------------------------------------------------------+ -class CMarkovCPD - { -private: - //--- private method - static void MCPDInit(const int n,const int entrystate,const int exitstate,CMCPDState &s); -public: - //--- constant - static const double m_xtol; - //--- constructor, destructor - CMarkovCPD(void); - ~CMarkovCPD(void); - //--- public methods - static void MCPDCreate(const int n,CMCPDState &s); - static void MCPDCreateEntry(const int n,const int entrystate,CMCPDState &s); - static void MCPDCreateExit(const int n,const int exitstate,CMCPDState &s); - static void MCPDCreateEntryExit(const int n,const int entrystate,const int exitstate,CMCPDState &s); - static void MCPDAddTrack(CMCPDState &s,CMatrixDouble &xy,const int k); - static void MCPDSetEC(CMCPDState &s,CMatrixDouble &ec); - static void MCPDAddEC(CMCPDState &s,const int i,const int j,const double c); - static void MCPDSetBC(CMCPDState &s,CMatrixDouble &bndl,CMatrixDouble &bndu); - static void MCPDAddBC(CMCPDState &s,const int i,const int j,double bndl,double bndu); - static void MCPDSetLC(CMCPDState &s,CMatrixDouble &c,int &ct[],const int k); - static void MCPDSetTikhonovRegularizer(CMCPDState &s,const double v); - static void MCPDSetPrior(CMCPDState &s,CMatrixDouble &cpp); - static void MCPDSetPredictionWeights(CMCPDState &s,double &pw[]); - static void MCPDSolve(CMCPDState &s); - static void MCPDResults(CMCPDState &s,CMatrixDouble &p,CMCPDReport &rep); - }; -//+------------------------------------------------------------------+ -//| Initialize constant | -//+------------------------------------------------------------------+ -const double CMarkovCPD::m_xtol=1.0E-8; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMarkovCPD::CMarkovCPD(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMarkovCPD::~CMarkovCPD(void) - { - - } -//+------------------------------------------------------------------+ -//| DESCRIPTION: | -//| This function creates MCPD (Markov Chains for Population Data) | -//| solver. | -//| This solver can be used to find transition matrix P for | -//| N-dimensional prediction problem where transition from X[i] to | -//| X[i+1] is modelled as X[i+1] = P*X[i] | -//| where X[i] and X[i+1] are N-dimensional population vectors | -//| (components of each X are non-negative), and P is a N*N | -//| transition matrix (elements of are non-negative, each column | -//| sums to 1.0). | -//| Such models arise when when: | -//| * there is some population of individuals | -//| * individuals can have different states | -//| * individuals can transit from one state to another | -//| * population size is constant, i.e. there is no new individuals | -//| and no one leaves population | -//| * you want to model transitions of individuals from one state | -//| into another | -//| USAGE: | -//| Here we give very brief outline of the MCPD. We strongly | -//| recommend you to read examples in the ALGLIB Reference Manual | -//| and to read ALGLIB User Guide on data analysis which is | -//| available at http://www.alglib.net/dataanalysis/ | -//| 1. User initializes algorithm state with MCPDCreate() call | -//| 2. User adds one or more tracks - sequences of states which | -//| describe evolution of a system being modelled from different | -//| starting conditions | -//| 3. User may add optional boundary, equality and/or linear | -//| constraints on the coefficients of P by calling one of the | -//| following functions: | -//| * MCPDSetEC() to set equality constraints | -//| * MCPDSetBC() to set bound constraints | -//| * MCPDSetLC() to set linear constraints | -//| 4. Optionally, user may set custom weights for prediction errors | -//| (by default, algorithm assigns non-equal, automatically chosen| -//| weights for errors in the prediction of different components | -//| of X). It can be done with a call of | -//| MCPDSetPredictionWeights() function. | -//| 5. User calls MCPDSolve() function which takes algorithm state | -//| and pointer (delegate, etc.) to callback function which | -//| calculates F/G. | -//| 6. User calls MCPDResults() to get solution | -//| INPUT PARAMETERS: | -//| N - problem dimension, N>=1 | -//| OUTPUT PARAMETERS: | -//| State - structure stores algorithm state | -//+------------------------------------------------------------------+ -static void CMarkovCPD::MCPDCreate(const int n,CMCPDState &s) - { -//--- check - if(!CAp::Assert(n>=1,"MCPDCreate: N<1")) - return; -//--- function call - MCPDInit(n,-1,-1,s); - } -//+------------------------------------------------------------------+ -//| DESCRIPTION: | -//| This function is a specialized version of MCPDCreate() function, | -//| and we recommend you to read comments for this function for | -//| general information about MCPD solver. | -//| This function creates MCPD (Markov Chains for Population Data) | -//| solver for "Entry-state" model, i.e. model where transition from | -//| X[i] to X[i+1] is modelled as | -//| X[i+1] = P*X[i] | -//| where | -//| X[i] and X[i+1] are N-dimensional state vectors | -//| P is a N*N transition matrix | -//| and one selected component of X[] is called "entry" state and | -//| is treated in a special way: | -//| system state always transits from "entry" state to some | -//| another state | -//| system state can not transit from any state into "entry" | -//| state | -//| Such conditions basically mean that row of P which corresponds to| -//| "entry" state is zero. | -//| Such models arise when: | -//| * there is some population of individuals | -//| * individuals can have different states | -//| * individuals can transit from one state to another | -//| * population size is NOT constant - at every moment of time | -//| there is some (unpredictable) amount of "new" individuals, | -//| which can transit into one of the states at the next turn, but | -//| still no one leaves population | -//| * you want to model transitions of individuals from one state | -//| into another | -//| * but you do NOT want to predict amount of "new" individuals | -//| because it does not depends on individuals already present | -//| (hence system can not transit INTO entry state - it can only | -//| transit FROM it). | -//| This model is discussed in more details in the ALGLIB User Guide | -//| (see http://www.alglib.net/dataanalysis/ for more data). | -//| INPUT PARAMETERS: | -//| N - problem dimension, N>=2 | -//| EntryState- index of entry state, in 0..N-1 | -//| OUTPUT PARAMETERS: | -//| State - structure stores algorithm state | -//+------------------------------------------------------------------+ -static void CMarkovCPD::MCPDCreateEntry(const int n,const int entrystate, - CMCPDState &s) - { -//--- check - if(!CAp::Assert(n>=2,__FUNCTION__+": N<2")) - return; -//--- check - if(!CAp::Assert(entrystate>=0,__FUNCTION__+": EntryState<0")) - return; -//--- check - if(!CAp::Assert(entrystate=N")) - return; -//--- function call - MCPDInit(n,entrystate,-1,s); - } -//+------------------------------------------------------------------+ -//| DESCRIPTION: | -//| This function is a specialized version of MCPDCreate() function, | -//| and we recommend you to read comments for this function for | -//| general information about MCPD solver. | -//| This function creates MCPD (Markov Chains for Population Data) | -//| solver for "Exit-state" model, i.e. model where transition from | -//| X[i] to X[i+1] is modelled as | -//| X[i+1] = P*X[i] | -//| where | -//| X[i] and X[i+1] are N-dimensional state vectors | -//| P is a N*N transition matrix | -//| and one selected component of X[] is called "exit" state and | -//| is treated in a special way: | -//| system state can transit from any state into "exit" state | -//| system state can not transit from "exit" state into any other| -//| state transition operator discards "exit" state (makes it | -//| zero at each turn) | -//| Such conditions basically mean that column of P which | -//| corresponds to "exit" state is zero. Multiplication by such P | -//| may decrease sum of vector components. | -//| Such models arise when: | -//| * there is some population of individuals | -//| * individuals can have different states | -//| * individuals can transit from one state to another | -//| * population size is NOT constant - individuals can move into | -//| "exit" state and leave population at the next turn, but there | -//| are no new individuals | -//| * amount of individuals which leave population can be predicted | -//| * you want to model transitions of individuals from one state | -//| into another (including transitions into the "exit" state) | -//| This model is discussed in more details in the ALGLIB User Guide | -//| (see http://www.alglib.net/dataanalysis/ for more data). | -//| INPUT PARAMETERS: | -//| N - problem dimension, N>=2 | -//| ExitState- index of exit state, in 0..N-1 | -//| OUTPUT PARAMETERS: | -//| State - structure stores algorithm state | -//+------------------------------------------------------------------+ -static void CMarkovCPD::MCPDCreateExit(const int n,const int exitstate, - CMCPDState &s) - { -//--- check - if(!CAp::Assert(n>=2,__FUNCTION__+": N<2")) - return; -//--- check - if(!CAp::Assert(exitstate>=0,__FUNCTION__+": ExitState<0")) - return; -//--- check - if(!CAp::Assert(exitstate=N")) - return; -//--- function call - MCPDInit(n,-1,exitstate,s); - } -//+------------------------------------------------------------------+ -//| DESCRIPTION: | -//| This function is a specialized version of MCPDCreate() function, | -//| and we recommend you to read comments for this function for | -//| general information about MCPD solver. | -//| This function creates MCPD (Markov Chains for Population Data) | -//| solver for "Entry-Exit-states" model, i.e. model where transition| -//| from X[i] to X[i+1] is modelled as | -//| X[i+1] = P*X[i] | -//| where | -//| X[i] and X[i+1] are N-dimensional state vectors | -//| P is a N*N transition matrix | -//| one selected component of X[] is called "entry" state and is a | -//| treated in special way: | -//| system state always transits from "entry" state to some | -//| another state | -//| system state can not transit from any state into "entry" | -//| state | -//| and another one component of X[] is called "exit" state and is | -//| treated in a special way too: | -//| system state can transit from any state into "exit" state | -//| system state can not transit from "exit" state into any other| -//| state transition operator discards "exit" state (makes it | -//| zero at each turn) | -//| Such conditions basically mean that: | -//| row of P which corresponds to "entry" state is zero | -//| column of P which corresponds to "exit" state is zero | -//| Multiplication by such P may decrease sum of vector components. | -//| Such models arise when: | -//| * there is some population of individuals | -//| * individuals can have different states | -//| * individuals can transit from one state to another | -//| * population size is NOT constant | -//| * at every moment of time there is some (unpredictable) amount | -//| of "new" individuals, which can transit into one of the states | -//| at the next turn | -//| * some individuals can move (predictably) into "exit" state | -//| and leave population at the next turn | -//| * you want to model transitions of individuals from one state | -//| into another, including transitions from the "entry" state and | -//| into the "exit" state. | -//| * but you do NOT want to predict amount of "new" individuals | -//| because it does not depends on individuals already present | -//| (hence system can not transit INTO entry state - it can only | -//| transit FROM it). | -//| This model is discussed in more details in the ALGLIB User | -//| Guide (see http://www.alglib.net/dataanalysis/ for more data). | -//| INPUT PARAMETERS: | -//| N - problem dimension, N>=2 | -//| EntryState- index of entry state, in 0..N-1 | -//| ExitState- index of exit state, in 0..N-1 | -//| OUTPUT PARAMETERS: | -//| State - structure stores algorithm state | -//+------------------------------------------------------------------+ -static void CMarkovCPD::MCPDCreateEntryExit(const int n,const int entrystate, - const int exitstate,CMCPDState &s) - { -//--- check - if(!CAp::Assert(n>=2,__FUNCTION__+": N<2")) - return; -//--- check - if(!CAp::Assert(entrystate>=0,__FUNCTION__+": EntryState<0")) - return; -//--- check - if(!CAp::Assert(entrystate=N")) - return; -//--- check - if(!CAp::Assert(exitstate>=0,__FUNCTION__+": ExitState<0")) - return; -//--- check - if(!CAp::Assert(exitstate=N")) - return; -//--- check - if(!CAp::Assert(entrystate!=exitstate,__FUNCTION__+": EntryState=ExitState")) - return; -//--- function call - MCPDInit(n,entrystate,exitstate,s); - } -//+------------------------------------------------------------------+ -//| This function is used to add a track - sequence of system states | -//| at the different moments of its evolution. | -//| You may add one or several tracks to the MCPD solver. In case you| -//| have several tracks, they won't overwrite each other. For | -//| example, if you pass two tracks, A1-A2-A3 (system at t=A+1, t=A+2| -//| and t=A+3) and B1-B2-B3, then solver will try to model | -//| transitions from t=A+1 to t=A+2, t=A+2 to t=A+3, t=B+1 to t=B+2, | -//| t=B+2 to t=B+3. But it WONT mix these two tracks - i.e. it wont | -//| try to model transition from t=A+3 to t=B+1. | -//| INPUT PARAMETERS: | -//| S - solver | -//| XY - track, array[K,N]: | -//| * I-th row is a state at t=I | -//| * elements of XY must be non-negative (exception | -//| will be thrown on negative elements) | -//| K - number of points in a track | -//| * if given, only leading K rows of XY are used | -//| * if not given, automatically determined from | -//| size of XY | -//| NOTES: | -//| 1. Track may contain either proportional or population data: | -//| * with proportional data all rows of XY must sum to 1.0, i.e. | -//| we have proportions instead of absolute population values | -//| * with population data rows of XY contain population counts | -//| and generally do not sum to 1.0 (although they still must be| -//| non-negative) | -//+------------------------------------------------------------------+ -static void CMarkovCPD::MCPDAddTrack(CMCPDState &s,CMatrixDouble &xy, - const int k) - { -//--- create variables - int i=0; - int j=0; - int n=0; - double s0=0; - double s1=0; -//--- initialization - n=s.m_n; -//--- check - if(!CAp::Assert(k>=0,__FUNCTION__+": K<0")) - return; -//--- check - if(!CAp::Assert(CAp::Cols(xy)>=n,__FUNCTION__+": Cols(XY)=k,__FUNCTION__+": Rows(XY)=0.0,__FUNCTION__+": XY contains negative elements")) - return; - } - } -//--- check - if(k<2) - return; -//--- check - if(CAp::Rows(s.m_data)=0) - s0=s0+xy[i][j]; - //--- check - if(s.m_states[j]<=0) - s1=s1+xy[i+1][j]; - } - //--- check - if(s0>0.0 && s1>0.0) - { - for(j=0;j<=n-1;j++) - { - //--- check - if(s.m_states[j]>=0) - s.m_data[s.m_npairs].Set(j,xy[i][j]/s0); - else - s.m_data[s.m_npairs].Set(j,0.0); - //--- check - if(s.m_states[j]<=0) - s.m_data[s.m_npairs].Set(n+j,xy[i+1][j]/s1); - else - s.m_data[s.m_npairs].Set(n+j,0.0); - } - //--- change value - s.m_npairs=s.m_npairs+1; - } - } - } -//+------------------------------------------------------------------+ -//| This function is used to add equality constraints on the elements| -//| of the transition matrix P. | -//| MCPD solver has four types of constraints which can be placed | -//| on P: | -//| * user-specified equality constraints (optional) | -//| * user-specified bound constraints (optional) | -//| * user-specified general linear constraints (optional) | -//| * basic constraints (always present): | -//| * non-negativity: P[i,j]>=0 | -//| * consistency: every column of P sums to 1.0 | -//| Final constraints which are passed to the underlying optimizer | -//| are calculated as intersection of all present constraints. For | -//| example, you may specify boundary constraint on P[0,0] and | -//| equality one: | -//| 0.1<=P[0,0]<=0.9 | -//| P[0,0]=0.5 | -//| Such combination of constraints will be silently reduced to their| -//| intersection, which is P[0,0]=0.5. | -//| This function can be used to place equality constraints on | -//| arbitrary subset of elements of P. Set of constraints is | -//| specified by EC, which may contain either NAN's or finite numbers| -//| from [0,1]. NAN denotes absence of constraint, finite number | -//| denotes equality constraint on specific element of P. | -//| You can also use MCPDAddEC() function which allows to ADD | -//| equality constraint for one element of P without changing | -//| constraints for other elements. | -//| These functions (MCPDSetEC and MCPDAddEC) interact as follows: | -//| * there is internal matrix of equality constraints which is | -//| stored in the MCPD solver | -//| * MCPDSetEC() replaces this matrix by another one (SET) | -//| * MCPDAddEC() modifies one element of this matrix and leaves | -//| other ones unchanged (ADD) | -//| * thus MCPDAddEC() call preserves all modifications done by | -//| previous calls, while MCPDSetEC() completely discards all | -//| changes done to the equality constraints. | -//| INPUT PARAMETERS: | -//| S - solver | -//| EC - equality constraints, array[N,N]. Elements of EC | -//| can be either NAN's or finite numbers from [0,1].| -//| NAN denotes absence of constraints, while finite | -//| value denotes equality constraint on the | -//| corresponding element of P. | -//| NOTES: | -//| 1. infinite values of EC will lead to exception being thrown. | -//| Values less than 0.0 or greater than 1.0 will lead to error code | -//| being returned after call to MCPDSolve(). | -//+------------------------------------------------------------------+ -static void CMarkovCPD::MCPDSetEC(CMCPDState &s,CMatrixDouble &ec) - { -//--- create variables - int i=0; - int j=0; - int n=0; -//--- initialization - n=s.m_n; -//--- check - if(!CAp::Assert(CAp::Cols(ec)>=n,__FUNCTION__+": Cols(EC)=n,__FUNCTION__+": Rows(EC)=0 | -//| * consistency: every column of P sums to 1.0 | -//| Final constraints which are passed to the underlying optimizer | -//| are calculated as intersection of all present constraints. For | -//| example, you may specify boundary constraint on P[0,0] and | -//| equality one: | -//| 0.1<=P[0,0]<=0.9 | -//| P[0,0]=0.5 | -//| Such combination of constraints will be silently reduced to their| -//| intersection, which is P[0,0]=0.5. | -//| This function can be used to ADD equality constraint for one | -//| element of P without changing constraints for other elements. | -//| You can also use MCPDSetEC() function which allows you to specify| -//| arbitrary set of equality constraints in one call. | -//| These functions (MCPDSetEC and MCPDAddEC) interact as follows: | -//| * there is internal matrix of equality constraints which is | -//| stored in the MCPD solver | -//| * MCPDSetEC() replaces this matrix by another one (SET) | -//| * MCPDAddEC() modifies one element of this matrix and leaves | -//| other ones unchanged (ADD) | -//| * thus MCPDAddEC() call preserves all modifications done by | -//| previous calls, while MCPDSetEC() completely discards all | -//| changes done to the equality constraints. | -//| INPUT PARAMETERS: | -//| S - solver | -//| I - row index of element being constrained | -//| J - column index of element being constrained | -//| C - value (constraint for P[I,J]). Can be either NAN | -//| (no constraint) or finite value from [0,1]. | -//| NOTES: | -//| 1. infinite values of C will lead to exception being thrown. | -//| Values less than 0.0 or greater than 1.0 will lead to error code | -//| being returned after call to MCPDSolve(). | -//+------------------------------------------------------------------+ -static void CMarkovCPD::MCPDAddEC(CMCPDState &s,const int i,const int j, - const double c) - { -//--- check - if(!CAp::Assert(i>=0,__FUNCTION__+": I<0")) - return; -//--- check - if(!CAp::Assert(i=N")) - return; -//--- check - if(!CAp::Assert(j>=0,__FUNCTION__+": J<0")) - return; -//--- check - if(!CAp::Assert(j=N")) - return; -//--- check - if(!CAp::Assert(CInfOrNaN::IsNaN(c) || CMath::IsFinite(c),"MCPDAddEC: C is not finite number or NAN")) - return; - s.m_ec[i].Set(j,c); - } -//+------------------------------------------------------------------+ -//| This function is used to add bound constraints on the elements | -//| of the transition matrix P. | -//| MCPD solver has four types of constraints which can be placed | -//| on P: | -//| * user-specified equality constraints (optional) | -//| * user-specified bound constraints (optional) | -//| * user-specified general linear constraints (optional) | -//| * basic constraints (always present): | -//| * non-negativity: P[i,j]>=0 | -//| * consistency: every column of P sums to 1.0 | -//| Final constraints which are passed to the underlying optimizer | -//| are calculated as intersection of all present constraints. For | -//| example, you may specify boundary constraint on P[0,0] and | -//| equality one: | -//| 0.1<=P[0,0]<=0.9 | -//| P[0,0]=0.5 | -//| Such combination of constraints will be silently reduced to their| -//| intersection, which is P[0,0]=0.5. | -//| This function can be used to place bound constraints on arbitrary| -//| subset of elements of P. Set of constraints is specified by | -//| BndL/BndU matrices, which may contain arbitrary combination of | -//| finite numbers or infinities (like -INF=n,__FUNCTION__+": Cols(BndL)=n,__FUNCTION__+": Rows(BndL)=n,__FUNCTION__+": Cols(BndU)=n,__FUNCTION__+": Rows(BndU)=0 | -//| * consistency: every column of P sums to 1.0 | -//| Final constraints which are passed to the underlying optimizer | -//| are calculated as intersection of all present constraints. For | -//| example, you may specify boundary constraint on P[0,0] and | -//| equality one: | -//| 0.1<=P[0,0]<=0.9 | -//| P[0,0]=0.5 | -//| Such combination of constraints will be silently reduced to their| -//| intersection, which is P[0,0]=0.5. | -//| This function can be used to ADD bound constraint for one element| -//| of P without changing constraints for other elements. | -//| You can also use MCPDSetBC() function which allows to place bound| -//| constraints on arbitrary subset of elements of P. Set of | -//| constraints is specified by BndL/BndU matrices, which may | -//| contain arbitrary combination of finite numbers or infinities | -//| (like -INF=0,__FUNCTION__+": I<0")) - return; -//--- check - if(!CAp::Assert(i=N")) - return; -//--- check - if(!CAp::Assert(j>=0,__FUNCTION__+": J<0")) - return; -//--- check - if(!CAp::Assert(j=N")) - return; -//--- check - if(!CAp::Assert(CMath::IsFinite(bndl) || CInfOrNaN::IsNegativeInfinity(bndl),"MCPDAddBC: BndL is NAN or +INF")) - return; -//--- check - if(!CAp::Assert(CMath::IsFinite(bndu) || CInfOrNaN::IsPositiveInfinity(bndu),"MCPDAddBC: BndU is NAN or -INF")) - return; -//--- change values - s.m_bndl[i].Set(j,bndl); - s.m_bndu[i].Set(j,bndu); - } -//+------------------------------------------------------------------+ -//| This function is used to set linear equality/inequality | -//| constraints on the elements of the transition matrix P. | -//| This function can be used to set one or several general linear | -//| constraints on the elements of P. Two types of constraints are | -//| supported: | -//| * equality constraints | -//| * inequality constraints (both less-or-equal and | -//| greater-or-equal) | -//| Coefficients of constraints are specified by matrix C (one of the| -//| parameters). One row of C corresponds to one constraint. | -//| Because transition matrix P has N*N elements, we need N*N columns| -//| to store all coefficients (they are stored row by row), and | -//| one more column to store right part - hence C has N*N+1 columns. | -//| Constraint kind is stored in the CT array. | -//| Thus, I-th linear constraint is | -//| P[0,0]*C[I,0] + P[0,1]*C[I,1] + .. + P[0,N-1]*C[I,N-1] + | -//| + P[1,0]*C[I,N] + P[1,1]*C[I,N+1] + ... + | -//| + P[N-1,N-1]*C[I,N*N-1] ?=? C[I,N*N] | -//| where ?=? can be either "=" (CT[i]=0), "<=" (CT[i]<0) or ">=" | -//| (CT[i]>0). | -//| Your constraint may involve only some subset of P (less than N*N | -//| elements). | -//| For example it can be something like | -//| P[0,0] + P[0,1] = 0.5 | -//| In this case you still should pass matrix with N*N+1 columns, | -//| but all its elements (except for C[0,0], C[0,1] and C[0,N*N-1]) | -//| will be zero. | -//| INPUT PARAMETERS: | -//| S - solver | -//| C - array[K,N*N+1] - coefficients of constraints | -//| (see above for complete description) | -//| CT - array[K] - constraint types | -//| (see above for complete description) | -//| K - number of equality/inequality constraints, K>=0: | -//| * if given, only leading K elements of C/CT are | -//| used | -//| * if not given, automatically determined from | -//| sizes of C/CT | -//+------------------------------------------------------------------+ -static void CMarkovCPD::MCPDSetLC(CMCPDState &s,CMatrixDouble &c,int &ct[], - const int k) - { -//--- create variables - int i=0; - int j=0; - int n=0; -//--- initialization - n=s.m_n; -//--- check - if(!CAp::Assert(CAp::Cols(c)>=n*n+1,__FUNCTION__+": Cols(C)=k,__FUNCTION__+": Rows(C)=k,__FUNCTION__+": Len(CT)=0.0,__FUNCTION__+": V is less than zero")) - return; -//--- change value - s.m_regterm=v; - } -//+------------------------------------------------------------------+ -//| This function allows to set prior values used for regularization | -//| of your problem. | -//| By default, regularizing term is equal to r*||P-prior_P||^2, | -//| where r is a small non-zero value, P is transition matrix, | -//| prior_P is identity matrix, ||X||^2 is a sum of squared elements | -//| of X. | -//| This function allows you to change prior values prior_P. You can | -//| also change r with MCPDSetTikhonovRegularizer() function. | -//| INPUT PARAMETERS: | -//| S - solver | -//| PP - array[N,N], matrix of prior values: | -//| 1. elements must be real numbers from [0,1] | -//| 2. columns must sum to 1.0. | -//| First property is checked (exception is thrown | -//| otherwise), while second one is not | -//| checked/enforced. | -//+------------------------------------------------------------------+ -static void CMarkovCPD::MCPDSetPrior(CMCPDState &s,CMatrixDouble &cpp) - { -//--- create variables - int i=0; - int j=0; - int n=0; -//--- create copy of matrices - CMatrixDouble pp; - pp=cpp; -//--- initialization - n=s.m_n; -//--- check - if(!CAp::Assert(CAp::Cols(pp)>=n,__FUNCTION__+": Cols(PP)=n,__FUNCTION__+": Rows(PP)=0.0 && pp[i][j]<=1.0,__FUNCTION__+": PP[i][j] is less than 0.0 or greater than 1.0")) - return; - //--- change value - s.m_priorp[i].Set(j,pp[i][j]); - } - } - } -//+------------------------------------------------------------------+ -//| This function is used to change prediction weights | -//| MCPD solver scales prediction errors as follows | -//| Error(P) = ||W*(y-P*x)||^2 | -//| where | -//| x is a system state at time t | -//| y is a system state at time t+1 | -//| P is a transition matrix | -//| W is a diagonal scaling matrix | -//| By default, weights are chosen in order to minimize relative | -//| prediction error instead of absolute one. For example, if one | -//| component of state is about 0.5 in magnitude and another one is | -//| about 0.05, then algorithm will make corresponding weights equal | -//| to 2.0 and 20.0. | -//| INPUT PARAMETERS: | -//| S - solver | -//| PW - array[N], weights: | -//| * must be non-negative values (exception will be | -//| thrown otherwise) | -//| * zero values will be replaced by automatically | -//| chosen values | -//+------------------------------------------------------------------+ -static void CMarkovCPD::MCPDSetPredictionWeights(CMCPDState &s,double &pw[]) - { -//--- create variables - int i=0; - int n=0; -//--- initialization - n=s.m_n; -//--- check - if(!CAp::Assert(CAp::Len(pw)>=n,__FUNCTION__+": Length(PW)=0.0,__FUNCTION__+": PW containts negative elements")) - return; - //--- change value - s.m_pw[i]=pw[i]; - } - } -//+------------------------------------------------------------------+ -//| This function is used to start solution of the MCPD problem. | -//| After return from this function, you can use MCPDResults() to get| -//| solution and completion code. | -//+------------------------------------------------------------------+ -static void CMarkovCPD::MCPDSolve(CMCPDState &s) - { -//--- create variables - int n=0; - int npairs=0; - int ccnt=0; - int i=0; - int j=0; - int k=0; - int k2=0; - double v=0; - double vv=0; - int i_=0; - int i1_=0; -//--- initialization - n=s.m_n; - npairs=s.m_npairs; -//--- init fields of S - s.m_repterminationtype=0; - s.m_repinneriterationscount=0; - s.m_repouteriterationscount=0; - s.m_repnfev=0; - for(k=0;k<=n-1;k++) - { - for(k2=0;k2<=n-1;k2++) - s.m_p[k].Set(k2,CInfOrNaN::NaN()); - } -//--- Generate "effective" weights for prediction and calculate preconditioner - for(i=0;i<=n-1;i++) - { - //--- check - if(s.m_pw[i]==0.0) - { - //--- change values - v=0; - k=0; - for(j=0;j<=npairs-1;j++) - { - //--- check - if(s.m_data[j][n+i]!=0.0) - { - v=v+s.m_data[j][n+i]; - k=k+1; - } - } - //--- check - if(k!=0) - s.m_effectivew[i]=k/v; - else - s.m_effectivew[i]=1.0; - } - else - s.m_effectivew[i]=s.m_pw[i]; - } -//--- calculation - for(i=0;i<=n-1;i++) - { - for(j=0;j<=n-1;j++) - s.m_h[i*n+j]=2*s.m_regterm; - } -//--- calculation - for(k=0;k<=npairs-1;k++) - { - for(i=0;i<=n-1;i++) - { - for(j=0;j<=n-1;j++) - s.m_h[i*n+j]=s.m_h[i*n+j]+2*CMath::Sqr(s.m_effectivew[i])*CMath::Sqr(s.m_data[k][j]); - } - } -//--- calculation - for(i=0;i<=n-1;i++) - { - for(j=0;j<=n-1;j++) - { - //--- check - if(s.m_h[i*n+j]==0.0) - s.m_h[i*n+j]=1; - } - } -//--- Generate "effective" BndL/BndU - for(i=0;i<=n-1;i++) - { - for(j=0;j<=n-1;j++) - { - //--- Set default boundary constraints. - //--- Lower bound is always zero,upper bound is calculated - //--- with respect to entry/exit states. - s.m_effectivebndl[i*n+j]=0.0; - //--- check - if(s.m_states[i]>0 || s.m_states[j]<0) - s.m_effectivebndu[i*n+j]=0.0; - else - s.m_effectivebndu[i*n+j]=1.0; - //--- Calculate intersection of the default and user-specified bound constraints. - //--- This code checks consistency of such combination. - if(CMath::IsFinite(s.m_bndl[i][j]) && s.m_bndl[i][j]>s.m_effectivebndl[i*n+j]) - s.m_effectivebndl[i*n+j]=s.m_bndl[i][j]; - //--- check - if(CMath::IsFinite(s.m_bndu[i][j]) && s.m_bndu[i][j]s.m_effectivebndu[i*n+j]) - { - s.m_repterminationtype=-3; - return; - } - //--- Calculate intersection of the effective bound constraints - //--- and user-specified equality constraints. - //--- This code checks consistency of such combination. - if(CMath::IsFinite(s.m_ec[i][j])) - { - //--- check - if(s.m_ec[i][j]s.m_effectivebndu[i*n+j]) - { - s.m_repterminationtype=-3; - return; - } - //--- change values - s.m_effectivebndl[i*n+j]=s.m_ec[i][j]; - s.m_effectivebndu[i*n+j]=s.m_ec[i][j]; - } - } - } -//--- Generate linear constraints: -//--- * "default" sums-to-one constraints (not generated for "exit" states) - CApServ::RMatrixSetLengthAtLeast(s.m_effectivec,s.m_ccnt+n,n*n+1); -//--- function call - CApServ::IVectorSetLengthAtLeast(s.m_effectivect,s.m_ccnt+n); - ccnt=s.m_ccnt; - for(i=0;i<=s.m_ccnt-1;i++) - { - for(j=0;j<=n*n;j++) - s.m_effectivec[i].Set(j,s.m_c[i][j]); - s.m_effectivect[i]=s.m_ct[i]; - } -//--- calculation - for(i=0;i<=n-1;i++) - { - //--- check - if(s.m_states[i]>=0) - { - for(k=0;k<=n*n-1;k++) - s.m_effectivec[ccnt].Set(k,0); - for(k=0;k<=n-1;k++) - s.m_effectivec[ccnt].Set(k*n+i,1); - //--- change values - s.m_effectivec[ccnt].Set(n*n,1.0); - s.m_effectivect[ccnt]=0; - ccnt=ccnt+1; - } - } -//--- create optimizer - for(i=0;i<=n-1;i++) - { - for(j=0;j<=n-1;j++) - s.m_tmpp[i*n+j]=1.0/(double)n; - } -//--- function calls - CMinBLEIC::MinBLEICRestartFrom(s.m_bs,s.m_tmpp); - CMinBLEIC::MinBLEICSetBC(s.m_bs,s.m_effectivebndl,s.m_effectivebndu); - CMinBLEIC::MinBLEICSetLC(s.m_bs,s.m_effectivec,s.m_effectivect,ccnt); - CMinBLEIC::MinBLEICSetInnerCond(s.m_bs,0,0,m_xtol); - CMinBLEIC::MinBLEICSetOuterCond(s.m_bs,m_xtol,1.0E-5); - CMinBLEIC::MinBLEICSetPrecDiag(s.m_bs,s.m_h); -//--- solve problem - while(CMinBLEIC::MinBLEICIteration(s.m_bs)) - { - //--- check - if(!CAp::Assert(s.m_bs.m_needfg,__FUNCTION__+": internal error")) - return; - //--- check - if(s.m_bs.m_needfg) - { - //--- Calculate regularization term - s.m_bs.m_f=0.0; - vv=s.m_regterm; - for(i=0;i<=n-1;i++) - { - for(j=0;j<=n-1;j++) - { - s.m_bs.m_f=s.m_bs.m_f+vv*CMath::Sqr(s.m_bs.m_x[i*n+j]-s.m_priorp[i][j]); - s.m_bs.m_g[i*n+j]=2*vv*(s.m_bs.m_x[i*n+j]-s.m_priorp[i][j]); - } - } - //--- calculate prediction error/gradient for K-th pair - for(k=0;k<=npairs-1;k++) - { - for(i=0;i<=n-1;i++) - { - i1_=(0)-(i*n); - v=0.0; - for(i_=i*n;i_<=i*n+n-1;i_++) - v+=s.m_bs.m_x[i_]*s.m_data[k][i_+i1_]; - vv=s.m_effectivew[i]; - s.m_bs.m_f=s.m_bs.m_f+CMath::Sqr(vv*(v-s.m_data[k][n+i])); - for(j=0;j<=n-1;j++) - { - s.m_bs.m_g[i*n+j]=s.m_bs.m_g[i*n+j]+2*vv*vv*(v-s.m_data[k][n+i])*s.m_data[k][j]; - } - } - } - //--- continue - continue; - } - } -//--- function call - CMinBLEIC::MinBLEICResultsBuf(s.m_bs,s.m_tmpp,s.m_br); - for(i=0;i<=n-1;i++) - { - for(j=0;j<=n-1;j++) - s.m_p[i].Set(j,s.m_tmpp[i*n+j]); - } -//--- change values - s.m_repterminationtype=s.m_br.m_terminationtype; - s.m_repinneriterationscount=s.m_br.m_inneriterationscount; - s.m_repouteriterationscount=s.m_br.m_outeriterationscount; - s.m_repnfev=s.m_br.m_nfev; - } -//+------------------------------------------------------------------+ -//| MCPD results | -//| INPUT PARAMETERS: | -//| State - algorithm state | -//| OUTPUT PARAMETERS: | -//| P - array[N,N], transition matrix | -//| Rep - optimization report. You should check Rep. | -//| TerminationType in order to distinguish successful| -//| termination from unsuccessful one. Speaking short,| -//| positive values denote success, negative ones are | -//| failures. More information about fields of this | -//| structure can befound in the comments on | -//| MCPDReport datatype. | -//+------------------------------------------------------------------+ -static void CMarkovCPD::MCPDResults(CMCPDState &s,CMatrixDouble &p, - CMCPDReport &rep) - { -//--- create variables - int i=0; - int j=0; -//--- allocation - p.Resize(s.m_n,s.m_n); -//--- copy - for(i=0;i<=s.m_n-1;i++) - { - for(j=0;j<=s.m_n-1;j++) - p[i].Set(j,s.m_p[i][j]); - } -//--- change values - rep.m_terminationtype=s.m_repterminationtype; - rep.m_inneriterationscount=s.m_repinneriterationscount; - rep.m_outeriterationscount=s.m_repouteriterationscount; - rep.m_nfev=s.m_repnfev; - } -//+------------------------------------------------------------------+ -//| Internal initialization function | -//+------------------------------------------------------------------+ -static void CMarkovCPD::MCPDInit(const int n,const int entrystate, - const int exitstate,CMCPDState &s) - { -//--- create variables - int i=0; - int j=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1")) - return; -//--- initialization - s.m_n=n; -//--- allocation - ArrayResizeAL(s.m_states,n); - for(i=0;i<=n-1;i++) - s.m_states[i]=0; -//--- check - if(entrystate>=0) - s.m_states[entrystate]=1; -//--- check - if(exitstate>=0) - s.m_states[exitstate]=-1; -//--- initialization - s.m_npairs=0; - s.m_regterm=1.0E-8; - s.m_ccnt=0; -//--- allocation - s.m_p.Resize(n,n); - s.m_ec.Resize(n,n); - s.m_bndl.Resize(n,n); - s.m_bndu.Resize(n,n); - ArrayResizeAL(s.m_pw,n); - s.m_priorp.Resize(n,n); - ArrayResizeAL(s.m_tmpp,n*n); - ArrayResizeAL(s.m_effectivew,n); - ArrayResizeAL(s.m_effectivebndl,n*n); - ArrayResizeAL(s.m_effectivebndu,n*n); - ArrayResizeAL(s.m_h,n*n); -//--- change values - for(i=0;i<=n-1;i++) - { - for(j=0;j<=n-1;j++) - { - s.m_p[i].Set(j,0.0); - s.m_priorp[i].Set(j,0.0); - s.m_bndl[i].Set(j,CInfOrNaN::NegativeInfinity()); - s.m_bndu[i].Set(j,CInfOrNaN::PositiveInfinity()); - s.m_ec[i].Set(j,CInfOrNaN::NaN()); - } - s.m_pw[i]=0.0; - s.m_priorp[i].Set(i,1.0); - } -//--- allocation - s.m_data.Resize(1,2*n); - for(i=0;i<=2*n-1;i++) - s.m_data[0].Set(i,0.0); - for(i=0;i<=n*n-1;i++) - s.m_tmpp[i]=0.0; -//--- function call - CMinBLEIC::MinBLEICCreate(n*n,s.m_tmpp,s.m_bs); - } -//+------------------------------------------------------------------+ -//| Training report: | -//| * NGrad - number of gradient calculations | -//| * NHess - number of Hessian calculations | -//| * NCholesky - number of Cholesky decompositions | -//+------------------------------------------------------------------+ -class CMLPReport - { -public: - //--- variables - int m_ngrad; - int m_nhess; - int m_ncholesky; - //--- constructor, destructor - CMLPReport(void); - ~CMLPReport(void); - //--- copy - void Copy(CMLPReport &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMLPReport::CMLPReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMLPReport::~CMLPReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CMLPReport::Copy(CMLPReport &obj) - { -//--- copy variables - m_ngrad=obj.m_ngrad; - m_nhess=obj.m_nhess; - m_ncholesky=obj.m_ncholesky; - } -//+------------------------------------------------------------------+ -//| Training report: | -//| * NGrad - number of gradient calculations | -//| * NHess - number of Hessian calculations | -//| * NCholesky - number of Cholesky decompositions | -//+------------------------------------------------------------------+ -class CMLPReportShell - { -private: - CMLPReport m_innerobj; -public: - //--- constructors, destructor - CMLPReportShell(void); - CMLPReportShell(CMLPReport &obj); - ~CMLPReportShell(void); - //--- methods - int GetNGrad(void); - void SetNGrad(const int i); - int GetNHess(void); - void SetNHess(const int i); - int GetNCholesky(void); - void SetNCholesky(const int i); - CMLPReport *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMLPReportShell::CMLPReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CMLPReportShell::CMLPReportShell(CMLPReport &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMLPReportShell::~CMLPReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable ngrad | -//+------------------------------------------------------------------+ -int CMLPReportShell::GetNGrad(void) - { -//--- return result - return(m_innerobj.m_ngrad); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable ngrad | -//+------------------------------------------------------------------+ -void CMLPReportShell::SetNGrad(const int i) - { -//--- change value - m_innerobj.m_ngrad=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable nhess | -//+------------------------------------------------------------------+ -int CMLPReportShell::GetNHess(void) - { -//--- return result - return(m_innerobj.m_nhess); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable nhess | -//+------------------------------------------------------------------+ -void CMLPReportShell::SetNHess(const int i) - { -//--- change value - m_innerobj.m_nhess=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable ncholesky | -//+------------------------------------------------------------------+ -int CMLPReportShell::GetNCholesky(void) - { -//--- return result - return(m_innerobj.m_ncholesky); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable ncholesky | -//+------------------------------------------------------------------+ -void CMLPReportShell::SetNCholesky(const int i) - { -//--- change value - m_innerobj.m_ncholesky=i; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CMLPReport *CMLPReportShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Cross-validation estimates of generalization error | -//+------------------------------------------------------------------+ -class CMLPCVReport - { -public: - //--- variables - double m_relclserror; - double m_avgce; - double m_rmserror; - double m_avgerror; - double m_avgrelerror; - //--- constructor, destructor - CMLPCVReport(void); - ~CMLPCVReport(void); - //--- copy - void Copy(CMLPCVReport &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMLPCVReport::CMLPCVReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMLPCVReport::~CMLPCVReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CMLPCVReport::Copy(CMLPCVReport &obj) - { -//--- copy variables - m_relclserror=obj.m_relclserror; - m_avgce=obj.m_avgce; - m_rmserror=obj.m_rmserror; - m_avgerror=obj.m_avgerror; - m_avgrelerror=obj.m_avgrelerror; - } -//+------------------------------------------------------------------+ -//| Cross-validation estimates of generalization error | -//+------------------------------------------------------------------+ -class CMLPCVReportShell - { -private: - CMLPCVReport m_innerobj; -public: - //--- constructors, destructor - CMLPCVReportShell(void); - CMLPCVReportShell(CMLPCVReport &obj); - ~CMLPCVReportShell(void); - //--- methods - double GetRelClsError(void); - void SetRelClsError(const double d); - double GetAvgCE(void); - void SetAvgCE(const double d); - double GetRMSError(void); - void SetRMSError(const double d); - double GetAvgError(void); - void SetAvgError(const double d); - double GetAvgRelError(void); - void SetAvgRelError(const double d); - CMLPCVReport *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMLPCVReportShell::CMLPCVReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CMLPCVReportShell::CMLPCVReportShell(CMLPCVReport &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMLPCVReportShell::~CMLPCVReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable relclserror | -//+------------------------------------------------------------------+ -double CMLPCVReportShell::GetRelClsError(void) - { -//--- return result - return(m_innerobj.m_relclserror); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable relclserror | -//+------------------------------------------------------------------+ -void CMLPCVReportShell::SetRelClsError(const double d) - { -//--- change value - m_innerobj.m_relclserror=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable avgce | -//+------------------------------------------------------------------+ -double CMLPCVReportShell::GetAvgCE(void) - { -//--- return result - return(m_innerobj.m_avgce); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable avgce | -//+------------------------------------------------------------------+ -void CMLPCVReportShell::SetAvgCE(const double d) - { -//--- change value - m_innerobj.m_avgce=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable rmserror | -//+------------------------------------------------------------------+ -double CMLPCVReportShell::GetRMSError(void) - { -//--- return result - return(m_innerobj.m_rmserror); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable rmserror | -//+------------------------------------------------------------------+ -void CMLPCVReportShell::SetRMSError(const double d) - { -//--- change value - m_innerobj.m_rmserror=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable avgerror | -//+------------------------------------------------------------------+ -double CMLPCVReportShell::GetAvgError(void) - { -//--- return result - return(m_innerobj.m_avgerror); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable avgerror | -//+------------------------------------------------------------------+ -void CMLPCVReportShell::SetAvgError(const double d) - { -//--- change value - m_innerobj.m_avgerror=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable avgrelerror | -//+------------------------------------------------------------------+ -double CMLPCVReportShell::GetAvgRelError(void) - { -//--- return result - return(m_innerobj.m_avgrelerror); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable avgrelerror | -//+------------------------------------------------------------------+ -void CMLPCVReportShell::SetAvgRelError(const double d) - { -//--- change value - m_innerobj.m_avgrelerror=d; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CMLPCVReport *CMLPCVReportShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Training neural networks | -//+------------------------------------------------------------------+ -class CMLPTrain - { -private: - //--- private methods - static void MLPKFoldCVGeneral(CMultilayerPerceptron &n,CMatrixDouble &xy,const int npoints,const double decay,const int restarts,const int foldscount,const bool lmalgorithm,const double wstep,const int maxits,int &info,CMLPReport &rep,CMLPCVReport &cvrep); - static void MLPKFoldSplit(CMatrixDouble &xy,const int npoints,const int nclasses,const int foldscount,const bool stratifiedsplits,int &folds[]); -public: - //--- constant - static const double m_mindecay; - //--- constructor, destructor - CMLPTrain(void); - ~CMLPTrain(void); - //--- public methods - static void MLPTrainLM(CMultilayerPerceptron &network,CMatrixDouble &xy,const int npoints,double decay,const int restarts,int &info,CMLPReport &rep); - static void MLPTrainLBFGS(CMultilayerPerceptron &network,CMatrixDouble &xy,const int npoints,double decay,const int restarts,const double wstep,int maxits,int &info,CMLPReport &rep); - static void MLPTrainES(CMultilayerPerceptron &network,CMatrixDouble &trnxy,const int trnsize,CMatrixDouble &valxy,const int valsize,const double decay,const int restarts,int &info,CMLPReport &rep); - static void MLPKFoldCVLBFGS(CMultilayerPerceptron &network,CMatrixDouble &xy,const int npoints,const double decay,const int restarts,const double wstep,const int maxits,const int foldscount,int &info,CMLPReport &rep,CMLPCVReport &cvrep); - static void MLPKFoldCVLM(CMultilayerPerceptron &network,CMatrixDouble &xy,const int npoints,const double decay,const int restarts,int foldscount,int &info,CMLPReport &rep,CMLPCVReport &cvrep); - }; -//+------------------------------------------------------------------+ -//| Initialize constant | -//+------------------------------------------------------------------+ -const double CMLPTrain::m_mindecay=0.001; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMLPTrain::CMLPTrain(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMLPTrain::~CMLPTrain(void) - { - - } -//+------------------------------------------------------------------+ -//| Neural network training using modified Levenberg-Marquardt with | -//| exact Hessian calculation and regularization. Subroutine trains | -//| neural network with restarts from random positions. Algorithm is | -//| well suited for small | -//| and medium scale problems (hundreds of weights). | -//| INPUT PARAMETERS: | -//| Network - neural network with initialized geometry | -//| XY - training set | -//| NPoints - training set size | -//| Decay - weight decay constant, >=0.001 | -//| Decay term 'Decay*||Weights||^2' is added to | -//| error function. | -//| If you don't know what Decay to choose, use | -//| 0.001. | -//| Restarts - number of restarts from random position, >0. | -//| If you don't know what Restarts to choose, | -//| use 2. | -//| OUTPUT PARAMETERS: | -//| Network - trained neural network. | -//| Info - return code: | -//| * -9, if internal matrix inverse subroutine | -//| failed | -//| * -2, if there is a point with class number | -//| outside of [0..NOut-1]. | -//| * -1, if wrong parameters specified | -//| (NPoints<0, Restarts<1). | -//| * 2, if task has been solved. | -//| Rep - training report | -//+------------------------------------------------------------------+ -static void CMLPTrain::MLPTrainLM(CMultilayerPerceptron &network,CMatrixDouble &xy, - const int npoints,double decay,const int restarts, - int &info,CMLPReport &rep) - { -//--- create variables - int nin=0; - int nout=0; - int wcount=0; - double lmm_ftol=0; - double lmsteptol=0; - int i=0; - int k=0; - double v=0; - double e=0; - double enew=0; - double xnorm2=0; - double stepnorm=0; - bool spd; - double nu=0; - double lambdav=0; - double lambdaup=0; - double lambdadown=0; - int pass=0; - double ebest=0; - int invinfo=0; - int solverinfo=0; - int i_=0; -//--- creating arrays - double g[]; - double d[]; - double x[]; - double y[]; - double wbase[]; - double wdir[]; - double wt[]; - double wx[]; - double wbest[]; -//--- create matrix - CMatrixDouble h; - CMatrixDouble hmod; - CMatrixDouble z; -//--- objects of classes - CMinLBFGSReport internalrep; - CMinLBFGSState state; - CMatInvReport invrep; - CDenseSolverReport solverrep; -//--- initialization - info=0; -//--- function call - CMLPBase::MLPProperties(network,nin,nout,wcount); -//--- initialization - lambdaup=10; - lambdadown=0.3; - lmm_ftol=0.001; - lmsteptol=0.001; -//--- Test for inputs - if(npoints<=0 || restarts<1) - { - info=-1; - return; - } -//--- check - if(CMLPBase::MLPIsSoftMax(network)) - { - for(i=0;i<=npoints-1;i++) - { - //--- check - if((int)MathRound(xy[i][nin])<0 || (int)MathRound(xy[i][nin])>=nout) - { - info=-2; - return; - } - } - } -//--- change values - decay=MathMax(decay,m_mindecay); - info=2; -//--- Initialize data - rep.m_ngrad=0; - rep.m_nhess=0; - rep.m_ncholesky=0; -//--- General case. -//--- Prepare task and network. Allocate space. - CMLPBase::MLPInitPreprocessor(network,xy,npoints); -//--- allocation - ArrayResizeAL(g,wcount); - h.Resize(wcount,wcount); - hmod.Resize(wcount,wcount); - ArrayResizeAL(wbase,wcount); - ArrayResizeAL(wdir,wcount); - ArrayResizeAL(wbest,wcount); - ArrayResizeAL(wt,wcount); - ArrayResizeAL(wx,wcount); -//--- initialization - ebest=CMath::m_maxrealnumber; -//--- Multiple passes - for(pass=1;pass<=restarts;pass++) - { - //--- Initialize weights - CMLPBase::MLPRandomize(network); - //--- First stage of the hybrid algorithm: LBFGS - for(i_=0;i_<=wcount-1;i_++) - wbase[i_]=network.m_weights[i_]; - //--- function calls - CMinLBFGS::MinLBFGSCreate(wcount,(int)(MathMin(wcount,5)),wbase,state); - CMinLBFGS::MinLBFGSSetCond(state,0,0,0,(int)(MathMax(25,wcount))); - while(CMinLBFGS::MinLBFGSIteration(state)) - { - //--- gradient - for(i_=0;i_<=wcount-1;i_++) - network.m_weights[i_]=state.m_x[i_]; - //--- function call - CMLPBase::MLPGradBatch(network,xy,npoints,state.m_f,state.m_g); - //--- weight decay - v=0.0; - for(i_=0;i_<=wcount-1;i_++) - v+=network.m_weights[i_]*network.m_weights[i_]; - state.m_f=state.m_f+0.5*decay*v; - for(i_=0;i_<=wcount-1;i_++) - state.m_g[i_]=state.m_g[i_]+decay*network.m_weights[i_]; - //--- next iteration - rep.m_ngrad=rep.m_ngrad+1; - } - //--- function call - CMinLBFGS::MinLBFGSResults(state,wbase,internalrep); - for(i_=0;i_<=wcount-1;i_++) - network.m_weights[i_]=wbase[i_]; - //--- Second stage of the hybrid algorithm: LM - //--- Initialize H with identity matrix, - //--- G with gradient, - //--- E with regularized error. - CMLPBase::MLPHessianBatch(network,xy,npoints,e,g,h); - v=0.0; - for(i_=0;i_<=wcount-1;i_++) - v+=network.m_weights[i_]*network.m_weights[i_]; - //--- change values - e=e+0.5*decay*v; - for(i_=0;i_<=wcount-1;i_++) - g[i_]=g[i_]+decay*network.m_weights[i_]; - for(k=0;k<=wcount-1;k++) - h[k].Set(k,h[k][k]+decay); - //--- change values - rep.m_nhess=rep.m_nhess+1; - lambdav=0.001; - nu=2; - //--- cycle - while(true) - { - //--- 1. HMod=H+lambda*I - //--- 2. Try to solve (H+Lambda*I)*dx=-g. - //--- Increase lambda if left part is not positive definite. - for(i=0;i<=wcount-1;i++) - { - for(i_=0;i_<=wcount-1;i_++) - hmod[i].Set(i_,h[i][i_]); - hmod[i].Set(i,hmod[i][i]+lambdav); - } - //--- function call - spd=CTrFac::SPDMatrixCholesky(hmod,wcount,true); - rep.m_ncholesky=rep.m_ncholesky+1; - //--- check - if(!spd) - { - lambdav=lambdav*lambdaup*nu; - nu=nu*2; - continue; - } - //--- function call - CDenseSolver::SPDMatrixCholeskySolve(hmod,wcount,true,g,solverinfo,solverrep,wdir); - //--- check - if(solverinfo<0) - { - lambdav=lambdav*lambdaup*nu; - nu=nu*2; - continue; - } - for(i_=0;i_<=wcount-1;i_++) - wdir[i_]=-1*wdir[i_]; - //--- Lambda found. - //--- 1. Save old w in WBase - //--- 1. Test some stopping criterions - //--- 2. If error(w+wdir)>error(w),increase lambda - for(i_=0;i_<=wcount-1;i_++) - network.m_weights[i_]=network.m_weights[i_]+wdir[i_]; - xnorm2=0.0; - for(i_=0;i_<=wcount-1;i_++) - xnorm2+=network.m_weights[i_]*network.m_weights[i_]; - //--- change value - stepnorm=0.0; - for(i_=0;i_<=wcount-1;i_++) - stepnorm+=wdir[i_]*wdir[i_]; - stepnorm=MathSqrt(stepnorm); - //--- function call - enew=CMLPBase::MLPError(network,xy,npoints)+0.5*decay*xnorm2; - //--- check - if(stepnorme) - { - lambdav=lambdav*lambdaup*nu; - nu=nu*2; - continue; - } - //--- Optimize using inv(cholesky(H)) as preconditioner - CMatInv::RMatrixTrInverse(hmod,wcount,true,false,invinfo,invrep); - //--- check - if(invinfo<=0) - { - //--- if matrix can't be inverted then exit with errors - //--- TODO: make WCount steps in direction suggested by HMod - info=-9; - return; - } - //--- calculation - for(i_=0;i_<=wcount-1;i_++) - wbase[i_]=network.m_weights[i_]; - for(i=0;i<=wcount-1;i++) - wt[i]=0; - //--- function calls - CMinLBFGS::MinLBFGSCreateX(wcount,wcount,wt,1,0.0,state); - CMinLBFGS::MinLBFGSSetCond(state,0,0,0,5); - while(CMinLBFGS::MinLBFGSIteration(state)) - { - //--- gradient - for(i=0;i<=wcount-1;i++) - { - v=0.0; - for(i_=i;i_<=wcount-1;i_++) - v+=state.m_x[i_]*hmod[i][i_]; - network.m_weights[i]=wbase[i]+v; - } - //--- function call - CMLPBase::MLPGradBatch(network,xy,npoints,state.m_f,g); - for(i=0;i<=wcount-1;i++) - state.m_g[i]=0; - for(i=0;i<=wcount-1;i++) - { - v=g[i]; - for(i_=i;i_<=wcount-1;i_++) - state.m_g[i_]=state.m_g[i_]+v*hmod[i][i_]; - } - //--- weight decay - //--- grad(x'*x)=A'*(x0+A*t) - v=0.0; - for(i_=0;i_<=wcount-1;i_++) - v+=network.m_weights[i_]*network.m_weights[i_]; - state.m_f=state.m_f+0.5*decay*v; - for(i=0;i<=wcount-1;i++) - { - v=decay*network.m_weights[i]; - for(i_=i;i_<=wcount-1;i_++) - state.m_g[i_]=state.m_g[i_]+v*hmod[i][i_]; - } - //--- next iteration - rep.m_ngrad=rep.m_ngrad+1; - } - //--- function call - CMinLBFGS::MinLBFGSResults(state,wt,internalrep); - //--- Accept new position. - //--- Calculate Hessian - for(i=0;i<=wcount-1;i++) - { - v=0.0; - for(i_=i;i_<=wcount-1;i_++) - v+=wt[i_]*hmod[i][i_]; - network.m_weights[i]=wbase[i]+v; - } - //--- function call - CMLPBase::MLPHessianBatch(network,xy,npoints,e,g,h); - v=0.0; - for(i_=0;i_<=wcount-1;i_++) - v+=network.m_weights[i_]*network.m_weights[i_]; - //--- change value - e=e+0.5*decay*v; - for(i_=0;i_<=wcount-1;i_++) - g[i_]=g[i_]+decay*network.m_weights[i_]; - for(k=0;k<=wcount-1;k++) - h[k].Set(k,h[k][k]+decay); - rep.m_nhess=rep.m_nhess+1; - //--- Update lambda - lambdav=lambdav*lambdadown; - nu=2; - } - //--- update WBest - v=0.0; - for(i_=0;i_<=wcount-1;i_++) - v+=network.m_weights[i_]*network.m_weights[i_]; - //--- change value - e=0.5*decay*v+CMLPBase::MLPError(network,xy,npoints); - //--- check - if(e=0.001 | -//| Decay term 'Decay*||Weights||^2' is added to | -//| error function. | -//| If you don't know what Decay to choose, use | -//| 0.001. | -//| Restarts - number of restarts from random position, >0. | -//| If you don't know what Restarts to choose, | -//| use 2. | -//| WStep - stopping criterion. Algorithm stops if step | -//| size is less than WStep. Recommended | -//| value - 0.01. Zero step size means stopping | -//| after MaxIts iterations. | -//| MaxIts - stopping criterion. Algorithm stops after | -//| MaxIts iterations (NOT gradient calculations).| -//| Zero MaxIts means stopping when step is | -//| sufficiently small. | -//| OUTPUT PARAMETERS: | -//| Network - trained neural network. | -//| Info - return code: | -//| * -8, if both WStep=0 and MaxIts=0 | -//| * -2, if there is a point with class number | -//| outside of [0..NOut-1]. | -//| * -1, if wrong parameters specified | -//| (NPoints<0, Restarts<1). | -//| * 2, if task has been solved. | -//| Rep - training report | -//+------------------------------------------------------------------+ -static void CMLPTrain::MLPTrainLBFGS(CMultilayerPerceptron &network, - CMatrixDouble &xy,const int npoints, - double decay,const int restarts, - const double wstep,int maxits, - int &info,CMLPReport &rep) - { -//--- create variables - int i=0; - int pass=0; - int nin=0; - int nout=0; - int wcount=0; - double e=0; - double v=0; - double ebest=0; -//--- creating arrays - double w[]; - double wbest[]; -//--- create objects of classes - CMinLBFGSReport internalrep; - CMinLBFGSState state; - int i_=0; -//--- initialization - info=0; -//--- Test inputs,parse flags,read network geometry - if(wstep==0.0 && maxits==0) - { - info=-8; - return; - } -//--- check - if(((npoints<=0 || restarts<1) || wstep<0.0) || maxits<0) - { - info=-1; - return; - } -//--- function call - CMLPBase::MLPProperties(network,nin,nout,wcount); -//--- check - if(CMLPBase::MLPIsSoftMax(network)) - { - for(i=0;i<=npoints-1;i++) - { - //--- check - if((int)MathRound(xy[i][nin])<0 || (int)MathRound(xy[i][nin])>=nout) - { - info=-2; - return; - } - } - } -//--- change values - decay=MathMax(decay,m_mindecay); - info=2; -//--- Prepare - CMLPBase::MLPInitPreprocessor(network,xy,npoints); -//--- allocation - ArrayResizeAL(w,wcount); - ArrayResizeAL(wbest,wcount); -//--- initialization - ebest=CMath::m_maxrealnumber; -//--- Multiple starts - rep.m_ncholesky=0; - rep.m_nhess=0; - rep.m_ngrad=0; - for(pass=1;pass<=restarts;pass++) - { - //--- Process - CMLPBase::MLPRandomize(network); - for(i_=0;i_<=wcount-1;i_++) - w[i_]=network.m_weights[i_]; - //--- function calls - CMinLBFGS::MinLBFGSCreate(wcount,(int)(MathMin(wcount,10)),w,state); - CMinLBFGS::MinLBFGSSetCond(state,0.0,0.0,wstep,maxits); - while(CMinLBFGS::MinLBFGSIteration(state)) - { - for(i_=0;i_<=wcount-1;i_++) - network.m_weights[i_]=state.m_x[i_]; - //--- function call - CMLPBase::MLPGradNBatch(network,xy,npoints,state.m_f,state.m_g); - v=0.0; - for(i_=0;i_<=wcount-1;i_++) - v+=network.m_weights[i_]*network.m_weights[i_]; - state.m_f=state.m_f+0.5*decay*v; - for(i_=0;i_<=wcount-1;i_++) - state.m_g[i_]=state.m_g[i_]+decay*network.m_weights[i_]; - rep.m_ngrad=rep.m_ngrad+1; - } - //--- function call - CMinLBFGS::MinLBFGSResults(state,w,internalrep); - for(i_=0;i_<=wcount-1;i_++) - network.m_weights[i_]=w[i_]; - //--- Compare with best - v=0.0; - for(i_=0;i_<=wcount-1;i_++) - v+=network.m_weights[i_]*network.m_weights[i_]; - //--- change value - e=CMLPBase::MLPErrorN(network,xy,npoints)+0.5*decay*v; - //--- check - if(e=0.001 | -//| Decay term 'Decay*||Weights||^2' is added to | -//| error function. | -//| If you don't know what Decay to choose, use | -//| 0.001. | -//| Restarts - number of restarts from random position, >0. | -//| If you don't know what Restarts to choose, | -//| use 2. | -//| OUTPUT PARAMETERS: | -//| Network - trained neural network. | -//| Info - return code: | -//| * -2, if there is a point with class number | -//| outside of [0..NOut-1]. | -//| * -1, if wrong parameters specified | -//| (NPoints<0, Restarts<1, ...). | -//| * 2, task has been solved, stopping | -//| criterion met - sufficiently small | -//| step size. Not expected (we use EARLY | -//| stopping) but possible and not an error| -//| * 6, task has been solved, stopping | -//| criterion met - increasing of | -//| validation set error. | -//| Rep - training report | -//| NOTE: | -//| Algorithm stops if validation set error increases for a long | -//| enough or step size is small enought (there are task where | -//| validation set may decrease for eternity). In any case solution | -//| returned corresponds to the minimum of validation set error. | -//+------------------------------------------------------------------+ -static void CMLPTrain::MLPTrainES(CMultilayerPerceptron &network, - CMatrixDouble &trnxy,const int trnsize, - CMatrixDouble &valxy,const int valsize, - const double decay,const int restarts, - int &info,CMLPReport &rep) - { -//--- create variables - int i=0; - int pass=0; - int nin=0; - int nout=0; - int wcount=0; - double e=0; - double v=0; - double ebest=0; - int itbest=0; - double wstep=0; - int i_=0; -//--- creating arrays - double w[]; - double wbest[]; - double wfinal[]; - double efinal=0; -//--- objects of classes - CMinLBFGSReport internalrep; - CMinLBFGSState state; -//--- initialization - info=0; - wstep=0.001; -//--- Test inputs,parse flags,read network geometry - if(((trnsize<=0 || valsize<=0) || restarts<1) || decay<0.0) - { - info=-1; - return; - } -//--- function call - CMLPBase::MLPProperties(network,nin,nout,wcount); -//--- check - if(CMLPBase::MLPIsSoftMax(network)) - { - for(i=0;i<=trnsize-1;i++) - { - //--- check - if((int)MathRound(trnxy[i][nin])<0 || (int)MathRound(trnxy[i][nin])>=nout) - { - info=-2; - return; - } - } - for(i=0;i<=valsize-1;i++) - { - //--- check - if((int)MathRound(valxy[i][nin])<0 || (int)MathRound(valxy[i][nin])>=nout) - { - info=-2; - return; - } - } - } -//--- change value - info=2; -//--- Prepare - CMLPBase::MLPInitPreprocessor(network,trnxy,trnsize); -//--- allocation - ArrayResizeAL(w,wcount); - ArrayResizeAL(wbest,wcount); - ArrayResizeAL(wfinal,wcount); -//--- initialization - efinal=CMath::m_maxrealnumber; - for(i=0;i<=wcount-1;i++) - wfinal[i]=0; -//--- Multiple starts - rep.m_ncholesky=0; - rep.m_nhess=0; - rep.m_ngrad=0; -//--- calculation - for(pass=1;pass<=restarts;pass++) - { - //--- Process - CMLPBase::MLPRandomize(network); - //--- change values - ebest=CMLPBase::MLPError(network,valxy,valsize); - for(i_=0;i_<=wcount-1;i_++) - wbest[i_]=network.m_weights[i_]; - //--- change values - itbest=0; - for(i_=0;i_<=wcount-1;i_++) - w[i_]=network.m_weights[i_]; - //--- function calls - CMinLBFGS::MinLBFGSCreate(wcount,(int)(MathMin(wcount,10)),w,state); - CMinLBFGS::MinLBFGSSetCond(state,0.0,0.0,wstep,0); - CMinLBFGS::MinLBFGSSetXRep(state,true); - while(CMinLBFGS::MinLBFGSIteration(state)) - { - //--- Calculate gradient - for(i_=0;i_<=wcount-1;i_++) - network.m_weights[i_]=state.m_x[i_]; - //--- function call - CMLPBase::MLPGradNBatch(network,trnxy,trnsize,state.m_f,state.m_g); - v=0.0; - for(i_=0;i_<=wcount-1;i_++) - v+=network.m_weights[i_]*network.m_weights[i_]; - state.m_f=state.m_f+0.5*decay*v; - for(i_=0;i_<=wcount-1;i_++) - state.m_g[i_]=state.m_g[i_]+decay*network.m_weights[i_]; - rep.m_ngrad=rep.m_ngrad+1; - //--- Validation set - if(state.m_xupdated) - { - for(i_=0;i_<=wcount-1;i_++) - network.m_weights[i_]=w[i_]; - //--- function call - e=CMLPBase::MLPError(network,valxy,valsize); - //--- check - if(e30 && (double)(internalrep.m_iterationscount)>(double)(1.5*itbest)) - { - info=6; - break; - } - } - } - //--- function call - CMinLBFGS::MinLBFGSResults(state,w,internalrep); - //--- Compare with final answer - if(ebest0. | -//| restarts are counted for each partition | -//| separately, so total number of restarts will | -//| be Restarts*FoldsCount. | -//| WStep - stopping criterion, same as in MLPTrainLBFGS | -//| MaxIts - stopping criterion, same as in MLPTrainLBFGS | -//| FoldsCount - number of folds in k-fold cross-validation, | -//| 2<=FoldsCount<=SSize. | -//| recommended value: 10. | -//| OUTPUT PARAMETERS: | -//| Info - return code, same as in MLPTrainLBFGS | -//| Rep - report, same as in MLPTrainLM/MLPTrainLBFGS | -//| CVRep - generalization error estimates | -//+------------------------------------------------------------------+ -static void CMLPTrain::MLPKFoldCVLBFGS(CMultilayerPerceptron &network, - CMatrixDouble &xy,const int npoints, - const double decay,const int restarts, - const double wstep,const int maxits, - const int foldscount,int &info, - CMLPReport &rep,CMLPCVReport &cvrep) - { -//--- initialization - info=0; -//--- function call - MLPKFoldCVGeneral(network,xy,npoints,decay,restarts,foldscount,false,wstep,maxits,info,rep,cvrep); - } -//+------------------------------------------------------------------+ -//| Cross-validation estimate of generalization error. | -//| Base algorithm - Levenberg-Marquardt. | -//| INPUT PARAMETERS: | -//| Network - neural network with initialized geometry. | -//| Network is not changed during | -//| cross-validation - it is used only as a | -//| representative of its architecture. | -//| XY - training set. | -//| SSize - training set size | -//| Decay - weight decay, same as in MLPTrainLBFGS | -//| Restarts - number of restarts, >0. | -//| restarts are counted for each partition | -//| separately, so total number of restarts will | -//| be Restarts*FoldsCount. | -//| FoldsCount - number of folds in k-fold cross-validation, | -//| 2<=FoldsCount<=SSize. | -//| recommended value: 10. | -//| OUTPUT PARAMETERS: | -//| Info - return code, same as in MLPTrainLBFGS | -//| Rep - report, same as in MLPTrainLM/MLPTrainLBFGS | -//| CVRep - generalization error estimates | -//+------------------------------------------------------------------+ -static void CMLPTrain::MLPKFoldCVLM(CMultilayerPerceptron &network, - CMatrixDouble &xy,const int npoints, - const double decay,const int restarts, - int foldscount,int &info,CMLPReport &rep, - CMLPCVReport &cvrep) - { -//--- initialization - info=0; -//--- function call - MLPKFoldCVGeneral(network,xy,npoints,decay,restarts,foldscount,true,0.0,0,info,rep,cvrep); - } -//+------------------------------------------------------------------+ -//| Internal cross-validation subroutine | -//+------------------------------------------------------------------+ -static void CMLPTrain::MLPKFoldCVGeneral(CMultilayerPerceptron &n, - CMatrixDouble &xy,const int npoints, - const double decay,const int restarts, - const int foldscount,const bool lmalgorithm, - const double wstep,const int maxits, - int &info,CMLPReport &rep, - CMLPCVReport &cvrep) - { -//--- create variables - int i=0; - int fold=0; - int j=0; - int k=0; - int nin=0; - int nout=0; - int rowlen=0; - int wcount=0; - int nclasses=0; - int tssize=0; - int cvssize=0; - int relcnt=0; - int i_=0; -//--- creating arrays - int folds[]; - double x[]; - double y[]; -//--- create matrix - CMatrixDouble cvset; - CMatrixDouble testset; -//--- creating arrays - CMultilayerPerceptron network; - CMLPReport internalrep; -//--- initialization - info=0; -//--- Read network geometry,test parameters - CMLPBase::MLPProperties(n,nin,nout,wcount); -//--- check - if(CMLPBase::MLPIsSoftMax(n)) - { - nclasses=nout; - rowlen=nin+1; - } - else - { - nclasses=-nout; - rowlen=nin+nout; - } -//--- check - if((npoints<=0 || foldscount<2) || foldscount>npoints) - { - info=-1; - return; - } -//--- function call - CMLPBase::MLPCopy(n,network); -//--- K-fold out cross-validation. -//--- First,estimate generalization error - testset.Resize(npoints,rowlen); - cvset.Resize(npoints,rowlen); - ArrayResizeAL(x,nin); - ArrayResizeAL(y,nout); -//--- function call - MLPKFoldSplit(xy,npoints,nclasses,foldscount,false,folds); -//--- change values - cvrep.m_relclserror=0; - cvrep.m_avgce=0; - cvrep.m_rmserror=0; - cvrep.m_avgerror=0; - cvrep.m_avgrelerror=0; - rep.m_ngrad=0; - rep.m_nhess=0; - rep.m_ncholesky=0; - relcnt=0; -//--- calculation - for(fold=0;fold<=foldscount-1;fold++) - { - //--- Separate set - tssize=0; - cvssize=0; - for(i=0;i<=npoints-1;i++) - { - //--- check - if(folds[i]==fold) - { - for(i_=0;i_<=rowlen-1;i_++) - testset[tssize].Set(i_,xy[i][i_]); - tssize=tssize+1; - } - else - { - for(i_=0;i_<=rowlen-1;i_++) - cvset[cvssize].Set(i_,xy[i][i_]); - cvssize=cvssize+1; - } - } - //--- Train on CV training set - if(lmalgorithm) - MLPTrainLM(network,cvset,cvssize,decay,restarts,info,internalrep); - else - MLPTrainLBFGS(network,cvset,cvssize,decay,restarts,wstep,maxits,info,internalrep); - //--- check - if(info<0) - { - //--- change values - cvrep.m_relclserror=0; - cvrep.m_avgce=0; - cvrep.m_rmserror=0; - cvrep.m_avgerror=0; - cvrep.m_avgrelerror=0; - //--- exit the function - return; - } - //--- change values - rep.m_ngrad=rep.m_ngrad+internalrep.m_ngrad; - rep.m_nhess=rep.m_nhess+internalrep.m_nhess; - rep.m_ncholesky=rep.m_ncholesky+internalrep.m_ncholesky; - //--- Estimate error using CV test set - if(CMLPBase::MLPIsSoftMax(network)) - { - //--- classification-only code - cvrep.m_relclserror=cvrep.m_relclserror+CMLPBase::MLPClsError(network,testset,tssize); - cvrep.m_avgce=cvrep.m_avgce+CMLPBase::MLPErrorN(network,testset,tssize); - } - //--- calculation - for(i=0;i<=tssize-1;i++) - { - for(i_=0;i_<=nin-1;i_++) - x[i_]=testset[i][i_]; - //--- function call - CMLPBase::MLPProcess(network,x,y); - //--- check - if(CMLPBase::MLPIsSoftMax(network)) - { - //--- Classification-specific code - k=(int)MathRound(testset[i][nin]); - for(j=0;j<=nout-1;j++) - { - //--- check - if(j==k) - { - //--- change values - cvrep.m_rmserror=cvrep.m_rmserror+CMath::Sqr(y[j]-1); - cvrep.m_avgerror=cvrep.m_avgerror+MathAbs(y[j]-1); - cvrep.m_avgrelerror=cvrep.m_avgrelerror+MathAbs(y[j]-1); - relcnt=relcnt+1; - } - else - { - //--- change values - cvrep.m_rmserror=cvrep.m_rmserror+CMath::Sqr(y[j]); - cvrep.m_avgerror=cvrep.m_avgerror+MathAbs(y[j]); - } - } - } - else - { - //--- Regression-specific code - for(j=0;j<=nout-1;j++) - { - cvrep.m_rmserror=cvrep.m_rmserror+CMath::Sqr(y[j]-testset[i][nin+j]); - cvrep.m_avgerror=cvrep.m_avgerror+MathAbs(y[j]-testset[i][nin+j]); - //--- check - if(testset[i][nin+j]!=0.0) - { - cvrep.m_avgrelerror=cvrep.m_avgrelerror+MathAbs((y[j]-testset[i][nin+j])/testset[i][nin+j]); - relcnt=relcnt+1; - } - } - } - } - } -//--- check - if(CMLPBase::MLPIsSoftMax(network)) - { - cvrep.m_relclserror=cvrep.m_relclserror/npoints; - cvrep.m_avgce=cvrep.m_avgce/(MathLog(2)*npoints); - } -//--- change values - cvrep.m_rmserror=MathSqrt(cvrep.m_rmserror/(npoints*nout)); - cvrep.m_avgerror=cvrep.m_avgerror/(npoints*nout); - cvrep.m_avgrelerror=cvrep.m_avgrelerror/relcnt; - info=1; - } -//+------------------------------------------------------------------+ -//| Subroutine prepares K-fold split of the training set. | -//| NOTES: | -//| "NClasses>0" means that we have classification task. | -//| "NClasses<0" means regression task with -NClasses real | -//| outputs. | -//+------------------------------------------------------------------+ -static void CMLPTrain::MLPKFoldSplit(CMatrixDouble &xy,const int npoints, - const int nclasses,const int foldscount, - const bool stratifiedsplits,int &folds[]) - { -//--- create variables - int i=0; - int j=0; - int k=0; -//--- test parameters - if(!CAp::Assert(npoints>0,__FUNCTION__+": wrong NPoints!")) - return; -//--- check - if(!CAp::Assert(nclasses>1 || nclasses<0,__FUNCTION__+": wrong NClasses!")) - return; -//--- check - if(!CAp::Assert(foldscount>=2 && foldscount<=npoints,__FUNCTION__+" wrong FoldsCount!")) - return; -//--- check - if(!CAp::Assert(!stratifiedsplits,__FUNCTION__+": stratified splits are not supported!")) - return; -//--- Folds - ArrayResizeAL(folds,npoints); - for(i=0;i<=npoints-1;i++) - folds[i]=i*foldscount/npoints; -//--- calculation - for(i=0;i<=npoints-2;i++) - { - j=i+CMath::RandomInteger(npoints-i); - //--- check - if(j!=i) - { - k=folds[i]; - folds[i]=folds[j]; - folds[j]=k; - } - } - } -//+------------------------------------------------------------------+ -//| Neural networks ensemble | -//+------------------------------------------------------------------+ -class CMLPEnsemble - { -public: - //--- variables - int m_ensemblesize; - int m_nin; - int m_nout; - int m_wcount; - bool m_issoftmax; - bool m_postprocessing; - int m_serializedlen; - //--- arrays - int m_structinfo[]; - double m_weights[]; - double m_columnmeans[]; - double m_columnsigmas[]; - double m_serializedmlp[]; - double m_tmpweights[]; - double m_tmpmeans[]; - double m_tmpsigmas[]; - double m_neurons[]; - double m_dfdnet[]; - double m_y[]; - //--- constructor, destructor - CMLPEnsemble(void); - ~CMLPEnsemble(void); - //--- copy - void Copy(CMLPEnsemble &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMLPEnsemble::CMLPEnsemble(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMLPEnsemble::~CMLPEnsemble(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CMLPEnsemble::Copy(CMLPEnsemble &obj) - { -//--- copy variables - m_ensemblesize=obj.m_ensemblesize; - m_nin=obj.m_nin; - m_nout=obj.m_nout; - m_wcount=obj.m_wcount; - m_issoftmax=obj.m_issoftmax; - m_postprocessing=obj.m_postprocessing; - m_serializedlen=obj.m_serializedlen; -//--- copy arrays - ArrayCopy(m_structinfo,obj.m_structinfo); - ArrayCopy(m_weights,obj.m_weights); - ArrayCopy(m_columnmeans,obj.m_columnmeans); - ArrayCopy(m_columnsigmas,obj.m_columnsigmas); - ArrayCopy(m_serializedmlp,obj.m_serializedmlp); - ArrayCopy(m_tmpweights,obj.m_tmpweights); - ArrayCopy(m_tmpmeans,obj.m_tmpmeans); - ArrayCopy(m_tmpsigmas,obj.m_tmpsigmas); - ArrayCopy(m_neurons,obj.m_neurons); - ArrayCopy(m_dfdnet,obj.m_dfdnet); - ArrayCopy(m_y,obj.m_y); - } -//+------------------------------------------------------------------+ -//| Neural networks ensemble | -//+------------------------------------------------------------------+ -class CMLPEnsembleShell - { -private: - CMLPEnsemble m_innerobj; -public: - //--- constructors, destructor - CMLPEnsembleShell(void); - CMLPEnsembleShell(CMLPEnsemble &obj); - ~CMLPEnsembleShell(void); - //--- method - CMLPEnsemble *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMLPEnsembleShell::CMLPEnsembleShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CMLPEnsembleShell::CMLPEnsembleShell(CMLPEnsemble &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMLPEnsembleShell::~CMLPEnsembleShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CMLPEnsemble *CMLPEnsembleShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Neural networks ensemble | -//+------------------------------------------------------------------+ -class CMLPE - { -private: - //--- private methods - static void MLPEAllErrors(CMLPEnsemble &ensemble,CMatrixDouble &xy,const int npoints,double &relcls,double &avgce,double &rms,double &avg,double &avgrel); - static void MLPEBaggingInternal(CMLPEnsemble &ensemble,CMatrixDouble &xy,const int npoints,const double decay,const int restarts,const double wstep,const int maxits,const bool lmalgorithm,int &info,CMLPReport &rep,CMLPCVReport &ooberrors); -public: - //--- class constants - static const int m_mlpntotaloffset; - static const int m_mlpevnum; - //--- constructor, destructor - CMLPE(void); - ~CMLPE(void); - //--- public methods - static void MLPECreate0(const int nin,const int nout,const int ensemblesize,CMLPEnsemble &ensemble); - static void MLPECreate1(const int nin,const int nhid,const int nout,const int ensemblesize,CMLPEnsemble &ensemble); - static void MLPECreate2(const int nin,const int nhid1,const int nhid2,const int nout,const int ensemblesize,CMLPEnsemble &ensemble); - static void MLPECreateB0(const int nin,const int nout,const double b,const double d,const int ensemblesize,CMLPEnsemble &ensemble); - static void MLPECreateB1(const int nin,const int nhid,const int nout,const double b,const double d,const int ensemblesize,CMLPEnsemble &ensemble); - static void MLPECreateB2(const int nin,const int nhid1,const int nhid2,const int nout,const double b,const double d,const int ensemblesize,CMLPEnsemble &ensemble); - static void MLPECreateR0(const int nin,const int nout,const double a,const double b,const int ensemblesize,CMLPEnsemble &ensemble); - static void MLPECreateR1(const int nin,const int nhid,const int nout,const double a,const double b,const int ensemblesize,CMLPEnsemble &ensemble); - static void MLPECreateR2(const int nin,const int nhid1,const int nhid2,const int nout,const double a,const double b,const int ensemblesize,CMLPEnsemble &ensemble); - static void MLPECreateC0(const int nin,const int nout,const int ensemblesize,CMLPEnsemble &ensemble); - static void MLPECreateC1(const int nin,const int nhid,const int nout,const int ensemblesize,CMLPEnsemble &ensemble); - static void MLPECreateC2(const int nin,const int nhid1,const int nhid2,const int nout,const int ensemblesize,CMLPEnsemble &ensemble); - static void MLPECreateFromNetwork(CMultilayerPerceptron &network,const int ensemblesize,CMLPEnsemble &ensemble); - static void MLPECopy(CMLPEnsemble &ensemble1,CMLPEnsemble &ensemble2); - static void MLPESerialize(CMLPEnsemble &ensemble,double &ra[],int &rlen); - static void MLPEUnserialize(double &ra[],CMLPEnsemble &ensemble); - static void MLPERandomize(CMLPEnsemble &ensemble); - static void MLPEProperties(CMLPEnsemble &ensemble,int &nin,int &nout); - static bool MLPEIsSoftMax(CMLPEnsemble &ensemble); - static void MLPEProcess(CMLPEnsemble &ensemble,double &x[],double &y[]); - static void MLPEProcessI(CMLPEnsemble &ensemble,double &x[],double &y[]); - static double MLPERelClsError(CMLPEnsemble &ensemble,CMatrixDouble &xy,const int npoints); - static double MLPEAvgCE(CMLPEnsemble &ensemble,CMatrixDouble &xy,const int npoints); - static double MLPERMSError(CMLPEnsemble &ensemble,CMatrixDouble &xy,const int npoints); - static double MLPEAvgError(CMLPEnsemble &ensemble,CMatrixDouble &xy,const int npoints); - static double MLPEAvgRelError(CMLPEnsemble &ensemble,CMatrixDouble &xy,const int npoints); - static void MLPEBaggingLM(CMLPEnsemble &ensemble,CMatrixDouble &xy,const int npoints,const double decay,const int restarts,int &info,CMLPReport &rep,CMLPCVReport &ooberrors); - static void MLPEBaggingLBFGS(CMLPEnsemble &ensemble,CMatrixDouble &xy,const int npoints,const double decay,const int restarts,const double wstep,const int maxits,int &info,CMLPReport &rep,CMLPCVReport &ooberrors); - static void MLPETrainES(CMLPEnsemble &ensemble,CMatrixDouble &xy,const int npoints,const double decay,const int restarts,int &info,CMLPReport &rep); - }; -//+------------------------------------------------------------------+ -//| Initialize constants | -//+------------------------------------------------------------------+ -const int CMLPE::m_mlpntotaloffset=3; -const int CMLPE::m_mlpevnum=9; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMLPE::CMLPE(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMLPE::~CMLPE(void) - { - - } -//+------------------------------------------------------------------+ -//| Like MLPCreate0, but for ensembles. | -//+------------------------------------------------------------------+ -static void CMLPE::MLPECreate0(const int nin,const int nout,const int ensemblesize, - CMLPEnsemble &ensemble) - { -//--- object of class - CMultilayerPerceptron net; -//--- function call - CMLPBase::MLPCreate0(nin,nout,net); -//--- function call - MLPECreateFromNetwork(net,ensemblesize,ensemble); - } -//+------------------------------------------------------------------+ -//| Like MLPCreate1, but for ensembles. | -//+------------------------------------------------------------------+ -static void CMLPE::MLPECreate1(const int nin,const int nhid,const int nout, - const int ensemblesize,CMLPEnsemble &ensemble) - { -//--- object of class - CMultilayerPerceptron net; -//--- function call - CMLPBase::MLPCreate1(nin,nhid,nout,net); -//--- function call - MLPECreateFromNetwork(net,ensemblesize,ensemble); - } -//+------------------------------------------------------------------+ -//| Like MLPCreate2, but for ensembles. | -//+------------------------------------------------------------------+ -static void CMLPE::MLPECreate2(const int nin,const int nhid1,const int nhid2, - const int nout,const int ensemblesize, - CMLPEnsemble &ensemble) - { -//--- object of class - CMultilayerPerceptron net; -//--- function call - CMLPBase::MLPCreate2(nin,nhid1,nhid2,nout,net); -//--- function call - MLPECreateFromNetwork(net,ensemblesize,ensemble); - } -//+------------------------------------------------------------------+ -//| Like MLPCreateB0, but for ensembles. | -//+------------------------------------------------------------------+ -static void CMLPE::MLPECreateB0(const int nin,const int nout,const double b, - const double d,const int ensemblesize, - CMLPEnsemble &ensemble) - { -//--- object of class - CMultilayerPerceptron net; -//--- function call - CMLPBase::MLPCreateB0(nin,nout,b,d,net); -//--- function call - MLPECreateFromNetwork(net,ensemblesize,ensemble); - } -//+------------------------------------------------------------------+ -//| Like MLPCreateB1, but for ensembles. | -//+------------------------------------------------------------------+ -static void CMLPE::MLPECreateB1(const int nin,const int nhid,const int nout, - const double b,const double d,const int ensemblesize, - CMLPEnsemble &ensemble) - { -//--- object of class - CMultilayerPerceptron net; -//--- function call - CMLPBase::MLPCreateB1(nin,nhid,nout,b,d,net); -//--- function call - MLPECreateFromNetwork(net,ensemblesize,ensemble); - } -//+------------------------------------------------------------------+ -//| Like MLPCreateB2, but for ensembles. | -//+------------------------------------------------------------------+ -static void CMLPE::MLPECreateB2(const int nin,const int nhid1,const int nhid2, - const int nout,const double b,const double d, - const int ensemblesize,CMLPEnsemble &ensemble) - { -//--- object of class - CMultilayerPerceptron net; -//--- function call - CMLPBase::MLPCreateB2(nin,nhid1,nhid2,nout,b,d,net); -//--- function call - MLPECreateFromNetwork(net,ensemblesize,ensemble); - } -//+------------------------------------------------------------------+ -//| Like MLPCreateR0, but for ensembles. | -//+------------------------------------------------------------------+ -static void CMLPE::MLPECreateR0(const int nin,const int nout,const double a, - const double b,const int ensemblesize, - CMLPEnsemble &ensemble) - { -//--- object of class - CMultilayerPerceptron net; -//--- function call - CMLPBase::MLPCreateR0(nin,nout,a,b,net); -//--- function call - MLPECreateFromNetwork(net,ensemblesize,ensemble); - } -//+------------------------------------------------------------------+ -//| Like MLPCreateR1, but for ensembles. | -//+------------------------------------------------------------------+ -static void CMLPE::MLPECreateR1(const int nin,const int nhid,const int nout, - const double a,const double b, - const int ensemblesize,CMLPEnsemble &ensemble) - { -//--- object of class - CMultilayerPerceptron net; -//--- function call - CMLPBase::MLPCreateR1(nin,nhid,nout,a,b,net); -//--- function call - MLPECreateFromNetwork(net,ensemblesize,ensemble); - } -//+------------------------------------------------------------------+ -//| Like MLPCreateR2, but for ensembles. | -//+------------------------------------------------------------------+ -static void CMLPE::MLPECreateR2(const int nin,const int nhid1,const int nhid2, - const int nout,const double a,const double b, - const int ensemblesize,CMLPEnsemble &ensemble) - { -//--- object of class - CMultilayerPerceptron net; -//--- function call - CMLPBase::MLPCreateR2(nin,nhid1,nhid2,nout,a,b,net); -//--- function call - MLPECreateFromNetwork(net,ensemblesize,ensemble); - } -//+------------------------------------------------------------------+ -//| Like MLPCreateC0, but for ensembles. | -//+------------------------------------------------------------------+ -static void CMLPE::MLPECreateC0(const int nin,const int nout,const int ensemblesize, - CMLPEnsemble &ensemble) - { -//--- object of class - CMultilayerPerceptron net; -//--- function call - CMLPBase::MLPCreateC0(nin,nout,net); -//--- function call - MLPECreateFromNetwork(net,ensemblesize,ensemble); - } -//+------------------------------------------------------------------+ -//| Like MLPCreateC1, but for ensembles. | -//+------------------------------------------------------------------+ -static void CMLPE::MLPECreateC1(const int nin,const int nhid,const int nout, - const int ensemblesize,CMLPEnsemble &ensemble) - { -//--- object of class - CMultilayerPerceptron net; -//--- function call - CMLPBase::MLPCreateC1(nin,nhid,nout,net); -//--- function call - MLPECreateFromNetwork(net,ensemblesize,ensemble); - } -//+------------------------------------------------------------------+ -//| Like MLPCreateC2, but for ensembles. | -//+------------------------------------------------------------------+ -static void CMLPE::MLPECreateC2(const int nin,const int nhid1,const int nhid2, - const int nout,const int ensemblesize, - CMLPEnsemble &ensemble) - { -//--- object of class - CMultilayerPerceptron net; -//--- function call - CMLPBase::MLPCreateC2(nin,nhid1,nhid2,nout,net); -//--- function call - MLPECreateFromNetwork(net,ensemblesize,ensemble); - } -//+------------------------------------------------------------------+ -//| Creates ensemble from network. Only network geometry is copied. | -//+------------------------------------------------------------------+ -static void CMLPE::MLPECreateFromNetwork(CMultilayerPerceptron &network, - const int ensemblesize, - CMLPEnsemble &ensemble) - { -//--- create variables - int i=0; - int ccount=0; - int i_=0; - int i1_=0; -//--- check - if(!CAp::Assert(ensemblesize>0,__FUNCTION__+": incorrect ensemble size!")) - return; -//--- network properties - CMLPBase::MLPProperties(network,ensemble.m_nin,ensemble.m_nout,ensemble.m_wcount); -//--- check - if(CMLPBase::MLPIsSoftMax(network)) - ccount=ensemble.m_nin; - else - ccount=ensemble.m_nin+ensemble.m_nout; -//--- change values - ensemble.m_postprocessing=false; - ensemble.m_issoftmax=CMLPBase::MLPIsSoftMax(network); - ensemble.m_ensemblesize=ensemblesize; -//--- structure information - ArrayResizeAL(ensemble.m_structinfo,network.m_structinfo[0]); -//--- copy - for(i=0;i<=network.m_structinfo[0]-1;i++) - ensemble.m_structinfo[i]=network.m_structinfo[i]; -//--- weights,means,sigmas - ArrayResizeAL(ensemble.m_weights,ensemblesize*ensemble.m_wcount); - ArrayResizeAL(ensemble.m_columnmeans,ensemblesize*ccount); - ArrayResizeAL(ensemble.m_columnsigmas,ensemblesize*ccount); -//--- calculation - for(i=0;i<=ensemblesize*ensemble.m_wcount-1;i++) - ensemble.m_weights[i]=CMath::RandomReal()-0.5; -//--- calculation - for(i=0;i<=ensemblesize-1;i++) - { - i1_=-(i*ccount); - for(i_=i*ccount;i_<=(i+1)*ccount-1;i_++) - ensemble.m_columnmeans[i_]=network.m_columnmeans[i_+i1_]; - i1_=-(i*ccount); - for(i_=i*ccount;i_<=(i+1)*ccount-1;i_++) - ensemble.m_columnsigmas[i_]=network.m_columnsigmas[i_+i1_]; - } -//--- serialized part - CMLPBase::MLPSerializeOld(network,ensemble.m_serializedmlp,ensemble.m_serializedlen); -//--- temporaries,internal buffers - ArrayResizeAL(ensemble.m_tmpweights,ensemble.m_wcount); - ArrayResizeAL(ensemble.m_tmpmeans,ccount); - ArrayResizeAL(ensemble.m_tmpsigmas,ccount); - ArrayResizeAL(ensemble.m_neurons,ensemble.m_structinfo[m_mlpntotaloffset]); - ArrayResizeAL(ensemble.m_dfdnet,ensemble.m_structinfo[m_mlpntotaloffset]); - ArrayResizeAL(ensemble.m_y,ensemble.m_nout); - } -//+------------------------------------------------------------------+ -//| Copying of MLPEnsemble strucure | -//| INPUT PARAMETERS: | -//| Ensemble1 - original | -//| OUTPUT PARAMETERS: | -//| Ensemble2 - copy | -//+------------------------------------------------------------------+ -static void CMLPE::MLPECopy(CMLPEnsemble &ensemble1,CMLPEnsemble &ensemble2) - { -//--- create variables - int i=0; - int ssize=0; - int ccount=0; - int ntotal=0; - int i_=0; -//--- Unload info - ssize=ensemble1.m_structinfo[0]; -//--- check - if(ensemble1.m_issoftmax) - ccount=ensemble1.m_nin; - else - ccount=ensemble1.m_nin+ensemble1.m_nout; -//--- change value - ntotal=ensemble1.m_structinfo[m_mlpntotaloffset]; -//--- Allocate space - ArrayResizeAL(ensemble2.m_structinfo,ssize); - ArrayResizeAL(ensemble2.m_weights,ensemble1.m_ensemblesize*ensemble1.m_wcount); - ArrayResizeAL(ensemble2.m_columnmeans,ensemble1.m_ensemblesize*ccount); - ArrayResizeAL(ensemble2.m_columnsigmas,ensemble1.m_ensemblesize*ccount); - ArrayResizeAL(ensemble2.m_tmpweights,ensemble1.m_wcount); - ArrayResizeAL(ensemble2.m_tmpmeans,ccount); - ArrayResizeAL(ensemble2.m_tmpsigmas,ccount); - ArrayResizeAL(ensemble2.m_serializedmlp,ensemble1.m_serializedlen); - ArrayResizeAL(ensemble2.m_neurons,ntotal); - ArrayResizeAL(ensemble2.m_dfdnet,ntotal); - ArrayResizeAL(ensemble2.m_y,ensemble1.m_nout); -//--- Copy - ensemble2.m_nin=ensemble1.m_nin; - ensemble2.m_nout=ensemble1.m_nout; - ensemble2.m_wcount=ensemble1.m_wcount; - ensemble2.m_ensemblesize=ensemble1.m_ensemblesize; - ensemble2.m_issoftmax=ensemble1.m_issoftmax; - ensemble2.m_postprocessing=ensemble1.m_postprocessing; - ensemble2.m_serializedlen=ensemble1.m_serializedlen; -//--- copy - for(i=0;i<=ssize-1;i++) - ensemble2.m_structinfo[i]=ensemble1.m_structinfo[i]; - for(i_=0;i_<=ensemble1.m_ensemblesize*ensemble1.m_wcount-1;i_++) - ensemble2.m_weights[i_]=ensemble1.m_weights[i_]; - for(i_=0;i_<=ensemble1.m_ensemblesize*ccount-1;i_++) - ensemble2.m_columnmeans[i_]=ensemble1.m_columnmeans[i_]; - for(i_=0;i_<=ensemble1.m_ensemblesize*ccount-1;i_++) - ensemble2.m_columnsigmas[i_]=ensemble1.m_columnsigmas[i_]; - for(i_=0;i_<=ensemble1.m_serializedlen-1;i_++) - ensemble2.m_serializedmlp[i_]=ensemble1.m_serializedmlp[i_]; - } -//+------------------------------------------------------------------+ -//| Serialization of MLPEnsemble strucure | -//| INPUT PARAMETERS: | -//| Ensemble- original | -//| OUTPUT PARAMETERS: | -//| RA - array of real numbers which stores ensemble, | -//| array[0..RLen-1] | -//| RLen - RA lenght | -//+------------------------------------------------------------------+ -static void CMLPE::MLPESerialize(CMLPEnsemble &ensemble,double &ra[],int &rlen) - { -//--- create variables - int i=0; - int ssize=0; - int ntotal=0; - int ccount=0; - int hsize=0; - int offs=0; - int i_=0; - int i1_=0; -//--- initialization - rlen=0; - hsize=13; - ssize=ensemble.m_structinfo[0]; -//--- check - if(ensemble.m_issoftmax) - ccount=ensemble.m_nin; - else - ccount=ensemble.m_nin+ensemble.m_nout; -//--- change values - ntotal=ensemble.m_structinfo[m_mlpntotaloffset]; - rlen=hsize+ssize+ensemble.m_ensemblesize*ensemble.m_wcount+2*ccount*ensemble.m_ensemblesize+ensemble.m_serializedlen; -//--- RA format: -//--- [0] RLen -//--- [1] Version (MLPEVNum) -//--- [2] EnsembleSize -//--- [3] NIn -//--- [4] NOut -//--- [5] WCount -//--- [6] IsSoftmax 0/1 -//--- [7] PostProcessing 0/1 -//--- [8] sizeof(StructInfo) -//--- [9] NTotal (sizeof(Neurons),sizeof(DFDNET)) -//--- [10] CCount (sizeof(ColumnMeans),sizeof(ColumnSigmas)) -//--- [11] data offset -//--- [12] SerializedLen -//--- [..] StructInfo -//--- [..] Weights -//--- [..] ColumnMeans -//--- [..] ColumnSigmas - ArrayResizeAL(ra,rlen); -//--- change values - ra[0]=rlen; - ra[1]=m_mlpevnum; - ra[2]=ensemble.m_ensemblesize; - ra[3]=ensemble.m_nin; - ra[4]=ensemble.m_nout; - ra[5]=ensemble.m_wcount; -//--- check - if(ensemble.m_issoftmax) - ra[6]=1; - else - ra[6]=0; -//--- check - if(ensemble.m_postprocessing) - ra[7]=1; - else - ra[7]=9; -//--- change values - ra[8]=ssize; - ra[9]=ntotal; - ra[10]=ccount; - ra[11]=hsize; - ra[12]=ensemble.m_serializedlen; -//--- copy - offs=hsize; - for(i=offs;i<=offs+ssize-1;i++) - ra[i]=ensemble.m_structinfo[i-offs]; -//--- copy - offs=offs+ssize; - i1_=-offs; - for(i_=offs;i_<=offs+ensemble.m_ensemblesize*ensemble.m_wcount-1;i_++) - ra[i_]=ensemble.m_weights[i_+i1_]; -//--- copy - offs=offs+ensemble.m_ensemblesize*ensemble.m_wcount; - i1_=-offs; - for(i_=offs;i_<=offs+ensemble.m_ensemblesize*ccount-1;i_++) - ra[i_]=ensemble.m_columnmeans[i_+i1_]; -//--- copy - offs=offs+ensemble.m_ensemblesize*ccount; - i1_=-offs; - for(i_=offs;i_<=offs+ensemble.m_ensemblesize*ccount-1;i_++) - ra[i_]=ensemble.m_columnsigmas[i_+i1_]; -//--- copy - offs=offs+ensemble.m_ensemblesize*ccount; - i1_=-offs; - for(i_=offs;i_<=offs+ensemble.m_serializedlen-1;i_++) - ra[i_]=ensemble.m_serializedmlp[i_+i1_]; - offs=offs+ensemble.m_serializedlen; - } -//+------------------------------------------------------------------+ -//| Unserialization of MLPEnsemble strucure | -//| INPUT PARAMETERS: | -//| RA - real array which stores ensemble | -//| OUTPUT PARAMETERS: | -//| Ensemble- restored structure | -//+------------------------------------------------------------------+ -static void CMLPE::MLPEUnserialize(double &ra[],CMLPEnsemble &ensemble) - { -//--- create variables - int i=0; - int ssize=0; - int ntotal=0; - int ccount=0; - int hsize=0; - int offs=0; - int i_=0; - int i1_=0; -//--- check - if(!CAp::Assert((int)MathRound(ra[1])==m_mlpevnum,__FUNCTION__+": incorrect array!")) - return; -//--- load info - hsize=13; - ensemble.m_ensemblesize=(int)MathRound(ra[2]); - ensemble.m_nin=(int)MathRound(ra[3]); - ensemble.m_nout=(int)MathRound(ra[4]); - ensemble.m_wcount=(int)MathRound(ra[5]); - ensemble.m_issoftmax=(int)MathRound(ra[6])==1; - ensemble.m_postprocessing=(int)MathRound(ra[7])==1; - ssize=(int)MathRound(ra[8]); - ntotal=(int)MathRound(ra[9]); - ccount=(int)MathRound(ra[10]); - offs=(int)MathRound(ra[11]); - ensemble.m_serializedlen=(int)MathRound(ra[12]); -//--- Allocate arrays - ArrayResizeAL(ensemble.m_structinfo,ssize); - ArrayResizeAL(ensemble.m_weights,ensemble.m_ensemblesize*ensemble.m_wcount); - ArrayResizeAL(ensemble.m_columnmeans,ensemble.m_ensemblesize*ccount); - ArrayResizeAL(ensemble.m_columnsigmas,ensemble.m_ensemblesize*ccount); - ArrayResizeAL(ensemble.m_tmpweights,ensemble.m_wcount); - ArrayResizeAL(ensemble.m_tmpmeans,ccount); - ArrayResizeAL(ensemble.m_tmpsigmas,ccount); - ArrayResizeAL(ensemble.m_neurons,ntotal); - ArrayResizeAL(ensemble.m_dfdnet,ntotal); - ArrayResizeAL(ensemble.m_serializedmlp,ensemble.m_serializedlen); - ArrayResizeAL(ensemble.m_y,ensemble.m_nout); -//--- load data - for(i=offs;i<=offs+ssize-1;i++) - ensemble.m_structinfo[i-offs]=(int)MathRound(ra[i]); -//--- copy - offs=offs+ssize; - i1_=offs; - for(i_=0;i_<=ensemble.m_ensemblesize*ensemble.m_wcount-1;i_++) - ensemble.m_weights[i_]=ra[i_+i1_]; -//--- copy - offs=offs+ensemble.m_ensemblesize*ensemble.m_wcount; - i1_=offs; - for(i_=0;i_<=ensemble.m_ensemblesize*ccount-1;i_++) - ensemble.m_columnmeans[i_]=ra[i_+i1_]; -//--- copy - offs=offs+ensemble.m_ensemblesize*ccount; - i1_=offs; - for(i_=0;i_<=ensemble.m_ensemblesize*ccount-1;i_++) - ensemble.m_columnsigmas[i_]=ra[i_+i1_]; -//--- copy - offs=offs+ensemble.m_ensemblesize*ccount; - i1_=offs; - for(i_=0;i_<=ensemble.m_serializedlen-1;i_++) - ensemble.m_serializedmlp[i_]=ra[i_+i1_]; - offs=offs+ensemble.m_serializedlen; - } -//+------------------------------------------------------------------+ -//| Randomization of MLP ensemble | -//+------------------------------------------------------------------+ -static void CMLPE::MLPERandomize(CMLPEnsemble &ensemble) - { -//--- create a variable - int i=0; -//--- calculation - for(i=0;i<=ensemble.m_ensemblesize*ensemble.m_wcount-1;i++) - ensemble.m_weights[i]=CMath::RandomReal()-0.5; - } -//+------------------------------------------------------------------+ -//| Return ensemble properties (number of inputs and outputs). | -//+------------------------------------------------------------------+ -static void CMLPE::MLPEProperties(CMLPEnsemble &ensemble,int &nin,int &nout) - { -//--- change values - nin=ensemble.m_nin; - nout=ensemble.m_nout; - } -//+------------------------------------------------------------------+ -//| Return normalization type (whether ensemble is SOFTMAX-normalized| -//| or not). | -//+------------------------------------------------------------------+ -static bool CMLPE::MLPEIsSoftMax(CMLPEnsemble &ensemble) - { -//--- return result - return(ensemble.m_issoftmax); - } -//+------------------------------------------------------------------+ -//| Procesing | -//| INPUT PARAMETERS: | -//| Ensemble- neural networks ensemble | -//| X - input vector, array[0..NIn-1]. | -//| Y - (possibly) preallocated buffer; if size of Y is | -//| less than NOut, it will be reallocated. If it is | -//| large enough, it is NOT reallocated, so we can | -//| save some time on reallocation. | -//| OUTPUT PARAMETERS: | -//| Y - result. Regression estimate when solving | -//| regression task, vector of posterior | -//| probabilities for classification task. | -//+------------------------------------------------------------------+ -static void CMLPE::MLPEProcess(CMLPEnsemble &ensemble,double &x[],double &y[]) - { -//--- create variables - int i=0; - int es=0; - int wc=0; - int cc=0; - double v=0; - int i_=0; - int i1_=0; -//--- check - if(CAp::Len(y)=0.001 | -//| Restarts - restarts, >0. | -//| OUTPUT PARAMETERS: | -//| Ensemble - trained model | -//| Info - return code: | -//| * -2, if there is a point with class number | -//| outside of [0..NClasses-1]. | -//| * -1, if incorrect parameters was passed | -//| (NPoints<0, Restarts<1). | -//| * 2, if task has been solved. | -//| Rep - training report. | -//| OOBErrors - out-of-bag generalization error estimate | -//+------------------------------------------------------------------+ -static void CMLPE::MLPEBaggingLM(CMLPEnsemble &ensemble,CMatrixDouble &xy, - const int npoints,const double decay, - const int restarts,int &info,CMLPReport &rep, - CMLPCVReport &ooberrors) - { -//--- initialization - info=0; -//--- function call - MLPEBaggingInternal(ensemble,xy,npoints,decay,restarts,0.0,0,true,info,rep,ooberrors); - } -//+------------------------------------------------------------------+ -//| Training neural networks ensemble using bootstrap aggregating | -//| (bagging). L-BFGS algorithm is used as base training method. | -//| INPUT PARAMETERS: | -//| Ensemble - model with initialized geometry | -//| XY - training set | -//| NPoints - training set size | -//| Decay - weight decay coefficient, >=0.001 | -//| Restarts - restarts, >0. | -//| WStep - stopping criterion, same as in MLPTrainLBFGS | -//| MaxIts - stopping criterion, same as in MLPTrainLBFGS | -//| OUTPUT PARAMETERS: | -//| Ensemble - trained model | -//| Info - return code: | -//| * -8, if both WStep=0 and MaxIts=0 | -//| * -2, if there is a point with class number | -//| outside of [0..NClasses-1]. | -//| * -1, if incorrect parameters was passed | -//| (NPoints<0, Restarts<1). | -//| * 2, if task has been solved. | -//| Rep - training report. | -//| OOBErrors - out-of-bag generalization error estimate | -//+------------------------------------------------------------------+ -static void CMLPE::MLPEBaggingLBFGS(CMLPEnsemble &ensemble,CMatrixDouble &xy, - const int npoints,const double decay, - const int restarts,const double wstep, - const int maxits,int &info,CMLPReport &rep, - CMLPCVReport &ooberrors) - { -//--- initialization - info=0; -//--- function call - MLPEBaggingInternal(ensemble,xy,npoints,decay,restarts,wstep,maxits,false,info,rep,ooberrors); - } -//+------------------------------------------------------------------+ -//| Training neural networks ensemble using early stopping. | -//| INPUT PARAMETERS: | -//| Ensemble - model with initialized geometry | -//| XY - training set | -//| NPoints - training set size | -//| Decay - weight decay coefficient, >=0.001 | -//| Restarts - restarts, >0. | -//| OUTPUT PARAMETERS: | -//| Ensemble - trained model | -//| Info - return code: | -//| * -2, if there is a point with class number | -//| outside of [0..NClasses-1]. | -//| * -1, if incorrect parameters was passed | -//| (NPoints<0, Restarts<1). | -//| * 6, if task has been solved. | -//| Rep - training report. | -//| OOBErrors - out-of-bag generalization error estimate | -//+------------------------------------------------------------------+ -static void CMLPE::MLPETrainES(CMLPEnsemble &ensemble,CMatrixDouble &xy, - const int npoints,const double decay, - const int restarts,int &info,CMLPReport &rep) - { -//--- create variables - int i=0; - int k=0; - int ccount=0; - int pcount=0; - int trnsize=0; - int valsize=0; - int tmpinfo=0; - int i_=0; - int i1_=0; -//--- create matrix - CMatrixDouble trnxy; - CMatrixDouble valxy; -//--- objects of classes - CMultilayerPerceptron network; - CMLPReport tmprep; -//--- initialization - info=0; -//--- check - if((npoints<2 || restarts<1) || decay<0.0) - { - info=-1; - return; - } -//--- check - if(ensemble.m_issoftmax) - { - for(i=0;i<=npoints-1;i++) - { - //--- check - if((int)MathRound(xy[i][ensemble.m_nin])<0 || (int)MathRound(xy[i][ensemble.m_nin])>=ensemble.m_nout) - { - info=-2; - return; - } - } - } -//--- change value - info=6; -//--- allocate - if(ensemble.m_issoftmax) - { - ccount=ensemble.m_nin+1; - pcount=ensemble.m_nin; - } - else - { - ccount=ensemble.m_nin+ensemble.m_nout; - pcount=ensemble.m_nin+ensemble.m_nout; - } -//--- allocation - trnxy.Resize(npoints,ccount); - valxy.Resize(npoints,ccount); -//--- function call - CMLPBase::MLPUnserializeOld(ensemble.m_serializedmlp,network); -//--- change values - rep.m_ngrad=0; - rep.m_nhess=0; - rep.m_ncholesky=0; -//--- train networks - for(k=0;k<=ensemble.m_ensemblesize-1;k++) - { - //--- Split set - do - { - trnsize=0; - valsize=0; - for(i=0;i<=npoints-1;i++) - { - //--- check - if(CMath::RandomReal()<0.66) - { - //--- Assign sample to training set - for(i_=0;i_<=ccount-1;i_++) - trnxy[trnsize].Set(i_,xy[i][i_]); - trnsize=trnsize+1; - } - else - { - //--- Assign sample to validation set - for(i_=0;i_<=ccount-1;i_++) - valxy[valsize].Set(i_,xy[i][i_]); - valsize=valsize+1; - } - } - } - while(!(trnsize!=0 && valsize!=0)); - //--- Train - CMLPTrain::MLPTrainES(network,trnxy,trnsize,valxy,valsize,decay,restarts,tmpinfo,tmprep); - //--- check - if(tmpinfo<0) - { - info=tmpinfo; - return; - } - //--- save results - i1_=-(k*ensemble.m_wcount); - for(i_=k*ensemble.m_wcount;i_<=(k+1)*ensemble.m_wcount-1;i_++) - ensemble.m_weights[i_]=network.m_weights[i_+i1_]; - i1_=-(k*pcount); - for(i_=k*pcount;i_<=(k+1)*pcount-1;i_++) - ensemble.m_columnmeans[i_]=network.m_columnmeans[i_+i1_]; - i1_=-(k*pcount); - for(i_=k*pcount;i_<=(k+1)*pcount-1;i_++) - ensemble.m_columnsigmas[i_]=network.m_columnsigmas[i_+i1_]; - //--- change values - rep.m_ngrad=rep.m_ngrad+tmprep.m_ngrad; - rep.m_nhess=rep.m_nhess+tmprep.m_nhess; - rep.m_ncholesky=rep.m_ncholesky+tmprep.m_ncholesky; - } - } -//+------------------------------------------------------------------+ -//| Calculation of all types of errors | -//+------------------------------------------------------------------+ -static void CMLPE::MLPEAllErrors(CMLPEnsemble &ensemble,CMatrixDouble &xy, - const int npoints,double &relcls, - double &avgce,double &rms, - double &avg,double &avgrel) - { -//--- create variables - int i=0; - int i_=0; - int i1_=0; -//--- creating arrays - double buf[]; - double workx[]; - double y[]; - double dy[]; -//--- initialization - relcls=0; - avgce=0; - rms=0; - avg=0; - avgrel=0; -//--- allocation - ArrayResizeAL(workx,ensemble.m_nin); - ArrayResizeAL(y,ensemble.m_nout); -//--- check - if(ensemble.m_issoftmax) - { - //--- allocation - ArrayResizeAL(dy,1); - //--- function call - CBdSS::DSErrAllocate(ensemble.m_nout,buf); - } - else - { - //--- allocation - ArrayResizeAL(dy,ensemble.m_nout); - //--- function call - CBdSS::DSErrAllocate(-ensemble.m_nout,buf); - } -//--- calculation - for(i=0;i<=npoints-1;i++) - { - for(i_=0;i_<=ensemble.m_nin-1;i_++) - workx[i_]=xy[i][i_]; - //--- function call - MLPEProcess(ensemble,workx,y); - //--- check - if(ensemble.m_issoftmax) - dy[0]=xy[i][ensemble.m_nin]; - else - { - i1_=ensemble.m_nin; - for(i_=0;i_<=ensemble.m_nout-1;i_++) - dy[i_]=xy[i][i_+i1_]; - } - //--- function call - CBdSS::DSErrAccumulate(buf,y,dy); - } -//--- function call - CBdSS::DSErrFinish(buf); -//--- change values - relcls=buf[0]; - avgce=buf[1]; - rms=buf[2]; - avg=buf[3]; - avgrel=buf[4]; - } -//+------------------------------------------------------------------+ -//| Internal bagging subroutine. | -//+------------------------------------------------------------------+ -static void CMLPE::MLPEBaggingInternal(CMLPEnsemble &ensemble,CMatrixDouble &xy, - const int npoints,const double decay, - const int restarts,const double wstep, - const int maxits,const bool lmalgorithm, - int &info,CMLPReport &rep,CMLPCVReport &ooberrors) - { -//--- create variables - int nin=0; - int nout=0; - int ccnt=0; - int pcnt=0; - int i=0; - int j=0; - int k=0; - double v=0; - int i_=0; - int i1_=0; -//--- creating arrays - bool s[]; - int oobcntbuf[]; - double x[]; - double y[]; - double dy[]; - double dsbuf[]; -//--- create matrix - CMatrixDouble xys; - CMatrixDouble oobbuf; -//--- objects of classes - CMLPReport tmprep; - CMultilayerPerceptron network; -//--- initialization - info=0; -//--- Test for inputs - if((!lmalgorithm && wstep==0.0) && maxits==0) - { - info=-8; - return; - } -//--- check - if(((npoints<=0 || restarts<1) || wstep<0.0) || maxits<0) - { - info=-1; - return; - } -//--- check - if(ensemble.m_issoftmax) - { - for(i=0;i<=npoints-1;i++) - { - //--- check - if((int)MathRound(xy[i][ensemble.m_nin])<0 || (int)MathRound(xy[i][ensemble.m_nin])>=ensemble.m_nout) - { - info=-2; - return; - } - } - } -//--- allocate temporaries - info=2; - rep.m_ngrad=0; - rep.m_nhess=0; - rep.m_ncholesky=0; - ooberrors.m_relclserror=0; - ooberrors.m_avgce=0; - ooberrors.m_rmserror=0; - ooberrors.m_avgerror=0; - ooberrors.m_avgrelerror=0; - nin=ensemble.m_nin; - nout=ensemble.m_nout; -//--- check - if(ensemble.m_issoftmax) - { - ccnt=nin+1; - pcnt=nin; - } - else - { - ccnt=nin+nout; - pcnt=nin+nout; - } -//--- allocation - xys.Resize(npoints,ccnt); - ArrayResizeAL(s,npoints); - oobbuf.Resize(npoints,nout); - ArrayResizeAL(oobcntbuf,npoints); - ArrayResizeAL(x,nin); - ArrayResizeAL(y,nout); -//--- check - if(ensemble.m_issoftmax) - ArrayResizeAL(dy,1); - else - ArrayResizeAL(dy,nout); -//--- initialization - for(i=0;i<=npoints-1;i++) - { - for(j=0;j<=nout-1;j++) - oobbuf[i].Set(j,0); - } - for(i=0;i<=npoints-1;i++) - oobcntbuf[i]=0; -//--- function call - CMLPBase::MLPUnserializeOld(ensemble.m_serializedmlp,network); -//--- main bagging cycle - for(k=0;k<=ensemble.m_ensemblesize-1;k++) - { - //--- prepare dataset - for(i=0;i<=npoints-1;i++) - s[i]=false; - for(i=0;i<=npoints-1;i++) - { - j=CMath::RandomInteger(npoints); - s[j]=true; - for(i_=0;i_<=ccnt-1;i_++) - xys[i].Set(i_,xy[j][i_]); - } - //--- train - if(lmalgorithm) - CMLPTrain::MLPTrainLM(network,xys,npoints,decay,restarts,info,tmprep); - else - CMLPTrain::MLPTrainLBFGS(network,xys,npoints,decay,restarts,wstep,maxits,info,tmprep); - //--- check - if(info<0) - return; - //--- save results - rep.m_ngrad=rep.m_ngrad+tmprep.m_ngrad; - rep.m_nhess=rep.m_nhess+tmprep.m_nhess; - rep.m_ncholesky=rep.m_ncholesky+tmprep.m_ncholesky; - //--- copy - i1_=-(k*ensemble.m_wcount); - for(i_=k*ensemble.m_wcount;i_<=(k+1)*ensemble.m_wcount-1;i_++) - ensemble.m_weights[i_]=network.m_weights[i_+i1_]; - //--- copy - i1_=-(k*pcnt); - for(i_=k*pcnt;i_<=(k+1)*pcnt-1;i_++) - ensemble.m_columnmeans[i_]=network.m_columnmeans[i_+i1_]; - //--- copy - i1_=-(k*pcnt); - for(i_=k*pcnt;i_<=(k+1)*pcnt-1;i_++) - ensemble.m_columnsigmas[i_]=network.m_columnsigmas[i_+i1_]; - //--- OOB estimates - for(i=0;i<=npoints-1;i++) - { - //--- check - if(!s[i]) - { - for(i_=0;i_<=nin-1;i_++) - x[i_]=xy[i][i_]; - //--- function call - CMLPBase::MLPProcess(network,x,y); - //--- change value - for(i_=0;i_<=nout-1;i_++) - oobbuf[i].Set(i_,oobbuf[i][i_]+y[i_]); - oobcntbuf[i]=oobcntbuf[i]+1; - } - } - } -//--- OOB estimates - if(ensemble.m_issoftmax) - { - //--- function call - CBdSS::DSErrAllocate(nout,dsbuf); - } - else - { - //--- function call - CBdSS::DSErrAllocate(-nout,dsbuf); - } - for(i=0;i<=npoints-1;i++) - { - //--- check - if(oobcntbuf[i]!=0) - { - v=1.0/(double)oobcntbuf[i]; - for(i_=0;i_<=nout-1;i_++) - y[i_]=v*oobbuf[i][i_]; - //--- check - if(ensemble.m_issoftmax) - dy[0]=xy[i][nin]; - else - { - i1_=nin; - for(i_=0;i_<=nout-1;i_++) - dy[i_]=v*xy[i][i_+i1_]; - } - //--- function call - CBdSS::DSErrAccumulate(dsbuf,y,dy); - } - } -//--- function call - CBdSS::DSErrFinish(dsbuf); -//--- change values - ooberrors.m_relclserror=dsbuf[0]; - ooberrors.m_avgce=dsbuf[1]; - ooberrors.m_rmserror=dsbuf[2]; - ooberrors.m_avgerror=dsbuf[3]; - ooberrors.m_avgrelerror=dsbuf[4]; - } -//+------------------------------------------------------------------+ -//| Principal components analysis | -//+------------------------------------------------------------------+ -class CPCAnalysis - { -public: - //--- constructor, destructor - CPCAnalysis(void); - ~CPCAnalysis(void); - //--- method - static void PCABuildBasis(CMatrixDouble &x,const int npoints,const int nvars,int &info,double &s2[],CMatrixDouble &v); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CPCAnalysis::CPCAnalysis(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CPCAnalysis::~CPCAnalysis(void) - { - - } -//+------------------------------------------------------------------+ -//| Principal components analysis | -//| Subroutine builds orthogonal basis where first axis corresponds | -//| to direction with maximum variance, second axis maximizes | -//| variance in subspace orthogonal to first axis and so on. | -//| It should be noted that, unlike LDA, PCA does not use class | -//| labels. | -//| INPUT PARAMETERS: | -//| X - dataset, array[0..NPoints-1,0..NVars-1]. | -//| matrix contains ONLY INDEPENDENT VARIABLES. | -//| NPoints - dataset size, NPoints>=0 | -//| NVars - number of independent variables, NVars>=1 | -//| OUTPUT PARAMETERS: | -//| Info - return code: | -//| * -4, if SVD subroutine haven't converged | -//| * -1, if wrong parameters has been passed | -//| (NPoints<0, NVars<1) | -//| * 1, if task is solved | -//| S2 - array[0..NVars-1]. variance values | -//| corresponding to basis vectors. | -//| V - array[0..NVars-1,0..NVars-1] | -//| matrix, whose columns store basis vectors. | -//+------------------------------------------------------------------+ -static void CPCAnalysis::PCABuildBasis(CMatrixDouble &x,const int npoints, - const int nvars,int &info,double &s2[], - CMatrixDouble &v) - { -//--- create variables - int i=0; - int j=0; - double mean=0; - double variance=0; - double skewness=0; - double kurtosis=0; - int i_=0; -//--- creating arrays - double m[]; - double t[]; -//--- create matrix - CMatrixDouble a; - CMatrixDouble u; - CMatrixDouble vt; -//--- initialization - info=0; -//--- Check input data - if(npoints<0 || nvars<1) - { - info=-1; - return; - } -//--- change value - info=1; -//--- Special case: NPoints=0 - if(npoints==0) - { - //--- allocation - ArrayResizeAL(s2,nvars); - v.Resize(nvars,nvars); - //--- initialization - for(i=0;i<=nvars-1;i++) - s2[i]=0; - for(i=0;i<=nvars-1;i++) - { - for(j=0;j<=nvars-1;j++) - { - //--- check - if(i==j) - v[i].Set(j,1); - else - v[i].Set(j,0); - } - } - //--- exit the function - return; - } -//--- Calculate means - ArrayResizeAL(m,nvars); - ArrayResizeAL(t,npoints); - for(j=0;j<=nvars-1;j++) - { - for(i_=0;i_<=npoints-1;i_++) - t[i_]=x[i_][j]; - //--- function call - CBaseStat::SampleMoments(t,npoints,mean,variance,skewness,kurtosis); - m[j]=mean; - } -//--- Center,apply SVD,prepare output - a.Resize(MathMax(npoints,nvars),nvars); -//--- calculation - for(i=0;i<=npoints-1;i++) - { - for(i_=0;i_<=nvars-1;i_++) - a[i].Set(i_,x[i][i_]); - for(i_=0;i_<=nvars-1;i_++) - a[i].Set(i_,a[i][i_]-m[i_]); - } - for(i=npoints;i<=nvars-1;i++) - { - for(j=0;j<=nvars-1;j++) - a[i].Set(j,0); - } -//--- check - if(!CSingValueDecompose::RMatrixSVD(a,MathMax(npoints,nvars),nvars,0,1,2,s2,u,vt)) - { - info=-4; - return; - } -//--- check - if(npoints!=1) - { - for(i=0;i<=nvars-1;i++) - s2[i]=CMath::Sqr(s2[i])/(npoints-1); - } -//--- allocation - v.Resize(nvars,nvars); -//--- function call - CBlas::CopyAndTranspose(vt,0,nvars-1,0,nvars-1,v,0,nvars-1,0,nvars-1); - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Alglib/delegatefunctions.mqh b/Include/Math/Alglib/delegatefunctions.mqh deleted file mode 100644 index 9b4b0a1..0000000 --- a/Include/Math/Alglib/delegatefunctions.mqh +++ /dev/null @@ -1,412 +0,0 @@ -//+------------------------------------------------------------------+ -//| delegatefunctions.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 -#include "matrix.mqh" -//+------------------------------------------------------------------+ -//| Calculates f(arg), stores result to func | -//+------------------------------------------------------------------+ -class CNDimensional_Func - { -public: - CNDimensional_Func(void); - ~CNDimensional_Func(void); - - virtual void Func(double &x[],double &func,CObject &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CNDimensional_Func::CNDimensional_Func(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CNDimensional_Func::~CNDimensional_Func(void) - { - - } -//+------------------------------------------------------------------+ -//| Empty function body | -//+------------------------------------------------------------------+ -void CNDimensional_Func::Func(double &x[],double &func,CObject &obj) - { - - } -//+------------------------------------------------------------------+ -//| calculates func = f(arg), grad[i] = df(arg)/d(arg[i]) | -//+------------------------------------------------------------------+ -class CNDimensional_Grad - { -public: - //--- constructor, destructor - CNDimensional_Grad(void); - ~CNDimensional_Grad(void); - //--- virtual method - virtual void Grad(double &x[],double &func,double &grad[],CObject &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CNDimensional_Grad::CNDimensional_Grad(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CNDimensional_Grad::~CNDimensional_Grad(void) - { - - } -//+------------------------------------------------------------------+ -//| Empty function body | -//+------------------------------------------------------------------+ -void CNDimensional_Grad::Grad(double &x[],double &func,double &grad[], - CObject &obj) - { - - } -//+------------------------------------------------------------------+ -//| Calculates func = f(arg), grad[i] = df(arg)/d(arg[i]), | -//| hess[i,j] = d2f(arg)/(d(arg[i])*d(arg[j])) | -//+------------------------------------------------------------------+ -class CNDimensional_Hess - { -public: - //--- constructor, destructor - CNDimensional_Hess(void); - ~CNDimensional_Hess(void); - //--- virtual method - virtual void Hess(double &x[],double &func,double &grad[],CMatrixDouble &hess,CObject &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CNDimensional_Hess::CNDimensional_Hess(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CNDimensional_Hess::~CNDimensional_Hess(void) - { - - } -//+------------------------------------------------------------------+ -//| Empty function body | -//+------------------------------------------------------------------+ -void CNDimensional_Hess::Hess(double &x[],double &func,double &grad[], - CMatrixDouble &hess,CObject &obj) - { - - } -//+------------------------------------------------------------------+ -//| Calculates vector function f(arg), stores result to fi | -//+------------------------------------------------------------------+ -class CNDimensional_FVec - { -public: - //--- constructor, destructor - CNDimensional_FVec(void); - ~CNDimensional_FVec(void); - //--- virtual method - virtual void FVec(double &x[],double &fi[],CObject &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CNDimensional_FVec::CNDimensional_FVec(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CNDimensional_FVec::~CNDimensional_FVec(void) - { - - } -//+------------------------------------------------------------------+ -//| Empty function body | -//+------------------------------------------------------------------+ -void CNDimensional_FVec::FVec(double &x[],double &fi[],CObject &obj) - { - - } -//+------------------------------------------------------------------+ -//| Calculates f[i] = fi(arg), jac[i,j] = df[i](arg)/d(arg[j]) | -//+------------------------------------------------------------------+ -class CNDimensional_Jac - { -public: - //--- constructor, destructor - CNDimensional_Jac(void); - ~CNDimensional_Jac(void); - //--- virtual method - virtual void Jac(double &x[],double &fi[],CMatrixDouble &jac, - CObject &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CNDimensional_Jac::CNDimensional_Jac(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CNDimensional_Jac::~CNDimensional_Jac(void) - { - - } -//+------------------------------------------------------------------+ -//| Empty function body | -//+------------------------------------------------------------------+ -void CNDimensional_Jac::Jac(double &x[],double &fi[],CMatrixDouble &jac, - CObject &obj) - { - - } -//+------------------------------------------------------------------+ -//| Calculates f(p,q), stores result to func | -//+------------------------------------------------------------------+ -class CNDimensional_PFunc - { -public: - //--- constructor, destructor - CNDimensional_PFunc(void); - ~CNDimensional_PFunc(void); - //--- virtual method - virtual void PFunc(double &c[],double &x[],double &func,CObject &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CNDimensional_PFunc::CNDimensional_PFunc(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CNDimensional_PFunc::~CNDimensional_PFunc(void) - { - - } -//+------------------------------------------------------------------+ -//| Empty function body | -//+------------------------------------------------------------------+ -void CNDimensional_PFunc::PFunc(double &c[],double &x[],double &func, - CObject &obj) - { - - } -//+------------------------------------------------------------------+ -//| Calculates func = f(p,q), grad[i] = df(p,q)/d(p[i]) | -//+------------------------------------------------------------------+ -class CNDimensional_PGrad - { -public: - //--- constructor, destructor - CNDimensional_PGrad(void); - ~CNDimensional_PGrad(void); - //--- virtual method - virtual void PGrad(double &c[],double &x[],double &func,double &grad[],CObject &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CNDimensional_PGrad::CNDimensional_PGrad(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CNDimensional_PGrad::~CNDimensional_PGrad(void) - { - - } -//+------------------------------------------------------------------+ -//| Empty function body | -//+------------------------------------------------------------------+ -void CNDimensional_PGrad::PGrad(double &c[],double &x[],double &func, - double &grad[],CObject &obj) - { - - } -//+------------------------------------------------------------------+ -//| Calculates func = f(p,q), grad[i] = df(p,q)/d(p[i]), | -//| hess[i,j] = d2f(p,q)/(d(p[i])*d(p[j])) | -//+------------------------------------------------------------------+ -class CNDimensional_PHess - { -public: - //--- constructor, destructor - CNDimensional_PHess(void); - ~CNDimensional_PHess(void); - //--- virtual method - virtual void PHess(double &c[],double &x[],double &func,double &grad[],CMatrixDouble &hess,CObject &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CNDimensional_PHess::CNDimensional_PHess(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CNDimensional_PHess::~CNDimensional_PHess(void) - { - - } -//+------------------------------------------------------------------+ -//| Empty function body | -//+------------------------------------------------------------------+ -void CNDimensional_PHess::PHess(double &c[],double &x[],double &func, - double &grad[],CMatrixDouble &hess, - CObject &obj) - { - - } -//+------------------------------------------------------------------+ -//| Callbacks for ODE solvers: calculates dy/dx for given y[] and x | -//+------------------------------------------------------------------+ -class CNDimensional_ODE_RP - { -public: - //--- constructor, destructor - CNDimensional_ODE_RP(void); - ~CNDimensional_ODE_RP(void); - //--- virtual method - virtual void ODE_RP(double &y[],double x,double &dy[],CObject &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CNDimensional_ODE_RP::CNDimensional_ODE_RP(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CNDimensional_ODE_RP::~CNDimensional_ODE_RP(void) - { - - } -//+------------------------------------------------------------------+ -//| Empty function body | -//+------------------------------------------------------------------+ -void CNDimensional_ODE_RP::ODE_RP(double &y[],double x,double &dy[], - CObject &obj) - { - - } -//+------------------------------------------------------------------+ -//| Callbacks for integrators: calculates f(x) for given x | -//| (additional parameters xminusa and bminusx contain x-a and b-x) | -//+------------------------------------------------------------------+ -class CIntegrator1_Func - { -public: - //--- constructor, destructor - CIntegrator1_Func(void); - ~CIntegrator1_Func(void); - //--- virtual method - virtual void Int_Func(double x,double xminusa,double bminusx,double &y,CObject &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CIntegrator1_Func::CIntegrator1_Func(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CIntegrator1_Func::~CIntegrator1_Func(void) - { - - } -//+------------------------------------------------------------------+ -//| Empty function body | -//+------------------------------------------------------------------+ -void CIntegrator1_Func::Int_Func(double x,double xminusa,double bminusx, - double &y,CObject &obj) - { - - } -//+------------------------------------------------------------------+ -//| Callbacks for progress reports: reports current position of | -//| optimization algo | -//+------------------------------------------------------------------+ -class CNDimensional_Rep - { -public: - //--- constructor, destructor - CNDimensional_Rep(void); - ~CNDimensional_Rep(void); - //--- virtual method - virtual void Rep(double &arg[],double func,CObject &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CNDimensional_Rep::CNDimensional_Rep(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CNDimensional_Rep::~CNDimensional_Rep(void) - { - - } -//+------------------------------------------------------------------+ -//| Empty function body | -//+------------------------------------------------------------------+ -void CNDimensional_Rep::Rep(double &arg[],double func,CObject &obj) - { - - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Alglib/diffequations.mqh b/Include/Math/Alglib/diffequations.mqh deleted file mode 100644 index 8470b0b..0000000 --- a/Include/Math/Alglib/diffequations.mqh +++ /dev/null @@ -1,928 +0,0 @@ -//+------------------------------------------------------------------+ -//| diffequations.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 "matrix.mqh" -#include "alglibinternal.mqh" -//+------------------------------------------------------------------+ -//| Auxiliary class for CODESolver | -//+------------------------------------------------------------------+ -class CODESolverState - { -public: - int m_n; - int m_m; - double m_xscale; - double m_h; - double m_eps; - bool m_fraceps; - int m_repterminationtype; - int m_repnfev; - int m_solvertype; - bool m_needdy; - double m_x; - RCommState m_rstate; - //--- arrays - double m_yc[]; - double m_escale[]; - double m_xg[]; - double m_y[]; - double m_dy[]; - double m_yn[]; - double m_yns[]; - double m_rka[]; - double m_rkc[]; - double m_rkcs[]; - //--- matrices - CMatrixDouble m_ytbl; - CMatrixDouble m_rkb; - CMatrixDouble m_rkk; - -public: - CODESolverState(void); - ~CODESolverState(void); - - void Copy(CODESolverState &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CODESolverState::CODESolverState(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CODESolverState::~CODESolverState(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CODESolverState::Copy(CODESolverState &obj) - { -//--- copy variables - m_n=obj.m_n; - m_m=obj.m_m; - m_xscale=obj.m_xscale; - m_h=obj.m_h; - m_eps=obj.m_eps; - m_fraceps=obj.m_fraceps; - m_repterminationtype=obj.m_repterminationtype; - m_repnfev=obj.m_repnfev; - m_solvertype=obj.m_solvertype; - m_needdy=obj.m_needdy; - m_x=obj.m_x; - m_rstate.Copy(obj.m_rstate); -//--- copy arrays - ArrayCopy(m_yc,obj.m_yc); - ArrayCopy(m_escale,obj.m_escale); - ArrayCopy(m_xg,obj.m_xg); - ArrayCopy(m_y,obj.m_y); - ArrayCopy(m_dy,obj.m_dy); - ArrayCopy(m_yn,obj.m_yn); - ArrayCopy(m_yns,obj.m_yns); - ArrayCopy(m_rka,obj.m_rka); - ArrayCopy(m_rkc,obj.m_rkc); - ArrayCopy(m_rkcs,obj.m_rkcs); -//--- copy matrices - m_ytbl=obj.m_ytbl; - m_rkb=obj.m_rkb; - m_rkk=obj.m_rkk; - } -//+------------------------------------------------------------------+ -//| This class is a shell for class CODESolverState | -//+------------------------------------------------------------------+ -class CODESolverStateShell - { -private: - CODESolverState m_innerobj; -public: - //--- constructors, destructor - CODESolverStateShell(void); - CODESolverStateShell(CODESolverState &obj); - ~CODESolverStateShell(void); - //--- methods - bool GetNeedDY(void); - void SetNeedDY(const bool b); - double GetX(void); - void SetX(const double d); - CODESolverState *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CODESolverStateShell::CODESolverStateShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CODESolverStateShell::CODESolverStateShell(CODESolverState &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CODESolverStateShell::~CODESolverStateShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable needdy | -//+------------------------------------------------------------------+ -bool CODESolverStateShell::GetNeedDY(void) - { -//--- return result - return(m_innerobj.m_needdy); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable needdy | -//+------------------------------------------------------------------+ -void CODESolverStateShell::SetNeedDY(const bool b) - { -//--- change value - m_innerobj.m_needdy=b; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable x | -//+------------------------------------------------------------------+ -double CODESolverStateShell::GetX(void) - { -//--- return result - return(m_innerobj.m_x); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable x | -//+------------------------------------------------------------------+ -void CODESolverStateShell::SetX(const double d) - { -//--- change value - m_innerobj.m_x=d; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CODESolverState *CODESolverStateShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Auxiliary class for CODESolver | -//+------------------------------------------------------------------+ -class CODESolverReport - { -public: - //--- class variables - int m_nfev; - int m_terminationtype; - //--- constructor, destructor - CODESolverReport(void); - ~CODESolverReport(void); - //--- copy - void Copy(CODESolverReport &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CODESolverReport::CODESolverReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CODESolverReport::~CODESolverReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CODESolverReport::Copy(CODESolverReport &obj) - { -//--- copy variables - m_nfev=obj.m_nfev; - m_terminationtype=obj.m_terminationtype; - } -//+------------------------------------------------------------------+ -//| This class is a shell for class CODESolverReport | -//+------------------------------------------------------------------+ -class CODESolverReportShell - { -private: - CODESolverReport m_innerobj; -public: - //--- constructor, destructor - CODESolverReportShell(void); - CODESolverReportShell(CODESolverReport &obj); - ~CODESolverReportShell(void); - //--- methods - int GetNFev(void); - void SetNFev(const int i); - int GetTerminationType(void); - void SetTerminationType(const int i); - CODESolverReport *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CODESolverReportShell::CODESolverReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CODESolverReportShell::CODESolverReportShell(CODESolverReport &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CODESolverReportShell::~CODESolverReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable nfev | -//+------------------------------------------------------------------+ -int CODESolverReportShell::GetNFev(void) - { -//--- return result - return(m_innerobj.m_nfev); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable nfev | -//+------------------------------------------------------------------+ -void CODESolverReportShell::SetNFev(const int i) - { -//--- change value - m_innerobj.m_nfev=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable terminationtype | -//+------------------------------------------------------------------+ -int CODESolverReportShell::GetTerminationType(void) - { -//--- return result - return(m_innerobj.m_terminationtype); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable terminationtype | -//+------------------------------------------------------------------+ -void CODESolverReportShell::SetTerminationType(const int i) - { -//--- change value - m_innerobj.m_terminationtype=i; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CODESolverReport *CODESolverReportShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Solution of ordinary differential equations | -//+------------------------------------------------------------------+ -class CODESolver - { -private: - //--- private method - static void ODESolverInit(int solvertype,double &y[],const int n,double &x[],const int m,const double eps,double h,CODESolverState &state); - //--- auxiliary functions for ODESolverIteration - static void Func_lbl_rcomm(CODESolverState &state,int n,int m,int i,int j,int k,int klimit,bool gridpoint,double xc,double v,double h,double h2,double err,double maxgrowpow); - static bool Func_lbl_6(CODESolverState &state,int &n,int &m,int &i,int &j,int &k,int &klimit,bool &gridpoint,double &xc,double &v,double &h,double &h2,double &err,double &maxgrowpow); - static bool Func_lbl_8(CODESolverState &state,int &n,int &m,int &i,int &j,int &k,int &klimit,bool &gridpoint,double &xc,double &v,double &h,double &h2,double &err,double &maxgrowpow); - static bool Func_lbl_10(CODESolverState &state,int &n,int &m,int &i,int &j,int &k,int &klimit,bool &gridpoint,double &xc,double &v,double &h,double &h2,double &err,double &maxgrowpow); -public: - //--- class constants - static const double m_odesolvermaxgrow; - static const double m_odesolvermaxshrink; - //--- constructor, destructor - CODESolver(void); - ~CODESolver(void); - //--- public methods - static void ODESolverRKCK(double &y[],const int n,double &x[],const int m,const double eps,const double h,CODESolverState &state); - static void ODESolverResults(CODESolverState &state,int &m,double &xtbl[],CMatrixDouble &ytbl,CODESolverReport &rep); - static bool ODESolverIteration(CODESolverState &state); - }; -//+------------------------------------------------------------------+ -//| Initialize constants | -//+------------------------------------------------------------------+ -const double CODESolver::m_odesolvermaxgrow=3.0; -const double CODESolver::m_odesolvermaxshrink=10.0; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CODESolver::CODESolver(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CODESolver::~CODESolver(void) - { - - } -//+------------------------------------------------------------------+ -//| Cash-Karp adaptive ODE solver. | -//| This subroutine solves ODE Y'=f(Y,x) with initial conditions | -//| Y(xs)=Ys (here Y may be single variable or vector of N variables)| -//| INPUT PARAMETERS: | -//| Y - initial conditions, array[0..N-1]. | -//| contains values of Y[] at X[0] | -//| N - system size | -//| X - points at which Y should be tabulated, | -//| array[0..M-1] integrations starts at X[0], ends | -//| at X[M-1], intermediate values at X[i] are | -//| returned too. | -//| SHOULD BE ORDERED BY ASCENDING OR BY DESCENDING!!| -//| M - number of intermediate points + first point + | -//| last point: | -//| * M>2 means that you need both Y(X[M-1]) and M-2 | -//| values at intermediate points | -//| * M=2 means that you want just to integrate from | -//| X[0] to X[1] and don't interested in | -//| intermediate values. | -//| * M=1 means that you don't want to integrate :) | -//| it is degenerate case, but it will be handled | -//| correctly. | -//| * M<1 means error | -//| Eps - tolerance (absolute/relative error on each step | -//| will be less than Eps). When passing: | -//| * Eps>0, it means desired ABSOLUTE error | -//| * Eps<0, it means desired RELATIVE error. | -//| Relative errors are calculated with respect to | -//| maximum values of Y seen so far. Be careful to | -//| use this criterion when starting from Y[] that | -//| are close to zero. | -//| H - initial step lenth, it will be adjusted | -//| automatically after the first step. If H=0, step | -//| will be selected automatically (usualy it will | -//| be equal to 0.001 of min(x[i]-x[j])). | -//| OUTPUT PARAMETERS | -//| State - structure which stores algorithm state between | -//| subsequent calls of OdeSolverIteration. Used | -//| for reverse communication. This structure should | -//| be passed to the OdeSolverIteration subroutine. | -//| SEE ALSO | -//| AutoGKSmoothW, AutoGKSingular, AutoGKIteration, AutoGKResults| -//+------------------------------------------------------------------+ -static void CODESolver::ODESolverRKCK(double &y[],const int n,double &x[], - const int m,const double eps, - const double h,CODESolverState &state) - { -//--- check - if(!CAp::Assert(n>=1,"ODESolverRKCK: N<1!")) - return; -//--- check - if(!CAp::Assert(m>=1,"ODESolverRKCK: M<1!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(y)>=n,"ODESolverRKCK: Length(Y)=m,"ODESolverRKCK: Length(X)=1 | -//| XTbl - array[0..M-1], values of X | -//| YTbl - array[0..M-1,0..N-1], values of Y in X[i] | -//| Rep - solver report: | -//| * Rep.TerminationType completetion code: | -//| * -2 X is not ordered by | -//| ascending/descending or there are | -//| non-distinct X[], i.e. X[i]=X[i+1] | -//| * -1 incorrect parameters were specified | -//| * 1 task has been solved | -//| * Rep.NFEV contains number of function | -//| calculations | -//+------------------------------------------------------------------+ -static void CODESolver::ODESolverResults(CODESolverState &state,int &m, - double &xtbl[],CMatrixDouble &ytbl, - CODESolverReport &rep) - { -//--- create variables - double v=0; - int i=0; - int i_=0; -//--- initialization - m=0; - rep.m_terminationtype=state.m_repterminationtype; -//--- check - if(rep.m_terminationtype>0) - { - //--- change values - m=state.m_m; - rep.m_nfev=state.m_repnfev; - //--- allocation - ArrayResizeAL(xtbl,state.m_m); - v=state.m_xscale; - //--- calculation - for(i_=0;i_<=state.m_m-1;i_++) - xtbl[i_]=v*state.m_xg[i_]; - //--- allocation - ytbl.Resize(state.m_m,state.m_n); - for(i=0;i<=state.m_m-1;i++) - { - for(i_=0;i_<=state.m_n-1;i_++) - ytbl[i].Set(i_,state.m_ytbl[i][i_]); - } - } - else - rep.m_nfev=0; - } -//+------------------------------------------------------------------+ -//| Internal initialization subroutine | -//+------------------------------------------------------------------+ -static void CODESolver::ODESolverInit(int solvertype,double &y[],const int n, - double &x[],const int m,const double eps, - double h,CODESolverState &state) - { -//--- create variables - int i=0; - double v=0; - int i_=0; -//--- Prepare RComm - ArrayResizeAL(state.m_rstate.ia,6); - ArrayResizeAL(state.m_rstate.ba,1); - ArrayResizeAL(state.m_rstate.ra,6); - state.m_rstate.stage=-1; - state.m_needdy=false; -//--- check parameters. - if((n<=0 || m<1) || eps==0.0) - { - state.m_repterminationtype=-1; - return; - } -//--- check - if(h<0.0) - h=-h; -//--- quick exit if necessary. -//--- after this block we assume that M>1 - if(m==1) - { - //--- change values - state.m_repnfev=0; - state.m_repterminationtype=1; - state.m_ytbl.Resize(1,n); - for(i_=0;i_<=n-1;i_++) - state.m_ytbl[0].Set(i_,y[i_]); - //--- allocation - ArrayResizeAL(state.m_xg,m); - for(i_=0;i_<=m-1;i_++) - state.m_xg[i_]=x[i_]; - //--- exit the function - return; - } -//--- check again: correct order of X[] - if(x[1]==x[0]) - { - state.m_repterminationtype=-2; - return; - } - for(i=1;i<=m-1;i++) - { - //--- check - if((x[1]>x[0] && x[i]<=x[i-1]) || (x[1]=x[i-1])) - { - state.m_repterminationtype=-2; - return; - } - } -//--- auto-select H if necessary - if(h==0.0) - { - v=MathAbs(x[1]-x[0]); - for(i=2;i<=m-1;i++) - v=MathMin(v,MathAbs(x[i]-x[i-1])); - h=0.001*v; - } -//--- store parameters - state.m_n=n; - state.m_m=m; - state.m_h=h; - state.m_eps=MathAbs(eps); - state.m_fraceps=eps<0.0; -//--- allocation - ArrayResizeAL(state.m_xg,m); - for(i_=0;i_<=m-1;i_++) - state.m_xg[i_]=x[i_]; -//--- check - if(x[1]>x[0]) - state.m_xscale=1; - else - { - state.m_xscale=-1; - for(i_=0;i_<=m-1;i_++) - state.m_xg[i_]=-1*state.m_xg[i_]; - } -//--- allocation - ArrayResizeAL(state.m_yc,n); - for(i_=0;i_<=n-1;i_++) - state.m_yc[i_]=y[i_]; -//--- change values - state.m_solvertype=solvertype; - state.m_repterminationtype=0; -//--- Allocate arrays - ArrayResizeAL(state.m_y,n); - ArrayResizeAL(state.m_dy,n); - } -//+------------------------------------------------------------------+ -//| Iterative method | -//+------------------------------------------------------------------+ -static bool CODESolver::ODESolverIteration(CODESolverState &state) - { -//--- create variables - int n=0; - int m=0; - int i=0; - int j=0; - int k=0; - double xc=0; - double v=0; - double h=0; - double h2=0; - bool gridpoint; - double err=0; - double maxgrowpow=0; - int klimit=0; - int i_=0; -//--- This code initializes locals by: -//--- * random values determined during code -//--- generation - on first subroutine call -//--- * values from previous call - on subsequent calls - if(state.m_rstate.stage>=0) - { - //--- initialization - n=state.m_rstate.ia[0]; - m=state.m_rstate.ia[1]; - i=state.m_rstate.ia[2]; - j=state.m_rstate.ia[3]; - k=state.m_rstate.ia[4]; - klimit=state.m_rstate.ia[5]; - gridpoint=state.m_rstate.ba[0]; - xc=state.m_rstate.ra[0]; - v=state.m_rstate.ra[1]; - h=state.m_rstate.ra[2]; - h2=state.m_rstate.ra[3]; - err=state.m_rstate.ra[4]; - maxgrowpow=state.m_rstate.ra[5]; - } - else - { - //--- initialization - n=-983; - m=-989; - i=-834; - j=900; - k=-287; - klimit=364; - gridpoint=false; - xc=-338; - v=-686; - h=912; - h2=585; - err=497; - maxgrowpow=-271; - } -//--- check - if(state.m_rstate.stage==0) - { - //--- change values - state.m_needdy=false; - state.m_repnfev=state.m_repnfev+1; - v=h*state.m_xscale; - for(i_=0;i_<=n-1;i_++) - state.m_rkk[k].Set(i_,v*state.m_dy[i_]); - //--- update YN/YNS - v=state.m_rkc[k]; - for(i_=0;i_<=n-1;i_++) - state.m_yn[i_]=state.m_yn[i_]+v*state.m_rkk[k][i_]; - v=state.m_rkcs[k]; - for(i_=0;i_<=n-1;i_++) - state.m_yns[i_]=state.m_yns[i_]+v*state.m_rkk[k][i_]; - k=k+1; - return(Func_lbl_8(state,n,m,i,j,k,klimit,gridpoint,xc,v,h,h2,err,maxgrowpow)); - } -//--- Routine body -//--- prepare - if(state.m_repterminationtype!=0) - return(false); -//--- change values - n=state.m_n; - m=state.m_m; - h=state.m_h; - maxgrowpow=MathPow(m_odesolvermaxgrow,5); - state.m_repnfev=0; -//--- some preliminary checks for internal errors -//--- after this we assume that H>0 and M>1 - if(!CAp::Assert(state.m_h>0.0,"ODESolver: internal error")) - return(false); -//--- check - if(!CAp::Assert(m>1,"ODESolverIteration: internal error")) - return(false); -//--- choose solver - if(state.m_solvertype!=0) - return(false); -//--- Cask-Karp solver -//--- Prepare coefficients table. -//--- Check it for errors - ArrayResizeAL(state.m_rka,6); -//--- calculation - state.m_rka[0]=0; - state.m_rka[1]=1.0/5.0; - state.m_rka[2]=3.0/10.0; - state.m_rka[3]=3.0/5.0; - state.m_rka[4]=1; - state.m_rka[5]=7.0/8.0; - state.m_rkb.Resize(6,5); - state.m_rkb[1].Set(0,1.0/5.0); - state.m_rkb[2].Set(0,3.0/40.0); - state.m_rkb[2].Set(1,9.0/40.0); - state.m_rkb[3].Set(0,3.0/10.0); - state.m_rkb[3].Set(1,-(9.0/10.0)); - state.m_rkb[3].Set(2,6.0/5.0); - state.m_rkb[4].Set(0,-(11.0/54.0)); - state.m_rkb[4].Set(1,5.0/2.0); - state.m_rkb[4].Set(2,-(70.0/27.0)); - state.m_rkb[4].Set(3,35.0/27.0); - state.m_rkb[5].Set(0,1631.0/55296.0); - state.m_rkb[5].Set(1,175.0/512.0); - state.m_rkb[5].Set(2,575.0/13824.0); - state.m_rkb[5].Set(3,44275.0/110592.0); - state.m_rkb[5].Set(4,253.0/4096.0); -//--- allocation - ArrayResizeAL(state.m_rkc,6); -//--- calculation - state.m_rkc[0]=37.0/378.0; - state.m_rkc[1]=0; - state.m_rkc[2]=250.0/621.0; - state.m_rkc[3]=125.0/594.0; - state.m_rkc[4]=0; - state.m_rkc[5]=512.0/1771.0; -//--- allocation - ArrayResizeAL(state.m_rkcs,6); -//--- calculation - state.m_rkcs[0]=2825.0/27648.0; - state.m_rkcs[1]=0; - state.m_rkcs[2]=18575.0/48384.0; - state.m_rkcs[3]=13525.0/55296.0; - state.m_rkcs[4]=277.0/14336.0; - state.m_rkcs[5]=1.0/4.0; - state.m_rkk.Resize(6,n); -//--- Main cycle consists of two iterations: -//--- * outer where we travel from X[i-1] to X[i] -//--- * inner where we travel inside [X[i-1],X[i]] - state.m_ytbl.Resize(m,n); - ArrayResizeAL(state.m_escale,n); - ArrayResizeAL(state.m_yn,n); - ArrayResizeAL(state.m_yns,n); -//--- change value - xc=state.m_xg[0]; - for(i_=0;i_<=n-1;i_++) - state.m_ytbl[0].Set(i_,state.m_yc[i_]); - for(j=0;j<=n-1;j++) - state.m_escale[j]=0; - i=1; -//--- check - if(i>m-1) - { - state.m_repterminationtype=1; - //--- return result - return(false); - } -//--- begin inner iteration - return(Func_lbl_6(state,n,m,i,j,k,klimit,gridpoint,xc,v,h,h2,err,maxgrowpow)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for ODESolverIteration. Is a product to get | -//| rid of the operator unconditional jump goto | -//+------------------------------------------------------------------+ -static void CODESolver::Func_lbl_rcomm(CODESolverState &state,int n,int m, - int i,int j,int k,int klimit, - bool gridpoint,double xc,double v, - double h,double h2,double err, - double maxgrowpow) - { -//--- save - state.m_rstate.ia[0]=n; - state.m_rstate.ia[1]=m; - state.m_rstate.ia[2]=i; - state.m_rstate.ia[3]=j; - state.m_rstate.ia[4]=k; - state.m_rstate.ia[5]=klimit; - state.m_rstate.ba[0]=gridpoint; - state.m_rstate.ra[0]=xc; - state.m_rstate.ra[1]=v; - state.m_rstate.ra[2]=h; - state.m_rstate.ra[3]=h2; - state.m_rstate.ra[4]=err; - state.m_rstate.ra[5]=maxgrowpow; - } -//+------------------------------------------------------------------+ -//| Auxiliary function for ODESolverIteration. Is a product to get | -//| rid of the operator unconditional jump goto | -//+------------------------------------------------------------------+ -static bool CODESolver::Func_lbl_6(CODESolverState &state,int &n,int &m, - int &i,int &j,int &k,int &klimit, - bool &gridpoint,double &xc,double &v, - double &h,double &h2,double &err, - double &maxgrowpow) - { -//--- truncate step if needed (beyond right boundary). -//--- determine should we store X or not - if(xc+h>=state.m_xg[i]) - { - h=state.m_xg[i]-xc; - gridpoint=true; - } - else - gridpoint=false; -//--- Update error scale maximums -//--- These maximums are initialized by zeros, -//--- then updated every iterations. - for(j=0;j<=n-1;j++) - state.m_escale[j]=MathMax(state.m_escale[j],MathAbs(state.m_yc[j])); -//--- make one step: -//--- 1. calculate all info needed to do step -//--- 2. update errors scale maximums using values/derivatives -//--- obtained during (1) -//--- Take into account that we use scaling of X to reduce task -//--- to the form where x[0] < x[1] < ... < x[n-1]. So X is -//--- replaced by x=xscale*t,and dy/dx=f(y,x) is replaced -//--- by dy/dt=xscale*f(y,xscale*t). - for(int i_=0;i_<=n-1;i_++) - state.m_yn[i_]=state.m_yc[i_]; - for(int i_=0;i_<=n-1;i_++) - state.m_yns[i_]=state.m_yc[i_]; - k=0; -//--- function call, return result - return(Func_lbl_8(state,n,m,i,j,k,klimit,gridpoint,xc,v,h,h2,err,maxgrowpow)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for ODESolverIteration. Is a product to get | -//| rid of the operator unconditional jump goto | -//+------------------------------------------------------------------+ -static bool CODESolver::Func_lbl_8(CODESolverState &state,int &n,int &m, - int &i,int &j,int &k,int &klimit, - bool &gridpoint,double &xc,double &v, - double &h,double &h2,double &err, - double &maxgrowpow) - { -//--- check - if(k>5) - return(Func_lbl_10(state,n,m,i,j,k,klimit,gridpoint,xc,v,h,h2,err,maxgrowpow)); -//--- prepare data for the next update of YN/YNS - state.m_x=state.m_xscale*(xc+state.m_rka[k]*h); - for(int i_=0;i_<=n-1;i_++) - state.m_y[i_]=state.m_yc[i_]; -//--- calculation - for(j=0;j<=k-1;j++) - { - v=state.m_rkb[k][j]; - for(int i_=0;i_<=n-1;i_++) - state.m_y[i_]=state.m_y[i_]+v*state.m_rkk[j][i_]; - } - state.m_needdy=true; - state.m_rstate.stage=0; -//--- Saving state - Func_lbl_rcomm(state,n,m,i,j,k,klimit,gridpoint,xc,v,h,h2,err,maxgrowpow); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for ODESolverIteration. Is a product to get | -//| rid of the operator unconditional jump goto | -//+------------------------------------------------------------------+ -static bool CODESolver::Func_lbl_10(CODESolverState &state,int &n,int &m, - int &i,int &j,int &k,int &klimit, - bool &gridpoint,double &xc,double &v, - double &h,double &h2,double &err, - double &maxgrowpow) - { -//--- estimate error - err=0; - for(j=0;j<=n-1;j++) - { - //--- check - if(!state.m_fraceps) - { - //--- absolute error is estimated - err=MathMax(err,MathAbs(state.m_yn[j]-state.m_yns[j])); - } - else - { - //--- Relative error is estimated - v=state.m_escale[j]; - //--- check - if(v==0.0) - v=1; - err=MathMax(err,MathAbs(state.m_yn[j]-state.m_yns[j])/v); - } - } -//--- calculate new step,restart if necessary - if(maxgrowpow*err<=state.m_eps) - h2=m_odesolvermaxgrow*h; - else - h2=h*MathPow(state.m_eps/err,0.2); -//--- check - if(h2state.m_eps) - { - h=h2; - //--- begin inner iteration - return(Func_lbl_6(state,n,m,i,j,k,klimit,gridpoint,xc,v,h,h2,err,maxgrowpow)); - } -//--- advance position - xc=xc+h; - for(int i_=0;i_<=n-1;i_++) - state.m_yc[i_]=state.m_yn[i_]; -//--- update H - h=h2; -//--- break on grid point - if(gridpoint) - { - //--- save result - for(int i_=0;i_<=n-1;i_++) - state.m_ytbl[i].Set(i_,state.m_yc[i_]); - i=i+1; - //--- check - if(i>m-1) - { - state.m_repterminationtype=1; - return(false); - } - //--- begin inner iteration - return(Func_lbl_6(state,n,m,i,j,k,klimit,gridpoint,xc,v,h,h2,err,maxgrowpow)); - } -//--- begin inner iteration - return(Func_lbl_6(state,n,m,i,j,k,klimit,gridpoint,xc,v,h,h2,err,maxgrowpow)); - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Alglib/fasttransforms.mqh b/Include/Math/Alglib/fasttransforms.mqh deleted file mode 100644 index e53c6a7..0000000 --- a/Include/Math/Alglib/fasttransforms.mqh +++ /dev/null @@ -1,2418 +0,0 @@ -//+------------------------------------------------------------------+ -//| fasttransforms.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 "complex.mqh" -#include "alglibinternal.mqh" -//+------------------------------------------------------------------+ -//| Fast Fourier Transform | -//+------------------------------------------------------------------+ -class CFastFourierTransform - { -public: - CFastFourierTransform(void); - ~CFastFourierTransform(void); - - static void FFTC1D(al_complex &a[],const int n); - static void FFTC1DInv(al_complex &a[],const int n); - static void FFTR1D(double &a[],const int n,al_complex &f[]); - static void FFTR1DInv(al_complex &f[],const int n,double &a[]); - static void FFTR1DInternalEven(double &a[],const int n,double &buf[],CFtPlan &plan); - static void FFTR1DInvInternalEven(double &a[],const int n,double &buf[],CFtPlan &plan); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CFastFourierTransform::CFastFourierTransform(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CFastFourierTransform::~CFastFourierTransform(void) - { - - } -//+------------------------------------------------------------------+ -//| 1-dimensional complex FFT. | -//| Array size N may be arbitrary number (composite or prime). | -//| Composite N's are handled with cache-oblivious variation of a | -//| Cooley-Tukey algorithm. Small prime-factors are transformed using| -//| hard coded codelets (similar to FFTW codelets, but without | -//| low-level optimization), large prime-factors are handled with | -//| Bluestein's algorithm. | -//| Fastests transforms are for smooth N's (prime factors are 2, 3, | -//| 5 only), most fast for powers of 2. When N have prime factors | -//| larger than these, but orders of magnitude smaller than N, | -//| computations will be about 4 times slower than for nearby highly | -//| composite N's. When N itself is prime, speed will be 6 times | -//| lower. | -//| Algorithm has O(N*logN) complexity for any N (composite or | -//| prime). | -//| INPUT PARAMETERS | -//| A - array[0..N-1] - complex function to be transformed | -//| N - problem size | -//| OUTPUT PARAMETERS | -//| A - DFT of a input array, array[0..N-1] | -//| A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), | -//| k = 0..N-1) | -//+------------------------------------------------------------------+ -static void CFastFourierTransform::FFTC1D(al_complex &a[],const int n) - { -//--- create a variable - int i=0; -//--- create array - double buf[]; -//--- object of class - CFtPlan plan; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": incorrect N!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(a)>=n,__FUNCTION__+": Length(A)0,__FUNCTION__+": incorrect N!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(a)>=n,__FUNCTION__+": Length(A)0,__FUNCTION__+": incorrect N!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(a)>=n,__FUNCTION__+": Length(A)0,__FUNCTION__+": incorrect N!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(f)>=(int)MathFloor((double)n/2.0)+1,__FUNCTION__+": Length(F)0 && n%2==0,__FUNCTION__+": incorrect N!")) - return; -//--- Special cases: -//--- * N=2 -//--- After this block we assume that N is strictly greater than 2 - if(n==2) - { - //--- change values - x=a[0]+a[1]; - y=a[0]-a[1]; - a[0]=x; - a[1]=y; - //--- exit the function - return; - } -//--- even-size real FFT,use reduction to the complex task - n2=n/2; -//--- copy - for(i_=0;i_<=n-1;i_++) - buf[i_]=a[i_]; -//--- function call - CFtBase::FtBaseExecutePlan(buf,0,n2,plan); -//--- change value - a[0]=buf[0]+buf[1]; - for(i=1;i<=n2-1;i++) - { - //--- calculation - idx=2*(i%n2); - hn.re=buf[idx+0]; - hn.im=buf[idx+1]; - idx=2*(n2-i); - hmnc.re=buf[idx+0]; - hmnc.im=-buf[idx+1]; - v.re=-MathSin(-(2*M_PI*i/n)); - v.im=MathCos(-(2*M_PI*i/n)); - v=hn+hmnc-v*(hn-hmnc); - a[2*i+0]=0.5*v.re; - a[2*i+1]=0.5*v.im; - } -//--- change value - a[1]=buf[0]-buf[1]; - } -//+------------------------------------------------------------------+ -//| Internal subroutine. Never call it directly! | -//+------------------------------------------------------------------+ -static void CFastFourierTransform::FFTR1DInvInternalEven(double &a[],const int n, - double &buf[],CFtPlan &plan) - { -//--- create variables - double x=0; - double y=0; - double t=0; - int i=0; - int n2=0; -//--- check - if(!CAp::Assert(n>0 && n%2==0,__FUNCTION__+": incorrect N!")) - return; -//--- Special cases: -//--- * N=2 -//--- After this block we assume that N is strictly greater than 2 - if(n==2) - { - //--- change values - x=0.5*(a[0]+a[1]); - y=0.5*(a[0]-a[1]); - a[0]=x; - a[1]=y; - //--- exit the function - return; - } -//--- inverse real FFT is reduced to the inverse real FHT, -//--- which is reduced to the forward real FHT, -//--- which is reduced to the forward real FFT. -//--- Don't worry,it is really compact and efficient reduction :) - n2=n/2; - buf[0]=a[0]; -//--- calculation - for(i=1;i<=n2-1;i++) - { - x=a[2*i+0]; - y=a[2*i+1]; - buf[i]=x-y; - buf[n-i]=x+y; - } - buf[n2]=a[1]; -//--- function call - FFTR1DInternalEven(buf,n,a,plan); -//--- change values - a[0]=buf[0]/n; - t=1.0/(double)n; -//--- calculation - for(i=1;i<=n2-1;i++) - { - x=buf[2*i+0]; - y=buf[2*i+1]; - a[i]=t*(x-y); - a[n-i]=t*(x+y); - } -//--- change value - a[n2]=buf[1]/n; - } -//+------------------------------------------------------------------+ -//| Convolution class | -//+------------------------------------------------------------------+ -class CConv - { -public: - //--- constructor, destructor - CConv(void); - ~CConv(void); - //--- methods - static void ConvC1D(al_complex &a[],const int m,al_complex &b[],const int n,al_complex &r[]); - static void ConvC1DInv(al_complex &a[],const int m,al_complex &b[],const int n,al_complex &r[]); - static void ConvC1DCircular(al_complex &s[],const int m,al_complex &r[],const int n,al_complex &c[]); - static void ConvC1DCircularInv(al_complex &a[],const int m,al_complex &b[],const int n,al_complex &r[]); - static void ConvR1D(double &a[],const int m,double &b[],const int n,double &r[]); - static void ConvR1DInv(double &a[],const int m,double &b[],const int n,double &r[]); - static void ConvR1DCircular(double &s[],const int m,double &r[],const int n,double &c[]); - static void ConvR1DCircularInv(double &a[],const int m,double &b[],const int n,double &r[]); - static void ConvC1DX(al_complex &a[],const int m,al_complex &b[],const int n,const bool circular,int alg,int q,al_complex &r[]); - static void ConvR1DX(double &a[],const int m,double &b[],const int n,const bool circular,int alg,int q,double &r[]); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CConv::CConv(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CConv::~CConv(void) - { - - } -//+------------------------------------------------------------------+ -//| 1-dimensional complex convolution. | -//| For given A/B returns conv(A,B) (non-circular). Subroutine can | -//| automatically choose between three implementations: | -//| straightforward O(M*N) formula for very small N (or M), | -//| significantly larger than min(M,N), but O(M*N) algorithm is too | -//| slow, and general FFT-based formula for cases where two previois | -//| algorithms are too slow. | -//| Algorithm has max(M,N)*log(max(M,N)) complexity for any M/N. | -//| INPUT PARAMETERS | -//| A - array[0..M-1] - complex function to be transformed | -//| M - problem size | -//| B - array[0..N-1] - complex function to be transformed | -//| N - problem size | -//| OUTPUT PARAMETERS | -//| R - convolution: A*B. array[0..N+M-2]. | -//| NOTE: | -//| It is assumed that A is zero at T<0, B is zero too. If one or| -//| both functions have non-zero values at negative T's, you can | -//| still use this subroutine - just shift its result | -//| correspondingly. | -//+------------------------------------------------------------------+ -static void CConv::ConvC1D(al_complex &a[],const int m,al_complex &b[],const int n, - al_complex &r[]) - { -//--- check - if(!CAp::Assert(n>0 && m>0,__FUNCTION__+": incorrect N or M!")) - return; -//--- normalize task: make M>=N, -//--- so A will be longer that B. - if(m0 && m>0) && n<=m,__FUNCTION__+": incorrect N or M!")) - return; -//--- function call - p=CFtBase::FtBaseFindSmooth(m); - CFtBase::FtBaseGenerateComplexFFtPlan(p,plan); -//--- allocation - ArrayResizeAL(buf,2*p); -//--- copy - for(i=0;i<=m-1;i++) - { - buf[2*i+0]=a[i].re; - buf[2*i+1]=a[i].im; - } -//--- make zero - for(i=m;i<=p-1;i++) - { - buf[2*i+0]=0; - buf[2*i+1]=0; - } -//--- allocation - ArrayResizeAL(buf2,2*p); -//--- copy - for(i=0;i<=n-1;i++) - { - buf2[2*i+0]=b[i].re; - buf2[2*i+1]=b[i].im; - } -//--- make zero - for(i=n;i<=p-1;i++) - { - buf2[2*i+0]=0; - buf2[2*i+1]=0; - } -//--- function call - CFtBase::FtBaseExecutePlan(buf,0,p,plan); - CFtBase::FtBaseExecutePlan(buf2,0,p,plan); -//--- calculation - for(i=0;i<=p-1;i++) - { - c1.re=buf[2*i+0]; - c1.im=buf[2*i+1]; - c2.re=buf2[2*i+0]; - c2.im=buf2[2*i+1]; - c3=c1/c2; - buf[2*i+0]=c3.re; - buf[2*i+1]=-c3.im; - } -//--- function call - CFtBase::FtBaseExecutePlan(buf,0,p,plan); - t=1.0/(double)p; -//--- allocation - ArrayResizeAL(r,m-n+1); -//--- change values - for(i=0;i<=m-n;i++) - { - r[i].re=t*buf[2*i+0]; - r[i].im=-(t*buf[2*i+1]); - } - } -//+------------------------------------------------------------------+ -//| 1-dimensional circular complex convolution. | -//| For given S/R returns conv(S,R) (circular). Algorithm has | -//| linearithmic complexity for any M/N. | -//| IMPORTANT: normal convolution is commutative, i.e. it is | -//| symmetric - conv(A,B)=conv(B,A). Cyclic convolution IS NOT. One | -//| function - S - is a signal, periodic function, and another - R - | -//| is a response, non-periodic function with limited length. | -//| INPUT PARAMETERS | -//| S - array[0..M-1] - complex periodic signal | -//| M - problem size | -//| B - array[0..N-1] - complex non-periodic response | -//| N - problem size | -//| OUTPUT PARAMETERS | -//| R - convolution: A*B. array[0..M-1]. | -//| NOTE: | -//| It is assumed that B is zero at T<0. If it has non-zero | -//| values at negative T's, you can still use this subroutine - just | -//| shift its result correspondingly. | -//+------------------------------------------------------------------+ -static void CConv::ConvC1DCircular(al_complex &s[],const int m,al_complex &r[], - const int n,al_complex &c[]) - { -//--- create variables - int i1=0; - int i2=0; - int j2=0; - int i_=0; - int i1_=0; -//--- create array - al_complex buf[]; -//--- check - if(!CAp::Assert(n>0 && m>0,__FUNCTION__+": incorrect N or M!")) - return; -//--- normalize task: make M>=N, -//--- so A will be longer (at least - not shorter) that B. - if(m0 && m>0,__FUNCTION__+": incorrect N or M!")) - return; -//--- normalize task: make M>=N, -//--- so A will be longer (at least - not shorter) that B. - if(m0 && m>0,__FUNCTION__+": incorrect N or M!")) - return; -//--- normalize task: make M>=N, -//--- so A will be longer that B. - if(m0 && m>0) && n<=m,__FUNCTION__+": incorrect N or M!")) - return; -//--- function call - p=CFtBase::FtBaseFindSmoothEven(m); -//--- allocation - ArrayResizeAL(buf,p); -//--- copy - for(i_=0;i_<=m-1;i_++) - buf[i_]=a[i_]; -//--- make zero - for(i=m;i<=p-1;i++) - buf[i]=0; -//--- allocation - ArrayResizeAL(buf2,p); - for(i_=0;i_<=n-1;i_++) - buf2[i_]=b[i_]; -//--- make zero - for(i=n;i<=p-1;i++) - buf2[i]=0; -//--- allocation - ArrayResizeAL(buf3,p); -//--- function call - CFtBase::FtBaseGenerateComplexFFtPlan(p/2,plan); -//--- function call - CFastFourierTransform::FFTR1DInternalEven(buf,p,buf3,plan); -//--- function call - CFastFourierTransform::FFTR1DInternalEven(buf2,p,buf3,plan); -//--- change values - buf[0]=buf[0]/buf2[0]; - buf[1]=buf[1]/buf2[1]; -//--- calculation - for(i=1;i<=p/2-1;i++) - { - c1.re=buf[2*i+0]; - c1.im=buf[2*i+1]; - c2.re=buf2[2*i+0]; - c2.im=buf2[2*i+1]; - c3=c1/c2; - buf[2*i+0]=c3.re; - buf[2*i+1]=c3.im; - } -//--- function call - CFastFourierTransform::FFTR1DInvInternalEven(buf,p,buf3,plan); -//--- allocation - ArrayResizeAL(r,m-n+1); -//--- copy - for(i_=0;i_<=m-n;i_++) - r[i_]=buf[i_]; - } -//+------------------------------------------------------------------+ -//| 1-dimensional circular real convolution. | -//| Analogous to ConvC1DCircular(), see ConvC1DCircular() comments | -//| for more details. | -//| INPUT PARAMETERS | -//| S - array[0..M-1] - real signal | -//| M - problem size | -//| B - array[0..N-1] - real response | -//| N - problem size | -//| OUTPUT PARAMETERS | -//| R - convolution: A*B. array[0..M-1]. | -//| NOTE: | -//| It is assumed that B is zero at T<0. If it has non-zero | -//| values at negative T's, you can still use this subroutine - just | -//| shift its result correspondingly. | -//+------------------------------------------------------------------+ -static void CConv::ConvR1DCircular(double &s[],const int m,double &r[], - const int n,double &c[]) - { -//--- create variables - int i1=0; - int i2=0; - int j2=0; - int i_=0; - int i1_=0; -//--- create array - double buf[]; -//--- check - if(!CAp::Assert(n>0 && m>0,__FUNCTION__+": incorrect N or M!")) - return; -//--- normalize task: make M>=N, -//--- so A will be longer (at least - not shorter) that B. - if(m0 && m>0,__FUNCTION__+": incorrect N or M!")) - return; -//--- normalize task: make M>=N, -//--- so A will be longer (at least - not shorter) that B. - if(m0 && m>0,__FUNCTION__+": incorrect N or M!")) - return; -//--- check - if(!CAp::Assert(n<=m,__FUNCTION__+": N0 && m>0,__FUNCTION__+": incorrect N or M!")) - return; -//--- check - if(!CAp::Assert(n<=m,__FUNCTION__+": N2 - we should call small case code otherwise - if(alg==1) - { - //--- check - if(!CAp::Assert(m+n-1>2,__FUNCTION__+": internal error!")) - return; - //--- check - if((circular && CFtBase::FtBaseIsSmooth(m)) && m%2==0) - { - //--- special code for circular convolution with smooth even M - ArrayResizeAL(buf,m); - for(i_=0;i_<=m-1;i_++) - buf[i_]=a[i_]; - //--- allocation - ArrayResizeAL(buf2,m); - for(i_=0;i_<=n-1;i_++) - buf2[i_]=b[i_]; - for(i=n;i<=m-1;i++) - buf2[i]=0; - //--- allocation - ArrayResizeAL(buf3,m); - //--- function call - CFtBase::FtBaseGenerateComplexFFtPlan(m/2,plan); - //--- function call - CFastFourierTransform::FFTR1DInternalEven(buf,m,buf3,plan); - //--- function call - CFastFourierTransform::FFTR1DInternalEven(buf2,m,buf3,plan); - //--- change values - buf[0]=buf[0]*buf2[0]; - buf[1]=buf[1]*buf2[1]; - //--- calculation - for(i=1;i<=m/2-1;i++) - { - ax=buf[2*i+0]; - ay=buf[2*i+1]; - bx=buf2[2*i+0]; - by=buf2[2*i+1]; - tx=ax*bx-ay*by; - ty=ax*by+ay*bx; - buf[2*i+0]=tx; - buf[2*i+1]=ty; - } - //--- function call - CFastFourierTransform::FFTR1DInvInternalEven(buf,m,buf3,plan); - //--- allocation - ArrayResizeAL(r,m); - //--- copy - for(i_=0;i_<=m-1;i_++) - r[i_]=buf[i_]; - } - else - { - //--- M is non-smooth or non-even,general code (circular/non-circular): - //--- * first part is the same for circular and non-circular - //--- convolutions. zero padding,FFTs,inverse FFTs - //--- * second part differs: - //--- * for non-circular convolution we just copy array - //--- * for circular convolution we add array tail to its head - p=CFtBase::FtBaseFindSmoothEven(m+n-1); - //--- allocation - ArrayResizeAL(buf,p); - for(i_=0;i_<=m-1;i_++) - buf[i_]=a[i_]; - for(i=m;i<=p-1;i++) - buf[i]=0; - //--- allocation - ArrayResizeAL(buf2,p); - for(i_=0;i_<=n-1;i_++) - buf2[i_]=b[i_]; - for(i=n;i<=p-1;i++) - buf2[i]=0; - //--- allocation - ArrayResizeAL(buf3,p); - //--- function call - CFtBase::FtBaseGenerateComplexFFtPlan(p/2,plan); - //--- function call - CFastFourierTransform::FFTR1DInternalEven(buf,p,buf3,plan); - //--- function call - CFastFourierTransform::FFTR1DInternalEven(buf2,p,buf3,plan); - //--- change values - buf[0]=buf[0]*buf2[0]; - buf[1]=buf[1]*buf2[1]; - //--- calculation - for(i=1;i<=p/2-1;i++) - { - ax=buf[2*i+0]; - ay=buf[2*i+1]; - bx=buf2[2*i+0]; - by=buf2[2*i+1]; - tx=ax*bx-ay*by; - ty=ax*by+ay*bx; - buf[2*i+0]=tx; - buf[2*i+1]=ty; - } - //--- function call - CFastFourierTransform::FFTR1DInvInternalEven(buf,p,buf3,plan); - //--- check - if(circular) - { - //--- circular,add tail to head - ArrayResizeAL(r,m); - for(i_=0;i_<=m-1;i_++) - r[i_]=buf[i_]; - //--- check - if(n>=2) - { - i1_=m; - for(i_=0;i_<=n-2;i_++) - r[i_]=r[i_]+buf[i_+i1_]; - } - } - else - { - //--- non-circular,just copy - ArrayResizeAL(r,m+n-1); - for(i_=0;i_<=m+n-2;i_++) - r[i_]=buf[i_]; - } - } - //--- exit the function - return; - } -//--- overlap-add method - if(alg==2) - { - //--- check - if(!CAp::Assert((q+n-1)%2==0,__FUNCTION__+": internal error!")) - return; - //--- allocation - ArrayResizeAL(buf,q+n-1); - ArrayResizeAL(buf2,q+n-1); - ArrayResizeAL(buf3,q+n-1); - //--- function call - CFtBase::FtBaseGenerateComplexFFtPlan((q+n-1)/2,plan); - //--- prepare R - if(circular) - { - //--- allocation - ArrayResizeAL(r,m); - for(i=0;i<=m-1;i++) - r[i]=0; - } - else - { - //--- allocation - ArrayResizeAL(r,m+n-1); - for(i=0;i<=m+n-2;i++) - r[i]=0; - } - //--- pre-calculated FFT(B) - for(i_=0;i_<=n-1;i_++) - buf2[i_]=b[i_]; - for(j=n;j<=q+n-2;j++) - buf2[j]=0; - //--- function call - CFastFourierTransform::FFTR1DInternalEven(buf2,q+n-1,buf3,plan); - //--- main overlap-add cycle - i=0; - //--- calculation - while(i<=m-1) - { - p=MathMin(q,m-i); - i1_=i; - //--- copy - for(i_=0;i_<=p-1;i_++) - buf[i_]=a[i_+i1_]; - //--- make zero - for(j=p;j<=q+n-2;j++) - buf[j]=0; - //--- function call - CFastFourierTransform::FFTR1DInternalEven(buf,q+n-1,buf3,plan); - //--- change values - buf[0]=buf[0]*buf2[0]; - buf[1]=buf[1]*buf2[1]; - //--- calculation - for(j=1;j<=(q+n-1)/2-1;j++) - { - ax=buf[2*j+0]; - ay=buf[2*j+1]; - bx=buf2[2*j+0]; - by=buf2[2*j+1]; - tx=ax*bx-ay*by; - ty=ax*by+ay*bx; - buf[2*j+0]=tx; - buf[2*j+1]=ty; - } - //--- function call - CFastFourierTransform::FFTR1DInvInternalEven(buf,q+n-1,buf3,plan); - //--- check - if(circular) - { - j1=MathMin(i+p+n-2,m-1)-i; - j2=j1+1; - } - else - { - j1=p+n-2; - j2=j1+1; - } - //--- change values - i1_=-i; - for(i_=i;i_<=i+j1;i_++) - r[i_]=r[i_]+buf[i_+i1_]; - //--- check - if(p+n-2>=j2) - { - i1_=j2; - for(i_=0;i_<=p+n-2-j2;i_++) - r[i_]=r[i_]+buf[i_+i1_]; - } - i=i+p; - } - //--- exit the function - return; - } - } -//+------------------------------------------------------------------+ -//| Cross-correlation class | -//+------------------------------------------------------------------+ -class CCorr - { -public: - //--- constructor, destructor - CCorr(void); - ~CCorr(void); - //--- methods - static void CorrC1D(al_complex &signal[],const int n,al_complex &pattern[],const int m,al_complex &r[]); - static void CorrC1DCircular(al_complex &signal[],const int m,al_complex &pattern[],const int n,al_complex &c[]); - static void CorrR1D(double &signal[],const int n,double &pattern[],const int m,double &r[]); - static void CorrR1DCircular(double &signal[],const int m,double &pattern[],const int n,double &c[]); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CCorr::CCorr(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CCorr::~CCorr(void) - { - - } -//+------------------------------------------------------------------+ -//| 1-dimensional complex cross-correlation. | -//| For given Pattern/Signal returns corr(Pattern,Signal) | -//| (non-circular). | -//| Correlation is calculated using reduction to convolution. | -//| Algorithm with max(N,N)*log(max(N,N)) complexity is used (see | -//| ConvC1D() for more info about performance). | -//| IMPORTANT: | -//| for historical reasons subroutine accepts its parameters in | -//| reversed order: CorrC1D(Signal, Pattern) = Pattern x Signal | -//| (using traditional definition of cross-correlation, denoting | -//| cross-correlation as "x"). | -//| INPUT PARAMETERS | -//| Signal - array[0..N-1] - complex function to be | -//| transformed, signal containing pattern | -//| N - problem size | -//| Pattern - array[0..M-1] - complex function to be | -//| transformed, pattern to search withing signal | -//| M - problem size | -//| OUTPUT PARAMETERS | -//| R - cross-correlation, array[0..N+M-2]: | -//| * positive lags are stored in R[0..N-1], | -//| R[i] = sum(conj(pattern[j])*signal[i+j] | -//| * negative lags are stored in R[N..N+M-2], | -//| R[N+M-1-i] = sum(conj(pattern[j])*signal[-i+j] | -//| NOTE: | -//| It is assumed that pattern domain is [0..M-1]. If Pattern is | -//| non-zero on [-K..M-1], you can still use this subroutine, just | -//| shift result by K. | -//+------------------------------------------------------------------+ -static void CCorr::CorrC1D(al_complex &signal[],const int n,al_complex &pattern[], - const int m,al_complex &r[]) - { -//--- create variables - int i=0; - int i_=0; - int i1_=0; -//--- create arrays - al_complex p[]; - al_complex b[]; -//--- check - if(!CAp::Assert(n>0 && m>0,__FUNCTION__+": incorrect N or M!")) - return; -//--- allocation - ArrayResizeAL(p,m); - for(i=0;i<=m-1;i++) - p[m-1-i]=CMath::Conj(pattern[i]); -//--- function call - CConv::ConvC1D(p,m,signal,n,b); -//--- allocation - ArrayResizeAL(r,m+n-1); - i1_=m-1; - for(i_=0;i_<=n-1;i_++) - r[i_]=b[i_+i1_]; -//--- check - if(m+n-2>=n) - { - i1_=-n; - for(i_=n;i_<=m+n-2;i_++) - r[i_]=b[i_+i1_]; - } - } -//+------------------------------------------------------------------+ -//| 1-dimensional circular complex cross-correlation. | -//| For given Pattern/Signal returns corr(Pattern,Signal) (circular).| -//| Algorithm has linearithmic complexity for any M/N. | -//| IMPORTANT: | -//| for historical reasons subroutine accepts its parameters in | -//| reversed order: CorrC1DCircular(Signal, Pattern) = Pattern x | -//| Signal (using traditional definition of cross-correlation, | -//| denoting cross-correlation as "x"). | -//| INPUT PARAMETERS | -//| Signal - array[0..N-1] - complex function to be | -//| transformed, periodic signal containing pattern | -//| N - problem size | -//| Pattern - array[0..M-1] - complex function to be | -//| transformed, non-periodic pattern to search | -//| withing signal | -//| M - problem size | -//| OUTPUT PARAMETERS | -//| R - convolution: A*B. array[0..M-1]. | -//+------------------------------------------------------------------+ -static void CCorr::CorrC1DCircular(al_complex &signal[],const int m,al_complex &pattern[], - const int n,al_complex &c[]) - { -//--- create variables - int i1=0; - int i2=0; - int i=0; - int j2=0; - int i_=0; - int i1_=0; -//--- create arrays - al_complex p[]; - al_complex b[]; -//--- check - if(!CAp::Assert(n>0 && m>0,__FUNCTION__+": incorrect N or M!")) - return; -//--- normalize task: make M>=N, -//--- so A will be longer (at least - not shorter) that B. - if(m0 && m>0,__FUNCTION__+": incorrect N or M!")) - return; -//--- allocation - ArrayResizeAL(p,m); -//--- copy - for(i=0;i<=m-1;i++) - p[m-1-i]=pattern[i]; -//--- function call - CConv::ConvR1D(p,m,signal,n,b); -//--- allocation - ArrayResizeAL(r,m+n-1); - i1_=m-1; -//--- copy - for(i_=0;i_<=n-1;i_++) - r[i_]=b[i_+i1_]; -//--- check - if(m+n-2>=n) - { - i1_=-n; - for(i_=n;i_<=m+n-2;i_++) - r[i_]=b[i_+i1_]; - } - } -//+------------------------------------------------------------------+ -//| 1-dimensional circular real cross-correlation. | -//| For given Pattern/Signal returns corr(Pattern,Signal) (circular).| -//| Algorithm has linearithmic complexity for any M/N. | -//| IMPORTANT: | -//| for historical reasons subroutine accepts its parameters in | -//| reversed order: CorrR1DCircular(Signal, Pattern) = Pattern x | -//| Signal (using traditional definition of cross-correlation, | -//| denoting cross-correlation as "x"). | -//| INPUT PARAMETERS | -//| Signal - array[0..N-1] - real function to be transformed, | -//| periodic signal containing pattern | -//| N - problem size | -//| Pattern - array[0..M-1] - real function to be transformed, | -//| non-periodic pattern to search withing signal | -//| M - problem size | -//| OUTPUT PARAMETERS | -//| R - convolution: A*B. array[0..M-1]. | -//+------------------------------------------------------------------+ -static void CCorr::CorrR1DCircular(double &signal[],const int m,double &pattern[], - const int n,double &c[]) - { -//--- create variables - int i1=0; - int i2=0; - int i=0; - int j2=0; - int i_=0; - int i1_=0; -//--- create arrays - double p[]; - double b[]; -//--- check - if(!CAp::Assert(n>0 && m>0,__FUNCTION__+": incorrect N or M!")) - return; -//--- normalize task: make M>=N, -//--- so A will be longer (at least - not shorter) that B. - if(m0,__FUNCTION__+": incorrect N!")) - return; -//--- Special case: N=1,FHT is just identity transform. -//--- After this block we assume that N is strictly greater than 1. - if(n==1) - return; -//--- Reduce FHt to real FFT - CFastFourierTransform::FFTR1D(a,n,fa); -//--- change values - for(i=0;i<=n-1;i++) - a[i]=fa[i].re-fa[i].im; - } -//+------------------------------------------------------------------+ -//| 1-dimensional inverse FHT. | -//| Algorithm has O(N*logN) complexity for any N (composite or prime)| -//| INPUT PARAMETERS | -//| A - array[0..N-1] - complex array to be transformed | -//| N - problem size | -//| OUTPUT PARAMETERS | -//| A - inverse FHT of a input array, array[0..N-1] | -//+------------------------------------------------------------------+ -static void CFastHartleyTransform::FHTR1DInv(double &a[],const int n) - { -//--- create a variable - int i=0; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": incorrect N!")) - return; -//--- Special case: N=1,iFHT is just identity transform. -//--- After this block we assume that N is strictly greater than 1. - if(n==1) - return; -//--- Inverse FHT can be expressed in terms of the FHT as -//--- invfht(x)=fht(x)/N - FHTR1D(a,n); -//--- change values - for(i=0;i<=n-1;i++) - a[i]=a[i]/n; - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Alglib/integration.mqh b/Include/Math/Alglib/integration.mqh deleted file mode 100644 index a052c3ec342cf8ff43f0ea87e8392f93011ab8aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 249418 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 diff --git a/Include/Math/Alglib/interpolation.mqh b/Include/Math/Alglib/interpolation.mqh deleted file mode 100644 index 1a09b5d..0000000 --- a/Include/Math/Alglib/interpolation.mqh +++ /dev/null @@ -1,13407 +0,0 @@ -//+------------------------------------------------------------------+ -//| interpolation.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 "alglibmisc.mqh" -#include "optimization.mqh" -#include "solvers.mqh" -#include "integration.mqh" -//+------------------------------------------------------------------+ -//| IDW interpolant. | -//+------------------------------------------------------------------+ -class CIDWInterpolant - { -public: - int m_n; - int m_nx; - int m_d; - double m_r; - int m_nw; - CKDTree m_tree; - int m_modeltype; - int m_debugsolverfailures; - double m_debugworstrcond; - double m_debugbestrcond; - //--- arrays - double m_xbuf[]; - int m_tbuf[]; - double m_rbuf[]; - //--- matrices - CMatrixDouble m_q; - CMatrixDouble m_xybuf; - -public: - CIDWInterpolant(void); - ~CIDWInterpolant(void); - - void Copy(CIDWInterpolant &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CIDWInterpolant::CIDWInterpolant(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CIDWInterpolant::~CIDWInterpolant(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CIDWInterpolant::Copy(CIDWInterpolant &obj) - { -//--- copy variables - m_n=obj.m_n; - m_nx=obj.m_nx; - m_d=obj.m_d; - m_r=obj.m_r; - m_nw=obj.m_nw; - m_modeltype=obj.m_modeltype; - m_debugsolverfailures=obj.m_debugsolverfailures; - m_debugworstrcond=obj.m_debugworstrcond; - m_debugbestrcond=obj.m_debugbestrcond; - m_tree.Copy(obj.m_tree); -//--- copy arrays - ArrayCopy(m_xbuf,obj.m_xbuf); - ArrayCopy(m_tbuf,obj.m_tbuf); - ArrayCopy(m_rbuf,obj.m_rbuf); -//--- copy matrices - m_q=obj.m_q; - m_xybuf=obj.m_xybuf; - } -//+------------------------------------------------------------------+ -//| IDW interpolant. | -//+------------------------------------------------------------------+ -class CIDWInterpolantShell - { -private: - CIDWInterpolant m_innerobj; -public: - //--- constructors, destructor - CIDWInterpolantShell(void); - CIDWInterpolantShell(CIDWInterpolant &obj); - ~CIDWInterpolantShell(void); - //--- method - CIDWInterpolant *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CIDWInterpolantShell::CIDWInterpolantShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CIDWInterpolantShell::CIDWInterpolantShell(CIDWInterpolant &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CIDWInterpolantShell::~CIDWInterpolantShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CIDWInterpolant *CIDWInterpolantShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Inverse distance weighting interpolation | -//+------------------------------------------------------------------+ -class CIDWInt - { -private: - //--- private methods - static double IDWCalcQ(CIDWInterpolant &z,double &x[],const int k); - static void IDWInit1(const int n,const int nx,const int d,int nq,int nw,CIDWInterpolant &z); - static void IDWInternalSolver(double &y[],double &w[],CMatrixDouble &fmatrix,double &temp[],const int n,const int m,int &info,double &x[],double &taskrcond); -public: - //--- class constants - static const double m_idwqfactor; - static const int m_idwkmin; - //--- constructor, destructor - CIDWInt(void); - ~CIDWInt(void); - //--- public methods - static double IDWCalc(CIDWInterpolant &z,double &x[]); - static void IDWBuildModifiedShepard(CMatrixDouble &xy,const int n,const int nx,const int d,int nq,int nw,CIDWInterpolant &z); - static void IDWBuildModifiedShepardR(CMatrixDouble &xy,const int n,const int nx,const double r,CIDWInterpolant &z); - static void IDWBuildNoisy(CMatrixDouble &xy,const int n,const int nx,const int d,int nq,int nw,CIDWInterpolant &z); - }; -//+------------------------------------------------------------------+ -//| Initialize constants | -//+------------------------------------------------------------------+ -const double CIDWInt::m_idwqfactor=1.5; -const int CIDWInt::m_idwkmin=5; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CIDWInt::CIDWInt(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CIDWInt::~CIDWInt(void) - { - - } -//+------------------------------------------------------------------+ -//| IDW interpolation | -//| INPUT PARAMETERS: | -//| Z - IDW interpolant built with one of model building | -//| subroutines. | -//| X - array[0..NX-1], interpolation point | -//| Result: | -//| IDW interpolant Z(X) | -//+------------------------------------------------------------------+ -static double CIDWInt::IDWCalc(CIDWInterpolant &z,double &x[]) - { -//--- create variables - double result=0; - int nx=0; - int i=0; - int k=0; - double r=0; - double s=0; - double w=0; - double v1=0; - double v2=0; - double d0=0; - double di=0; -//--- these initializers are not really necessary, -//--- but without them compiler complains about uninitialized locals - k=0; -//--- Query - if(z.m_modeltype==0) - { - //--- NQ/NW-based model - nx=z.m_nx; - k=CNearestNeighbor::KDTreeQueryKNN(z.m_tree,x,z.m_nw,true); - //--- function call - CNearestNeighbor::KDTreeQueryResultsDistances(z.m_tree,z.m_rbuf); - //--- function call - CNearestNeighbor::KDTreeQueryResultsTags(z.m_tree,z.m_tbuf); - } - if(z.m_modeltype==1) - { - //--- R-based model - nx=z.m_nx; - k=CNearestNeighbor::KDTreeQueryRNN(z.m_tree,x,z.m_r,true); - //--- function call - CNearestNeighbor::KDTreeQueryResultsDistances(z.m_tree,z.m_rbuf); - //--- function call - CNearestNeighbor::KDTreeQueryResultsTags(z.m_tree,z.m_tbuf); - if(kd0 -//--- NOTE 2: self-match is USED for this query -//--- NOTE 3: last point almost always gain zero weight,but it MUST -//--- be used for fitting because sometimes it will gain NON-ZERO -//--- weight - for example,when all distances are equal. - r=z.m_rbuf[k-1]; - d0=z.m_rbuf[0]; - result=0; - s=0; - for(i=0;i<=k-1;i++) - { - di=z.m_rbuf[i]; - //--- check - if(di==d0) - { - //--- distance is equal to shortest,set it 1.0 - //--- without explicitly calculating (which would give - //--- us same result,but 'll expose us to the risk of - //--- division by zero). - w=1; - } - else - { - //--- use normalized formula - v1=(r-di)/(r-d0); - v2=d0/di; - w=CMath::Sqr(v1*v2); - } - //--- change result - result=result+w*IDWCalcQ(z,x,z.m_tbuf[i]); - s=s+w; - } -//--- return result - return(result/s); - } -//+------------------------------------------------------------------+ -//| IDW interpolant using modified Shepard method for uniform point | -//| distributions. | -//| INPUT PARAMETERS: | -//| XY - X and Y values, array[0..N-1,0..NX]. | -//| First NX columns contain X-values, last column | -//| contain Y-values. | -//| N - number of nodes, N>0. | -//| NX - space dimension, NX>=1. | -//| D - nodal function type, either: | -//| * 0 constant model. Just for demonstration only,| -//| worst model ever. | -//| * 1 linear model, least squares fitting. Simpe | -//| model for datasets too small for quadratic | -//| models | -//| * 2 quadratic model, least squares fitting. | -//| Best model available (if your dataset is | -//| large enough). | -//| * -1 "fast" linear model, use with caution!!! It | -//| is significantly faster than linear/quadratic| -//| and better than constant model. But it is | -//| less robust (especially in the presence of | -//| noise). | -//| NQ - number of points used to calculate nodal functions | -//| (ignored for constant models). NQ should be LARGER | -//| than: | -//| * max(1.5*(1+NX),2^NX+1) for linear model, | -//| * max(3/4*(NX+2)*(NX+1),2^NX+1) for quadratic model. | -//| Values less than this threshold will be silently | -//| increased. | -//| NW - number of points used to calculate weights and to | -//| interpolate. Required: >=2^NX+1, values less than | -//| this threshold will be silently increased. | -//| Recommended value: about 2*NQ | -//| OUTPUT PARAMETERS: | -//| Z - IDW interpolant. | -//| NOTES: | -//| * best results are obtained with quadratic models, worst - with| -//| constant models | -//| * when N is large, NQ and NW must be significantly smaller than| -//| N both to obtain optimal performance and to obtain optimal | -//| accuracy. In 2 or 3-dimensional tasks NQ=15 and NW=25 are | -//| good values to start with. | -//| * NQ and NW may be greater than N. In such cases they will be | -//| automatically decreased. | -//| * this subroutine is always succeeds (as long as correct | -//| parameters are passed). | -//| * see 'Multivariate Interpolation of Large Sets of Scattered | -//| Data' by Robert J. Renka for more information on this | -//| algorithm. | -//| * this subroutine assumes that point distribution is uniform at| -//| the small scales. If it isn't - for example, points are | -//| concentrated along "lines", but "lines" distribution is | -//| uniform at the larger scale - then you should use | -//| IDWBuildModifiedShepardR() | -//+------------------------------------------------------------------+ -static void CIDWInt::IDWBuildModifiedShepard(CMatrixDouble &xy,const int n, - const int nx,const int d, - int nq,int nw,CIDWInterpolant &z) - { -//--- create variables - int i=0; - int j=0; - int k=0; - int j2=0; - int j3=0; - double v=0; - double r=0; - double s=0; - double d0=0; - double di=0; - double v1=0; - double v2=0; - int nc=0; - int offs=0; - int info=0; - double taskrcond=0; - int i_=0; -//--- create arrays - double x[]; - double qrbuf[]; - double y[]; - double w[]; - double qsol[]; - double temp[]; - int tags[]; -//--- create matrix - CMatrixDouble qxybuf; - CMatrixDouble fmatrix; -//--- these initializers are not really necessary, -//--- but without them compiler complains about uninitialized locals - nc=0; -//--- assertions - if(!CAp::Assert(n>0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(nx>=1,__FUNCTION__+": NX<1!")) - return; -//--- check - if(!CAp::Assert(d>=-1 && d<=2,__FUNCTION__+": D<>-1 and D<>0 and D<>1 and D<>2!")) - return; -//--- Correct parameters if needed - if(d==1) - { - nq=MathMax(nq,(int)MathCeil(m_idwqfactor*(1+nx))+1); - nq=MathMax(nq,(int)MathRound(MathPow(2,nx))+1); - } -//--- check - if(d==2) - { - nq=MathMax(nq,(int)MathCeil(m_idwqfactor*(nx+2)*(nx+1)/2)+1); - nq=MathMax(nq,(int)MathRound(MathPow(2,nx))+1); - } -//--- change values - nw=MathMax(nw,(int)MathRound(MathPow(2,nx))+1); - nq=MathMin(nq,n); - nw=MathMin(nw,n); -//--- primary initialization of Z - IDWInit1(n,nx,d,nq,nw,z); - z.m_modeltype=0; -//--- Create KD-tree - ArrayResizeAL(tags,n); - for(i=0;i<=n-1;i++) - tags[i]=i; -//--- function call - CNearestNeighbor::KDTreeBuildTagged(xy,tags,n,nx,1,2,z.m_tree); -//--- build nodal functions - ArrayResizeAL(temp,nq+1); - ArrayResizeAL(x,nx); - ArrayResizeAL(qrbuf,nq); - qxybuf.Resize(nq,nx+1); -//--- check - if(d==-1) - ArrayResizeAL(w,nq); -//--- check - if(d==1) - { - //--- allocation - ArrayResizeAL(y,nq); - ArrayResizeAL(w,nq); - ArrayResizeAL(qsol,nx); - //--- NX for linear members, - //--- 1 for temporary storage - fmatrix.Resize(nq,nx+1); - } -//--- check - if(d==2) - { - //--- allocation - ArrayResizeAL(y,nq); - ArrayResizeAL(w,nq); - ArrayResizeAL(qsol,nx+(int)MathRound(nx*(nx+1)*0.5)); - //--- NX for linear members, - //--- Round(NX*(NX+1)*0.5) for quadratic model, - //--- 1 for temporary storage - fmatrix.Resize(nq,nx+(int)MathRound(nx*(nx+1)*0.5)+1); - } - for(i=0;i<=n-1;i++) - { - //--- Initialize center and function value. - //--- If D=0 it is all what we need - for(i_=0;i_<=nx;i_++) - z.m_q[i].Set(i_,xy[i][i_]); - //--- check - if(d==0) - continue; - //--- calculate weights for linear/quadratic members calculation. - //--- NOTE 1: weights are calculated using NORMALIZED modified - //--- Shepard's formula. Original formula is w(i)=sqr((R-di)/(R*di)), - //--- where di is i-th distance,R is max(di). Modified formula have - //--- following form: - //--- w_mod(i)=1,if di=d0 - //--- w_mod(i)=w(i)/w(0),if di<>d0 - //--- NOTE 2: self-match is NOT used for this query - //--- NOTE 3: last point almost always gain zero weight,but it MUST - //--- be used for fitting because sometimes it will gain NON-ZERO - //--- weight - for example,when all distances are equal. - for(i_=0;i_<=nx-1;i_++) - x[i_]=xy[i][i_]; - k=CNearestNeighbor::KDTreeQueryKNN(z.m_tree,x,nq,false); - //--- function call - CNearestNeighbor::KDTreeQueryResultsXY(z.m_tree,qxybuf); - //--- function call - CNearestNeighbor::KDTreeQueryResultsDistances(z.m_tree,qrbuf); - r=qrbuf[k-1]; - d0=qrbuf[0]; - //--- calculation - for(j=0;j<=k-1;j++) - { - di=qrbuf[j]; - //--- check - if(di==d0) - { - //--- distance is equal to shortest,set it 1.0 - //--- without explicitly calculating (which would give - //--- us same result,but 'll expose us to the risk of - //--- division by zero). - w[j]=1; - } - else - { - //--- use normalized formula - v1=(r-di)/(r-d0); - v2=d0/di; - w[j]=CMath::Sqr(v1*v2); - } - } - //--- calculate linear/quadratic members - if(d==-1) - { - //--- "Fast" linear nodal function calculated using - //--- inverse distance weighting - for(j=0;j<=nx-1;j++) - x[j]=0; - s=0; - //--- calculation - for(j=0;j<=k-1;j++) - { - //--- calculate J-th inverse distance weighted gradient: - //--- grad_k=(y_j-y_k)*(x_j-x_k)/sqr(norm(x_j-x_k)) - //--- grad=sum(wk*grad_k)/sum(w_k) - v=0; - for(j2=0;j2<=nx-1;j2++) - v=v+CMath::Sqr(qxybuf[j][j2]-xy[i][j2]); - //--- Although x_j<>x_k,sqr(norm(x_j-x_k)) may be zero due to - //--- underflow. If it is,we assume than J-th gradient is zero - //--- (i.m_e. don't add anything) - if(v!=0.0) - { - for(j2=0;j2<=nx-1;j2++) - x[j2]=x[j2]+w[j]*(qxybuf[j][nx]-xy[i][nx])*(qxybuf[j][j2]-xy[i][j2])/v; - } - s=s+w[j]; - } - for(j=0;j<=nx-1;j++) - z.m_q[i].Set(nx+1+j,x[j]/s); - } - else - { - //--- Least squares models: build - if(d==1) - { - //--- Linear nodal function calculated using - //--- least squares fitting to its neighbors - for(j=0;j<=k-1;j++) - { - for(j2=0;j2<=nx-1;j2++) - fmatrix[j].Set(j2,qxybuf[j][j2]-xy[i][j2]); - y[j]=qxybuf[j][nx]-xy[i][nx]; - } - nc=nx; - } - //--- check - if(d==2) - { - //--- Quadratic nodal function calculated using - //--- least squares fitting to its neighbors - for(j=0;j<=k-1;j++) - { - offs=0; - for(j2=0;j2<=nx-1;j2++) - { - fmatrix[j].Set(offs,qxybuf[j][j2]-xy[i][j2]); - offs=offs+1; - } - //--- calculation - for(j2=0;j2<=nx-1;j2++) - { - for(j3=j2;j3<=nx-1;j3++) - { - fmatrix[j].Set(offs,(qxybuf[j][j2]-xy[i][j2])*(qxybuf[j][j3]-xy[i][j3])); - offs=offs+1; - } - } - y[j]=qxybuf[j][nx]-xy[i][nx]; - } - nc=nx+(int)MathRound(nx*(nx+1)*0.5); - } - //--- function call - IDWInternalSolver(y,w,fmatrix,temp,k,nc,info,qsol,taskrcond); - //--- Least squares models: copy results - if(info>0) - { - //--- LLS task is solved,copy results - z.m_debugworstrcond=MathMin(z.m_debugworstrcond,taskrcond); - z.m_debugbestrcond=MathMax(z.m_debugbestrcond,taskrcond); - for(j=0;j<=nc-1;j++) - z.m_q[i].Set(nx+1+j,qsol[j]); - } - else - { - //--- Solver failure,very strange,but we will use - //--- zero values to handle it. - z.m_debugsolverfailures=z.m_debugsolverfailures+1; - for(j=0;j<=nc-1;j++) - z.m_q[i].Set(nx+1+j,0); - } - } - } - } -//+------------------------------------------------------------------+ -//| IDW interpolant using modified Shepard method for non-uniform | -//| datasets. | -//| This type of model uses constant nodal functions and interpolates| -//| using all nodes which are closer than user-specified radius R. It| -//| may be used when points distribution is non-uniform at the small | -//| scale, but it is at the distances as large as R. | -//| INPUT PARAMETERS: | -//| XY - X and Y values, array[0..N-1,0..NX]. | -//| First NX columns contain X-values, last column | -//| contain Y-values. | -//| N - number of nodes, N>0. | -//| NX - space dimension, NX>=1. | -//| R - radius, R>0 | -//| OUTPUT PARAMETERS: | -//| Z - IDW interpolant. | -//| NOTES: | -//| * if there is less than IDWKMin points within R-ball, algorithm | -//| selects IDWKMin closest ones, so that continuity properties of | -//| interpolant are preserved even far from points. | -//+------------------------------------------------------------------+ -static void CIDWInt::IDWBuildModifiedShepardR(CMatrixDouble &xy,const int n, - const int nx,const double r, - CIDWInterpolant &z) - { -//--- create variables - int i=0; - int i_=0; -//--- create array - int tags[]; -//--- assertions - if(!CAp::Assert(n>0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(nx>=1,__FUNCTION__+": NX<1!")) - return; -//--- check - if(!CAp::Assert(r>0.0,__FUNCTION__+": R<=0!")) - return; -//--- primary initialization of Z - IDWInit1(n,nx,0,0,n,z); - z.m_modeltype=1; - z.m_r=r; -//--- Create KD-tree - ArrayResizeAL(tags,n); - for(i=0;i<=n-1;i++) - tags[i]=i; -//--- function call - CNearestNeighbor::KDTreeBuildTagged(xy,tags,n,nx,1,2,z.m_tree); -//--- build nodal functions - for(i=0;i<=n-1;i++) - { - for(i_=0;i_<=nx;i_++) - z.m_q[i].Set(i_,xy[i][i_]); - } - } -//+------------------------------------------------------------------+ -//| IDW model for noisy data. | -//| This subroutine may be used to handle noisy data, i.e. data with | -//| noise in OUTPUT values. It differs from IDWBuildModifiedShepard()| -//| in the following aspects: | -//| * nodal functions are not constrained to pass through nodes: | -//| Qi(xi)<>yi, i.e. we have fitting instead of interpolation. | -//| * weights which are used during least squares fitting stage are | -//| all equal to 1.0 (independently of distance) | -//| * "fast"-linear or constant nodal functions are not supported | -//| (either not robust enough or too rigid) | -//| This problem require far more complex tuning than interpolation | -//| problems. | -//| Below you can find some recommendations regarding this problem: | -//| * focus on tuning NQ; it controls noise reduction. As for NW, you| -//| can just make it equal to 2*NQ. | -//| * you can use cross-validation to determine optimal NQ. | -//| * optimal NQ is a result of complex tradeoff between noise level | -//| (more noise = larger NQ required) and underlying function | -//| complexity (given fixed N, larger NQ means smoothing of compex | -//| features in the data). For example, NQ=N will reduce noise to | -//| the minimum level possible, but you will end up with just | -//| constant/linear/quadratic (depending on D) least squares | -//| model for the whole dataset. | -//| INPUT PARAMETERS: | -//| XY - X and Y values, array[0..N-1,0..NX]. | -//| First NX columns contain X-values, last column | -//| contain Y-values. | -//| N - number of nodes, N>0. | -//| NX - space dimension, NX>=1. | -//| D - nodal function degree, either: | -//| * 1 linear model, least squares fitting. Simpe | -//| model for datasets too small for quadratic | -//| models (or for very noisy problems). | -//| * 2 quadratic model, least squares fitting. Best | -//| model available (if your dataset is large | -//| enough). | -//| NQ - number of points used to calculate nodal functions. | -//| NQ should be significantly larger than 1.5 times the | -//| number of coefficients in a nodal function to | -//| overcome effects of noise: | -//| * larger than 1.5*(1+NX) for linear model, | -//| * larger than 3/4*(NX+2)*(NX+1) for quadratic model. | -//| Values less than this threshold will be silently | -//| increased. | -//| NW - number of points used to calculate weights and to | -//| interpolate. Required: >=2^NX+1, values less than | -//| this threshold will be silently increased. | -//| Recommended value: about 2*NQ or larger | -//| OUTPUT PARAMETERS: | -//| Z - IDW inte rpolant. | -//| NOTES: | -//| * best results are obtained with quadratic models, linear | -//| models are not recommended to use unless you are pretty sure | -//| that it is what you want | -//| * this subroutine is always succeeds (as long as correct | -//| parameters are passed). | -//| * see 'Multivariate Interpolation of Large Sets of Scattered | -//| Data' by Robert J. Renka for more information on this | -//| algorithm. | -//+------------------------------------------------------------------+ -static void CIDWInt::IDWBuildNoisy(CMatrixDouble &xy,const int n,const int nx, - const int d,int nq,int nw,CIDWInterpolant &z) - { -//--- create variables - int i=0; - int j=0; - int k=0; - int j2=0; - int j3=0; - double v=0; - int nc=0; - int offs=0; - double taskrcond=0; - int info=0; - int i_=0; -//--- create arrays - double x[]; - double qrbuf[]; - double y[]; - double w[]; - double qsol[]; - int tags[]; - double temp[]; -//--- create matrix - CMatrixDouble qxybuf; - CMatrixDouble fmatrix; -//--- these initializers are not really necessary, -//--- but without them compiler complains about uninitialized locals - nc=0; -//--- assertions - if(!CAp::Assert(n>0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(nx>=1,__FUNCTION__+": NX<1!")) - return; -//--- check - if(!CAp::Assert(d>=1 && d<=2,__FUNCTION__+": D<>1 and D<>2!")) - return; -//--- Correct parameters if needed - if(d==1) - nq=MathMax(nq,(int)MathCeil(m_idwqfactor*(1+nx))+1); -//--- check - if(d==2) - nq=MathMax(nq,(int)MathCeil(m_idwqfactor*(nx+2)*(nx+1)/2)+1); -//--- change values - nw=MathMax(nw,(int)MathRound(MathPow(2,nx))+1); - nq=MathMin(nq,n); - nw=MathMin(nw,n); -//--- primary initialization of Z - IDWInit1(n,nx,d,nq,nw,z); - z.m_modeltype=0; -//--- Create KD-tree - ArrayResizeAL(tags,n); - for(i=0;i<=n-1;i++) - tags[i]=i; -//--- function call - CNearestNeighbor::KDTreeBuildTagged(xy,tags,n,nx,1,2,z.m_tree); -//--- build nodal functions -//--- (special algorithm for noisy data is used) - ArrayResizeAL(temp,nq+1); - ArrayResizeAL(x,nx); - ArrayResizeAL(qrbuf,nq); - qxybuf.Resize(nq,nx+1); -//--- check - if(d==1) - { - //--- allocation - ArrayResizeAL(y,nq); - ArrayResizeAL(w,nq); - ArrayResizeAL(qsol,1+nx); - //--- 1 for constant member, - //--- NX for linear members, - //--- 1 for temporary storage - fmatrix.Resize(nq,1+nx+1); - } -//--- check - if(d==2) - { - //--- allocation - ArrayResizeAL(y,nq); - ArrayResizeAL(w,nq); - ArrayResizeAL(qsol,1+nx+(int)MathRound(nx*(nx+1)*0.5)); - //--- 1 for constant member, - //--- NX for linear members, - //--- Round(NX*(NX+1)*0.5) for quadratic model, - //--- 1 for temporary storage - fmatrix.Resize(nq,1+nx+(int)MathRound(nx*(nx+1)*0.5)+1); - } -//--- calculation - for(i=0;i<=n-1;i++) - { - //--- Initialize center. - for(i_=0;i_<=nx-1;i_++) - z.m_q[i].Set(i_,xy[i][i_]); - //--- Calculate linear/quadratic members - //--- using least squares fit - //--- NOTE 1: all weight are equal to 1.0 - //--- NOTE 2: self-match is USED for this query - for(i_=0;i_<=nx-1;i_++) - x[i_]=xy[i][i_]; - k=CNearestNeighbor::KDTreeQueryKNN(z.m_tree,x,nq,true); - //--- function call - CNearestNeighbor::KDTreeQueryResultsXY(z.m_tree,qxybuf); - //--- function call - CNearestNeighbor::KDTreeQueryResultsDistances(z.m_tree,qrbuf); - //--- check - if(d==1) - { - //--- Linear nodal function calculated using - //--- least squares fitting to its neighbors - for(j=0;j<=k-1;j++) - { - fmatrix[j].Set(0,1.0); - for(j2=0;j2<=nx-1;j2++) - fmatrix[j].Set(1+j2,qxybuf[j][j2]-xy[i][j2]); - //--- change values - y[j]=qxybuf[j][nx]; - w[j]=1; - } - nc=1+nx; - } - //--- check - if(d==2) - { - //--- Quadratic nodal function calculated using - //--- least squares fitting to its neighbors - for(j=0;j<=k-1;j++) - { - fmatrix[j].Set(0,1); - offs=1; - for(j2=0;j2<=nx-1;j2++) - { - fmatrix[j].Set(offs,qxybuf[j][j2]-xy[i][j2]); - offs=offs+1; - } - //--- calculation - for(j2=0;j2<=nx-1;j2++) - { - for(j3=j2;j3<=nx-1;j3++) - { - fmatrix[j].Set(offs,(qxybuf[j][j2]-xy[i][j2])*(qxybuf[j][j3]-xy[i][j3])); - offs=offs+1; - } - } - //--- change values - y[j]=qxybuf[j][nx]; - w[j]=1; - } - nc=1+nx+(int)MathRound(nx*(nx+1)*0.5); - } - //--- function call - IDWInternalSolver(y,w,fmatrix,temp,k,nc,info,qsol,taskrcond); - //--- Least squares models: copy results - if(info>0) - { - //--- LLS task is solved,copy results - z.m_debugworstrcond=MathMin(z.m_debugworstrcond,taskrcond); - z.m_debugbestrcond=MathMax(z.m_debugbestrcond,taskrcond); - for(j=0;j<=nc-1;j++) - z.m_q[i].Set(nx+j,qsol[j]); - } - else - { - //--- Solver failure,very strange,but we will use - //--- zero values to handle it. - z.m_debugsolverfailures=z.m_debugsolverfailures+1; - v=0; - for(j=0;j<=k-1;j++) - v=v+qxybuf[j][nx]; - z.m_q[i].Set(nx,v/k); - for(j=0;j<=nc-2;j++) - z.m_q[i].Set(nx+1+j,0); - } - } - } -//+------------------------------------------------------------------+ -//| Internal subroutine: K-th nodal function calculation | -//+------------------------------------------------------------------+ -static double CIDWInt::IDWCalcQ(CIDWInterpolant &z,double &x[],const int k) - { -//--- create variables - double result=0; - int nx=0; - int i=0; - int j=0; - int offs=0; -//--- initialization - nx=z.m_nx; -//--- constant member - result=z.m_q[k][nx]; -//--- linear members - if(z.m_d>=1) - { - for(i=0;i<=nx-1;i++) - result=result+z.m_q[k][nx+1+i]*(x[i]-z.m_q[k][i]); - } -//--- quadratic members - if(z.m_d>=2) - { - offs=nx+1+nx; - for(i=0;i<=nx-1;i++) - { - for(j=i;j<=nx-1;j++) - { - result=result+z.m_q[k][offs]*(x[i]-z.m_q[k][i])*(x[j]-z.m_q[k][j]); - offs=offs+1; - } - } - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Initialization of internal structures. | -//| It assumes correctness of all parameters. | -//+------------------------------------------------------------------+ -static void CIDWInt::IDWInit1(const int n,const int nx,const int d, - int nq,int nw,CIDWInterpolant &z) - { -//--- initialization - z.m_debugsolverfailures=0; - z.m_debugworstrcond=1.0; - z.m_debugbestrcond=0; - z.m_n=n; - z.m_nx=nx; - z.m_d=0; -//--- check - if(d==1) - z.m_d=1; -//--- check - if(d==2) - z.m_d=2; -//--- check - if(d==-1) - z.m_d=1; - z.m_nw=nw; -//--- check - if(d==-1) - z.m_q.Resize(n,2*nx+1); -//--- check - if(d==0) - z.m_q.Resize(n,nx+1); -//--- check - if(d==1) - z.m_q.Resize(n,2*nx+1); -//--- check - if(d==2) - z.m_q.Resize(n,nx+1+nx+(int)MathRound(nx*(nx+1)*0.5)); -//--- allocation - ArrayResizeAL(z.m_tbuf,nw); - ArrayResizeAL(z.m_rbuf,nw); - z.m_xybuf.Resize(nw,nx+1); - ArrayResizeAL(z.m_xbuf,nx); - } -//+------------------------------------------------------------------+ -//| Linear least squares solver for small tasks. | -//| Works faster than standard ALGLIB solver in non-degenerate | -//| cases (due to absense of internal allocations and optimized | -//| row/colums). In degenerate cases it calls standard solver, which| -//| results in small performance penalty associated with preliminary | -//| steps. | -//| INPUT PARAMETERS: | -//| Y array[0..N-1] | -//| W array[0..N-1] | -//| FMatrix array[0..N-1,0..M], have additional column for | -//| temporary values | -//| Temp array[0..N] | -//+------------------------------------------------------------------+ -static void CIDWInt::IDWInternalSolver(double &y[],double &w[],CMatrixDouble &fmatrix, - double &temp[],const int n,const int m, - int &info,double &x[],double &taskrcond) - { -//--- create variables - int i=0; - int j=0; - double v=0; - double tau=0; - int i_=0; - int i1_=0; -//--- create array - double b[]; -//--- object of class - CDenseSolverLSReport srep; -//--- set up info - info=1; -//--- prepare matrix - for(i=0;i<=n-1;i++) - { - fmatrix[i].Set(m,y[i]); - v=w[i]; - for(i_=0;i_<=m;i_++) - fmatrix[i].Set(i_,v*fmatrix[i][i_]); - } -//--- use either fast algorithm or general algorithm - if(m<=n) - { - //--- QR decomposition - //--- We assume that M<=N (we would have called LSFit() otherwise) - for(i=0;i<=m-1;i++) - { - //--- check - if(i10000*n*CMath::m_machineepsilon) - { - //--- solve triangular system R*x=FMatrix[0:M-1,M] - //--- using fast algorithm,then exit - x[m-1]=fmatrix[m-1][m]/fmatrix[m-1][m-1]; - for(i=m-2;i>=0;i--) - { - v=0.0; - for(i_=i+1;i_<=m-1;i_++) - v+=fmatrix[i][i_]*x[i_]; - x[i]=(fmatrix[i][m]-v)/fmatrix[i][i]; - } - } - else - { - //--- use more general algorithm - ArrayResizeAL(b,m); - for(i=0;i<=m-1;i++) - { - for(j=0;j<=i-1;j++) - fmatrix[i].Set(j,0.0); - b[i]=fmatrix[i][m]; - } - //--- function call - CDenseSolver::RMatrixSolveLS(fmatrix,m,m,b,10000*CMath::m_machineepsilon,info,srep,x); - } - } - else - { - //--- use more general algorithm - ArrayResizeAL(b,n); - for(i=0;i<=n-1;i++) - b[i]=fmatrix[i][m]; - //--- function call - CDenseSolver::RMatrixSolveLS(fmatrix,n,m,b,10000*CMath::m_machineepsilon,info,srep,x); - taskrcond=srep.m_r2; - } - } -//+------------------------------------------------------------------+ -//| Barycentric interpolant. | -//+------------------------------------------------------------------+ -class CBarycentricInterpolant - { -public: - //--- variables - int m_n; - double m_sy; - //--- arrays - double m_x[]; - double m_y[]; - double m_w[]; - //--- constructor, destructor - CBarycentricInterpolant(void); - ~CBarycentricInterpolant(void); - //--- copy - void Copy(CBarycentricInterpolant &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CBarycentricInterpolant::CBarycentricInterpolant(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CBarycentricInterpolant::~CBarycentricInterpolant(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CBarycentricInterpolant::Copy(CBarycentricInterpolant &obj) - { -//--- copy variables - m_n=obj.m_n; - m_sy=obj.m_sy; -//--- copy arrays - ArrayCopy(m_x,obj.m_x); - ArrayCopy(m_y,obj.m_y); - ArrayCopy(m_w,obj.m_w); - } -//+------------------------------------------------------------------+ -//| Barycentric interpolant. | -//+------------------------------------------------------------------+ -class CBarycentricInterpolantShell - { -private: - CBarycentricInterpolant m_innerobj; -public: - //--- constructor, destructor - CBarycentricInterpolantShell(void); - CBarycentricInterpolantShell(CBarycentricInterpolant &obj); - ~CBarycentricInterpolantShell(void); - //--- method - CBarycentricInterpolant *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CBarycentricInterpolantShell::CBarycentricInterpolantShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CBarycentricInterpolantShell::CBarycentricInterpolantShell(CBarycentricInterpolant &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CBarycentricInterpolantShell::~CBarycentricInterpolantShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CBarycentricInterpolant *CBarycentricInterpolantShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Rational interpolation | -//+------------------------------------------------------------------+ -class CRatInt - { -private: - //--- private method - static void BarycentricNormalize(CBarycentricInterpolant &b); -public: - //--- constructor, destructor - CRatInt(void); - ~CRatInt(void); - //--- public methods - static double BarycentricCalc(CBarycentricInterpolant &b,const double t); - static void BarycentricDiff1(CBarycentricInterpolant &b,double t,double &f,double &df); - static void BarycentricDiff2(CBarycentricInterpolant &b,const double t,double &f,double &df,double &d2f); - static void BarycentricLinTransX(CBarycentricInterpolant &b,const double ca,const double cb); - static void BarycentricLinTransY(CBarycentricInterpolant &b,const double ca,const double cb); - static void BarycentricUnpack(CBarycentricInterpolant &b,int &n,double &x[],double &y[],double &w[]); - static void BarycentricBuildXYW(double &x[],double &y[],double &w[],const int n,CBarycentricInterpolant &b); - static void BarycentricBuildFloaterHormann(double &x[],double &y[],const int n,int d,CBarycentricInterpolant &b); - static void BarycentricCopy(CBarycentricInterpolant &b,CBarycentricInterpolant &b2); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CRatInt::CRatInt(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CRatInt::~CRatInt(void) - { - - } -//+------------------------------------------------------------------+ -//| Rational interpolation using barycentric formula | -//| F(t)=SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i]))| -//| Input parameters: | -//| B - barycentric interpolant built with one of model | -//| building subroutines. | -//| T - interpolation point | -//| Result: | -//| barycentric interpolant F(t) | -//+------------------------------------------------------------------+ -static double CRatInt::BarycentricCalc(CBarycentricInterpolant &b,const double t) - { -//--- create variables - double s1=0; - double s2=0; - double s=0; - double v=0; - int i=0; -//--- check - if(!CAp::Assert(!CInfOrNaN::IsInfinity(t),__FUNCTION__+": infinite T!")) - return(EMPTY_VALUE); -//--- special case: NaN - if(CInfOrNaN::IsNaN(t)) - return(CInfOrNaN::NaN()); -//--- special case: N=1 - if(b.m_n==1) - return(b.m_sy*b.m_y[0]); -//--- Here we assume that task is normalized,i.m_e.: -//--- 1. abs(Y[i])<=1 -//--- 2. abs(W[i])<=1 -//--- 3. X[] is ordered - s=MathAbs(t-b.m_x[0]); - for(i=0;i<=b.m_n-1;i++) - { - v=b.m_x[i]; - //--- check - if(v==(double)(t)) - return(b.m_sy*b.m_y[i]); - v=MathAbs(t-v); - //--- check - if(v0.0,__FUNCTION__+": internal error")) - return; -//--- We assume than N>1 and B.SY>0. Find: -//--- 1. pivot point (X[i] closest to T) -//--- 2. width of interval containing X[i] - v=MathAbs(b.m_x[0]-t); - k=0; - xmin=b.m_x[0]; - xmax=b.m_x[0]; -//--- calculation - for(i=1;i<=b.m_n-1;i++) - { - vv=b.m_x[i]; - //--- check - if(MathAbs(vv-t)xprev,__FUNCTION__+": points are too close!")) - return; - xprev=xi; - //--- check - if(i!=k) - { - vv=CMath::Sqr(t-xi); - s0=(t-xk)/(t-xi); - s1=(xk-xi)/vv; - } - else - { - s0=1; - s1=0; - } - //--- change values - vv=b.m_w[i]*b.m_y[i]; - n0=n0+s0*vv; - n1=n1+s1*vv; - vv=b.m_w[i]; - d0=d0+s0*vv; - d1=d1+s1*vv; - } -//--- change values - f=b.m_sy*n0/d0; - df=(n1*d0-n0*d1)/CMath::Sqr(d0); -//--- check - if(df!=0.0) - df=MathSign(df)*MathExp(MathLog(MathAbs(df))+MathLog(b.m_sy)+MathLog(xscale1)+MathLog(xscale2)); - } -//+------------------------------------------------------------------+ -//| Differentiation of barycentric interpolant: first/second | -//| derivatives. | -//| INPUT PARAMETERS: | -//| B - barycentric interpolant built with one of model | -//| building subroutines. | -//| T - interpolation point | -//| OUTPUT PARAMETERS: | -//| F - barycentric interpolant at T | -//| DF - first derivative | -//| D2F - second derivative | -//| NOTE: this algorithm may fail due to overflow/underflor if used | -//| on data whose values are close to MaxRealNumber or MinRealNumber.| -//| Use more robust BarycentricDiff1() subroutine in such cases. | -//+------------------------------------------------------------------+ -static void CRatInt::BarycentricDiff2(CBarycentricInterpolant &b,const double t, - double &f,double &df,double &d2f) - { -//--- create variables - double v=0; - double vv=0; - int i=0; - int k=0; - double n0=0; - double n1=0; - double n2=0; - double d0=0; - double d1=0; - double d2=0; - double s0=0; - double s1=0; - double s2=0; - double xk=0; - double xi=0; -//--- initialization - f=0; - df=0; - d2f=0; -//--- check - if(!CAp::Assert(!CInfOrNaN::IsInfinity(t),__FUNCTION__+": infinite T!")) - return; -//--- special case: NaN - if(CInfOrNaN::IsNaN(t)) - { - //--- change values - f=CInfOrNaN::NaN(); - df=CInfOrNaN::NaN(); - d2f=CInfOrNaN::NaN(); - //--- exit the function - return; - } -//--- special case: N=1 - if(b.m_n==1) - { - //--- change values - f=b.m_sy*b.m_y[0]; - df=0; - d2f=0; - //--- exit the function - return; - } -//--- check - if(b.m_sy==0.0) - { - //--- change values - f=0; - df=0; - d2f=0; - //--- exit the function - return; - } -//--- We assume than N>1 and B.SY>0. Find: -//--- 1. pivot point (X[i] closest to T) -//--- 2. width of interval containing X[i] - if(!CAp::Assert(b.m_sy>0.0,__FUNCTION__+": internal error")) - return; -//--- change values - f=0; - df=0; - d2f=0; - v=MathAbs(b.m_x[0]-t); - k=0; - for(i=1;i<=b.m_n-1;i++) - { - vv=b.m_x[i]; - //--- check - if(MathAbs(vv-t)0 - for(i=0;i<=b.m_n-1;i++) - b.m_x[i]=(b.m_x[i]-cb)/ca; -//--- check - if(ca<0.0) - { - for(i=0;i<=b.m_n-1;i++) - { - //--- check - if(i0.0) - { - v=1/b.m_sy; - //--- calculation - for(i_=0;i_<=b.m_n-1;i_++) - b.m_y[i_]=v*b.m_y[i_]; - } - } -//+------------------------------------------------------------------+ -//| Extracts X/Y/W arrays from rational interpolant | -//| INPUT PARAMETERS: | -//| B - barycentric interpolant | -//| OUTPUT PARAMETERS: | -//| N - nodes count, N>0 | -//| X - interpolation nodes, array[0..N-1] | -//| F - function values, array[0..N-1] | -//| W - barycentric weights, array[0..N-1] | -//+------------------------------------------------------------------+ -static void CRatInt::BarycentricUnpack(CBarycentricInterpolant &b,int &n, - double &x[],double &y[],double &w[]) - { -//--- create variables - double v=0; - int i_=0; -//--- initialization - n=b.m_n; -//--- allocation - ArrayResizeAL(x,n); - ArrayResizeAL(y,n); - ArrayResizeAL(w,n); -//--- initialization - v=b.m_sy; -//--- copy - for(i_=0;i_<=n-1;i_++) - x[i_]=b.m_x[i_]; - for(i_=0;i_<=n-1;i_++) - y[i_]=v*b.m_y[i_]; - for(i_=0;i_<=n-1;i_++) - w[i_]=b.m_w[i_]; - } -//+------------------------------------------------------------------+ -//| Rational interpolant from X/Y/W arrays | -//| F(t)=SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i]))| -//| INPUT PARAMETERS: | -//| X - interpolation nodes, array[0..N-1] | -//| F - function values, array[0..N-1] | -//| W - barycentric weights, array[0..N-1] | -//| N - nodes count, N>0 | -//| OUTPUT PARAMETERS: | -//| B - barycentric interpolant built from (X, Y, W) | -//+------------------------------------------------------------------+ -static void CRatInt::BarycentricBuildXYW(double &x[],double &y[],double &w[], - const int n,CBarycentricInterpolant &b) - { -//--- create a variable - int i_=0; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": incorrect N!")) - return; -//--- fill X/Y/W - ArrayResizeAL(b.m_x,n); - ArrayResizeAL(b.m_y,n); - ArrayResizeAL(b.m_w,n); -//--- copy - for(i_=0;i_<=n-1;i_++) - b.m_x[i_]=x[i_]; - for(i_=0;i_<=n-1;i_++) - b.m_y[i_]=y[i_]; - for(i_=0;i_<=n-1;i_++) - b.m_w[i_]=w[i_]; - b.m_n=n; -//--- Normalize - BarycentricNormalize(b); - } -//+------------------------------------------------------------------+ -//| Rational interpolant without poles | -//| The subroutine constructs the rational interpolating function | -//| without real poles (see 'Barycentric rational interpolation with | -//| no poles and high rates of approximation', Michael S. Floater. | -//| and Kai Hormann, for more information on this subject). | -//| Input parameters: | -//| X - interpolation nodes, array[0..N-1]. | -//| Y - function values, array[0..N-1]. | -//| N - number of nodes, N>0. | -//| D - order of the interpolation scheme, 0 <= D <= N-1. | -//| D<0 will cause an error. | -//| D>=N it will be replaced with D=N-1. | -//| if you don't know what D to choose, use small value | -//| about 3-5. | -//| Output parameters: | -//| B - barycentric interpolant. | -//| Note: | -//| this algorithm always succeeds and calculates the weights | -//| with close to machine precision. | -//+------------------------------------------------------------------+ -static void CRatInt::BarycentricBuildFloaterHormann(double &x[],double &y[], - const int n,int d, - CBarycentricInterpolant &b) - { -//--- create variables - double s0=0; - double s=0; - double v=0; - int i=0; - int j=0; - int k=0; - int i_=0; -//--- create arrays - int perm[]; - double wtemp[]; - double sortrbuf[]; - double sortrbuf2[]; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(d>=0,__FUNCTION__+": incorrect D!")) - return; -//--- Prepare - if(d>n-1) - d=n-1; - b.m_n=n; -//--- special case: N=1 - if(n==1) - { - //--- allocation - ArrayResizeAL(b.m_x,n); - ArrayResizeAL(b.m_y,n); - ArrayResizeAL(b.m_w,n); - //--- change values - b.m_x[0]=x[0]; - b.m_y[0]=y[0]; - b.m_w[0]=1; - //--- function call - BarycentricNormalize(b); - //--- exit the function - return; - } -//--- Fill X/Y - ArrayResizeAL(b.m_x,n); - ArrayResizeAL(b.m_y,n); -//--- copy - for(i_=0;i_<=n-1;i_++) - b.m_x[i_]=x[i_]; - for(i_=0;i_<=n-1;i_++) - b.m_y[i_]=y[i_]; -//--- function call - CTSort::TagSortFastR(b.m_x,b.m_y,sortrbuf,sortrbuf2,n); -//--- Calculate Wk - ArrayResizeAL(b.m_w,n); - s0=1; - for(k=1;k<=d;k++) - s0=-s0; -//--- calculation - for(k=0;k<=n-1;k++) - { - //--- Wk - s=0; - for(i=(int)(MathMax(k-d,0));i<=MathMin(k,n-1-d);i++) - { - v=1; - for(j=i;j<=i+d;j++) - { - //--- check - if(j!=k) - v=v/MathAbs(b.m_x[k]-b.m_x[j]); - } - s=s+v; - } - b.m_w[k]=s0*s; - //--- Next S0 - s0=-s0; - } -//--- Normalize - BarycentricNormalize(b); - } -//+------------------------------------------------------------------+ -//| Copying of the barycentric interpolant (for internal use only) | -//| INPUT PARAMETERS: | -//| B - barycentric interpolant | -//| OUTPUT PARAMETERS: | -//| B2 - copy(B1) | -//+------------------------------------------------------------------+ -static void CRatInt::BarycentricCopy(CBarycentricInterpolant &b, - CBarycentricInterpolant &b2) - { -//--- create a variable - int i_=0; -//--- change values - b2.m_n=b.m_n; - b2.m_sy=b.m_sy; -//--- allocation - ArrayResizeAL(b2.m_x,b2.m_n); - ArrayResizeAL(b2.m_y,b2.m_n); - ArrayResizeAL(b2.m_w,b2.m_n); -//--- copy - for(i_=0;i_<=b2.m_n-1;i_++) - b2.m_x[i_]=b.m_x[i_]; - for(i_=0;i_<=b2.m_n-1;i_++) - b2.m_y[i_]=b.m_y[i_]; - for(i_=0;i_<=b2.m_n-1;i_++) - b2.m_w[i_]=b.m_w[i_]; - } -//+------------------------------------------------------------------+ -//| Normalization of barycentric interpolant: | -//| * B.N, B.X, B.Y and B.W are initialized | -//| * B.SY is NOT initialized | -//| * Y[] is normalized, scaling coefficient is stored in B.SY | -//| * W[] is normalized, no scaling coefficient is stored | -//| * X[] is sorted | -//| Internal subroutine. | -//+------------------------------------------------------------------+ -static void CRatInt::BarycentricNormalize(CBarycentricInterpolant &b) - { -//--- create variables - int i=0; - int j=0; - int j2=0; - double v=0; - int i_=0; -//--- create arrays - int p1[]; - int p2[]; -//--- Normalize task: |Y|<=1,|W|<=1,sort X[] - b.m_sy=0; - for(i=0;i<=b.m_n-1;i++) - b.m_sy=MathMax(b.m_sy,MathAbs(b.m_y[i])); -//--- check - if(b.m_sy>0.0 && MathAbs(b.m_sy-1)>10*CMath::m_machineepsilon) - { - v=1/b.m_sy; - for(i_=0;i_<=b.m_n-1;i_++) - b.m_y[i_]=v*b.m_y[i_]; - } -//--- change value - v=0; - for(i=0;i<=b.m_n-1;i++) - v=MathMax(v,MathAbs(b.m_w[i])); -//--- check - if(v>0.0 && MathAbs(v-1)>10*CMath::m_machineepsilon) - { - v=1/v; - for(i_=0;i_<=b.m_n-1;i_++) - b.m_w[i_]=v*b.m_w[i_]; - } - for(i=0;i<=b.m_n-2;i++) - { - //--- check - if(b.m_x[i+1]B | -//| OUTPUT PARAMETERS | -//| T - coefficients of Chebyshev representation; | -//| P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N-1 }, | -//| where Ti - I-th Chebyshev polynomial. | -//| NOTES: | -//| barycentric interpolant passed as P may be either polynomial | -//| obtained from polynomial interpolation/ fitting or rational | -//| function which is NOT polynomial. We can't distinguish | -//| between these two cases, and this algorithm just tries to | -//| work assuming that P IS a polynomial. If not, algorithm will | -//| return results, but they won't have any meaning. | -//+------------------------------------------------------------------+ -static void CPolInt::PolynomialBar2Cheb(CBarycentricInterpolant &p, - const double a,const double b, - double &t[]) - { -//--- create variables - int i=0; - int k=0; - double v=0; - int i_=0; -//--- create arrays - double vp[]; - double vx[]; - double tk[]; - double tk1[]; -//--- check - if(!CAp::Assert(CMath::IsFinite(a),__FUNCTION__+": A is not finite!")) - return; -//--- check - if(!CAp::Assert(CMath::IsFinite(b),__FUNCTION__+": B is not finite!")) - return; -//--- check - if(!CAp::Assert(a!=b,__FUNCTION__+": A=B!")) - return; -//--- check - if(!CAp::Assert(p.m_n>0,__FUNCTION__+": P is not correctly initialized barycentric interpolant!")) - return; -//--- Calculate function values on a Chebyshev grid - ArrayResizeAL(vp,p.m_n); - ArrayResizeAL(vx,p.m_n); - for(i=0;i<=p.m_n-1;i++) - { - vx[i]=MathCos(M_PI*(i+0.5)/p.m_n); - vp[i]=CRatInt::BarycentricCalc(p,0.5*(vx[i]+1)*(b-a)+a); - } -//--- T[0] - ArrayResizeAL(t,p.m_n); - v=0; - for(i=0;i<=p.m_n-1;i++) - v=v+vp[i]; - t[0]=v/p.m_n; -//--- other T's. -//--- NOTES: -//--- 1. TK stores T{k} on VX,TK1 stores T{k-1} on VX -//--- 2. we can do same calculations with fast DCT,but it -//--- * adds dependencies -//--- * still leaves us with O(N^2) algorithm because -//--- preparation of function values is O(N^2) process - if(p.m_n>1) - { - //--- allocation - ArrayResizeAL(tk,p.m_n); - ArrayResizeAL(tk1,p.m_n); - for(i=0;i<=p.m_n-1;i++) - { - tk[i]=vx[i]; - tk1[i]=1; - } - //--- calculation - for(k=1;k<=p.m_n-1;k++) - { - //--- calculate discrete product of function vector and TK - v=0.0; - for(i_=0;i_<=p.m_n-1;i_++) - v+=tk[i_]*vp[i_]; - t[k]=v/(0.5*p.m_n); - //--- Update TK and TK1 - for(i=0;i<=p.m_n-1;i++) - { - v=2*vx[i]*tk[i]-tk1[i]; - tk1[i]=tk[i]; - tk[i]=v; - } - } - } - } -//+------------------------------------------------------------------+ -//| Conversion from Chebyshev basis to barycentric representation. | -//| This function has O(N^2) complexity. | -//| INPUT PARAMETERS: | -//| T - coefficients of Chebyshev representation; | -//| P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N }, | -//| where Ti - I-th Chebyshev polynomial. | -//| N - number of coefficients: | -//| * if given, only leading N elements of T are used | -//| * if not given, automatically determined from size | -//| of T | -//| A,B - base interval for Chebyshev polynomials (see above) | -//| A=1,__FUNCTION__+": N<1")) - return; -//--- check - if(!CAp::Assert(CAp::Len(t)>=n,__FUNCTION__+": Length(T)0. | -//| OUTPUT PARAMETERS | -//| A - coefficients, | -//| P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } | -//| N - number of coefficients (polynomial degree plus 1) | -//| NOTES: | -//| 1. this function accepts offset and scale, which can be set to | -//| improve numerical properties of polynomial. For example, if | -//| P was obtained as result of interpolation on [-1,+1], you can| -//| set C=0 and S=1 and represent P as sum of 1, x, x^2, x^3 and | -//| so on. In most cases you it is exactly what you need. | -//| However, if your interpolation model was built on [999,1001],| -//| you will see significant growth of numerical errors when | -//| using {1, x, x^2, x^3} as basis. Representing P as sum of 1, | -//| (x-1000), (x-1000)^2, (x-1000)^3 will be better option. Such | -//| representation can be obtained by using 1000.0 as offset | -//| C and 1.0 as scale S. | -//| 2. power basis is ill-conditioned and tricks described above | -//| can't solve this problem completely. This function will | -//| return coefficients in any case, but for N>8 they will become| -//| unreliable. However, N's less than 5 are pretty safe. | -//| 3. barycentric interpolant passed as P may be either polynomial | -//| obtained from polynomial interpolation/ fitting or rational | -//| function which is NOT polynomial. We can't distinguish | -//| between these two cases, and this algorithm just tries to | -//| work assuming that P IS a polynomial. If not, algorithm will | -//| return results, but they won't have any meaning. | -//+------------------------------------------------------------------+ -static void CPolInt::PolynomialBar2Pow(CBarycentricInterpolant &p, - const double c,const double s, - double &a[]) - { -//--- create variables - int i=0; - int k=0; - double e=0; - double d=0; - double v=0; - int i_=0; -//--- create arrays - double vp[]; - double vx[]; - double tk[]; - double tk1[]; - double t[]; -//--- check - if(!CAp::Assert(CMath::IsFinite(c),__FUNCTION__+": C is not finite!")) - return; -//--- check - if(!CAp::Assert(CMath::IsFinite(s),__FUNCTION__+": S is not finite!")) - return; -//--- check - if(!CAp::Assert(s!=0.0,__FUNCTION__+": S=0!")) - return; -//--- check - if(!CAp::Assert(p.m_n>0,__FUNCTION__+": P is not correctly initialized barycentric interpolant!")) - return; -//--- Calculate function values on a Chebyshev grid - ArrayResizeAL(vp,p.m_n); - ArrayResizeAL(vx,p.m_n); - for(i=0;i<=p.m_n-1;i++) - { - vx[i]=MathCos(M_PI*(i+0.5)/p.m_n); - vp[i]=CRatInt::BarycentricCalc(p,s*vx[i]+c); - } -//--- T[0] - ArrayResizeAL(t,p.m_n); - v=0; - for(i=0;i<=p.m_n-1;i++) - v=v+vp[i]; - t[0]=v/p.m_n; -//--- other T's. -//--- NOTES: -//--- 1. TK stores T{k} on VX,TK1 stores T{k-1} on VX -//--- 2. we can do same calculations with fast DCT,but it -//--- * adds dependencies -//--- * still leaves us with O(N^2) algorithm because -//--- preparation of function values is O(N^2) process - if(p.m_n>1) - { - //--- allocation - ArrayResizeAL(tk,p.m_n); - ArrayResizeAL(tk1,p.m_n); - for(i=0;i<=p.m_n-1;i++) - { - tk[i]=vx[i]; - tk1[i]=1; - } - //--- calculation - for(k=1;k<=p.m_n-1;k++) - { - //--- calculate discrete product of function vector and TK - v=0.0; - for(i_=0;i_<=p.m_n-1;i_++) - v+=tk[i_]*vp[i_]; - t[k]=v/(0.5*p.m_n); - //--- Update TK and TK1 - for(i=0;i<=p.m_n-1;i++) - { - v=2*vx[i]*tk[i]-tk1[i]; - tk1[i]=tk[i]; - tk[i]=v; - } - } - } -//--- Convert from Chebyshev basis to power basis - ArrayResizeAL(a,p.m_n); - for(i=0;i<=p.m_n-1;i++) - a[i]=0; - d=0; -//--- calculation - for(i=0;i<=p.m_n-1;i++) - { - for(k=i;k<=p.m_n-1;k++) - { - e=a[k]; - a[k]=0; - //--- check - if(i<=1 && k==i) - a[k]=1; - else - { - //--- check - if(i!=0) - a[k]=2*d; - //--- check - if(k>i+1) - a[k]=a[k]-a[k-2]; - } - d=e; - } - //--- change values - d=a[i]; - e=0; - k=i; - //--- cycle - while(k<=p.m_n-1) - { - e=e+a[k]*t[k]; - k=k+2; - } - a[i]=e; - } - } -//+------------------------------------------------------------------+ -//| Conversion from power basis to barycentric representation. | -//| This function has O(N^2) complexity. | -//| INPUT PARAMETERS: | -//| A - coefficients, P(x)=sum { A[i]*((X-C)/S)^i, i=0..N-1 }| -//| N - number of coefficients (polynomial degree plus 1) | -//| * if given, only leading N elements of A are used | -//| * if not given, automatically determined from size | -//| of A | -//| C - offset (see below); 0.0 is used as default value. | -//| S - scale (see below); 1.0 is used as default value. | -//| S<>0. | -//| OUTPUT PARAMETERS | -//| P - polynomial in barycentric form | -//| NOTES: | -//| 1. this function accepts offset and scale, which can be set to | -//| improve numerical properties of polynomial. For example, if | -//| you interpolate on [-1,+1], you can set C=0 and S=1 and | -//| convert from sum of 1, x, x^2, x^3 and so on. In most cases | -//| you it is exactly what you need. | -//| However, if your interpolation model was built on [999,1001],| -//| you will see significant growth of numerical errors when | -//| using {1, x, x^2, x^3} as input basis. Converting from sum | -//| of 1, (x-1000), (x-1000)^2, (x-1000)^3 will be better option | -//| (you have to specify 1000.0 as offset C and 1.0 as scale S). | -//| 2. power basis is ill-conditioned and tricks described above | -//| can't solve this problem completely. This function will | -//| return barycentric model in any case, but for N>8 accuracy | -//| well degrade. However, N's less than 5 are pretty safe. | -//+------------------------------------------------------------------+ -static void CPolInt::PolynomialPow2Bar(double &a[],const int n,const double c, - const double s,CBarycentricInterpolant &p) - { -//--- create variables - int i=0; - int k=0; - double vx=0; - double vy=0; - double px=0; -//--- create array - double y[]; -//--- check - if(!CAp::Assert(CMath::IsFinite(c),__FUNCTION__+": C is not finite!")) - return; -//--- check - if(!CAp::Assert(CMath::IsFinite(s),__FUNCTION__+": S is not finite!")) - return; -//--- check - if(!CAp::Assert(s!=0.0,__FUNCTION__+": S is zero!")) - return; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1")) - return; -//--- check - if(!CAp::Assert(CAp::Len(a)>=n,__FUNCTION__+": Length(A)=1 | -//| OUTPUT PARAMETERS | -//| P - barycentric model which represents Lagrange | -//| interpolant (see ratint unit info and | -//| BarycentricCalc() description for more information). | -//+------------------------------------------------------------------+ -static void CPolInt::PolynomialBuild(double &cx[],double &cy[],const int n, - CBarycentricInterpolant &p) - { -//--- create variables - int j=0; - int k=0; - double b=0; - double a=0; - double v=0; - double mx=0; - int i_=0; -//--- create arrays - double w[]; - double sortrbuf[]; - double sortrbuf2[]; - double x[]; - double y[]; -//--- copy arrays - ArrayCopy(x,cx); - ArrayCopy(y,cy); -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(Y)=1 | -//| for N=1 a constant model is constructed. | -//| OUTPUT PARAMETERS | -//| P - barycentric model which represents Lagrange | -//| interpolant (see ratint unit info and | -//| BarycentricCalc() description for more information). | -//+------------------------------------------------------------------+ -static void CPolInt::PolynomialBuildEqDist(const double a,const double b, - double &y[],const int n, - CBarycentricInterpolant &p) - { -//--- create variables - int i=0; - double v=0; -//--- create arrays - double w[]; - double x[]; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(y)>=n,__FUNCTION__+": Length(Y)=1 | -//| for N=1 a constant model is constructed. | -//| OUTPUT PARAMETERS | -//| P - barycentric model which represents Lagrange | -//| interpolant (see ratint unit info and | -//| BarycentricCalc() description for more information). | -//+------------------------------------------------------------------+ -static void CPolInt::PolynomialBuildCheb1(const double a,const double b, - double &y[],const int n, - CBarycentricInterpolant &p) - { -//--- create variables - int i=0; - double v=0; - double t=0; -//--- create arrays - double w[]; - double x[]; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(y)>=n,__FUNCTION__+": Length(Y)=1 | -//| for N=1 a constant model is constructed. | -//| OUTPUT PARAMETERS | -//| P - barycentric model which represents Lagrange | -//| interpolant (see ratint unit info and | -//| BarycentricCalc() description for more information). | -//+------------------------------------------------------------------+ -static void CPolInt::PolynomialBuildCheb2(const double a,const double b, - double &y[],const int n, - CBarycentricInterpolant &p) - { -//--- create variables - int i=0; - double v=0; -//--- create arrays - double w[]; - double x[]; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(y)>=n,__FUNCTION__+": Length(Y)=1 | -//| for N=1 a constant model is constructed. | -//| T - position where P(x) is calculated | -//| RESULT | -//| value of the Lagrange interpolant at T | -//| IMPORTANT | -//| this function provides fast interface which is not | -//| overflow-safe nor it is very precise. | -//| the best option is to use PolynomialBuildEqDist() or | -//| BarycentricCalc() subroutines unless you are pretty sure that| -//| your data will not result in overflow. | -//+------------------------------------------------------------------+ -static double CPolInt::PolynomialCalcEqDist(const double a,const double b, - double &f[],const int n,const double t) - { -//--- create variables - double s1=0; - double s2=0; - double v=0; - double threshold=0; - double s=0; - double h=0; - int i=0; - int j=0; - double w=0; - double x=0; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": N<=0!")) - return(EMPTY_VALUE); -//--- check - if(!CAp::Assert(CAp::Len(f)>=n,__FUNCTION__+": Length(F)threshold) - { - //--- use fast formula - j=-1; - s=1.0; - } -//--- Calculate using safe or fast barycentric formula - s1=0; - s2=0; - w=1.0; - h=(b-a)/(n-1); -//--- calculation - for(i=0;i<=n-1;i++) - { - //--- check - if(i!=j) - { - v=s*w/(t-(a+i*h)); - s1=s1+v*f[i]; - s2=s2+v; - } - else - { - v=w; - s1=s1+v*f[i]; - s2=s2+v; - } - //--- change values - w=-(w*(n-1-i)); - w=w/(i+1); - } -//--- return result - return(s1/s2); - } -//+------------------------------------------------------------------+ -//| Fast polynomial interpolation function on Chebyshev points (first| -//| kind) with O(N) complexity. | -//| INPUT PARAMETERS: | -//| A - left boundary of [A,B] | -//| B - right boundary of [A,B] | -//| F - function values, array[0..N-1] | -//| N - number of points on Chebyshev grid (first kind), | -//| X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)) | -//| for N=1 a constant model is constructed. | -//| T - position where P(x) is calculated | -//| RESULT | -//| value of the Lagrange interpolant at T | -//| IMPORTANT | -//| this function provides fast interface which is not | -//| overflow-safe nor it is very precise | -//| the best option is to use PolIntBuildCheb1() or | -//| BarycentricCalc() subroutines unless you are pretty sure that| -//| your data will not result in overflow. | -//+------------------------------------------------------------------+ -static double CPolInt::PolynomialCalcCheb1(const double a,const double b, - double &f[],const int n,double t) - { -//--- create variables - double s1=0; - double s2=0; - double v=0; - double threshold=0; - double s=0; - int i=0; - int j=0; - double a0=0; - double delta=0; - double alpha=0; - double beta=0; - double ca=0; - double sa=0; - double tempc=0; - double temps=0; - double x=0; - double w=0; - double p1=0; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": N<=0!")) - return(EMPTY_VALUE); -//--- check - if(!CAp::Assert(CAp::Len(f)>=n,__FUNCTION__+": Length(F)threshold) - { - //--- use fast formula - j=-1; - s=1.0; - } -//--- Calculate using safe or fast barycentric formula - s1=0; - s2=0; - ca=MathCos(a0); - sa=MathSin(a0); - p1=1.0; -//--- calculation - for(i=0;i<=n-1;i++) - { - //--- Calculate X[i],W[i] - x=ca; - w=p1*sa; - //--- Proceed - if(i!=j) - { - v=s*w/(t-x); - s1=s1+v*f[i]; - s2=s2+v; - } - else - { - v=w; - s1=s1+v*f[i]; - s2=s2+v; - } - //--- Next CA,SA,P1 - temps=sa-(alpha*sa-beta*ca); - tempc=ca-(alpha*ca+beta*sa); - sa=temps; - ca=tempc; - p1=-p1; - } -//--- return result - return(s1/s2); - } -//+------------------------------------------------------------------+ -//| Fast polynomial interpolation function on Chebyshev points | -//| (second kind) with O(N) complexity. | -//| INPUT PARAMETERS: | -//| A - left boundary of [A,B] | -//| B - right boundary of [A,B] | -//| F - function values, array[0..N-1] | -//| N - number of points on Chebyshev grid (second kind), | -//| X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)) | -//| for N=1 a constant model is constructed. | -//| T - position where P(x) is calculated | -//| RESULT | -//| value of the Lagrange interpolant at T | -//| IMPORTANT | -//| this function provides fast interface which is not | -//| overflow-safe nor it is very precise. | -//| the best option is to use PolIntBuildCheb2() or | -//| BarycentricCalc() subroutines unless you are pretty sure that| -//| your data will not result in overflow. | -//+------------------------------------------------------------------+ -static double CPolInt::PolynomialCalcCheb2(const double a,const double b, - double &f[],const int n,double t) - { -//--- create variables - double s1=0; - double s2=0; - double v=0; - double threshold=0; - double s=0; - int i=0; - int j=0; - double a0=0; - double delta=0; - double alpha=0; - double beta=0; - double ca=0; - double sa=0; - double tempc=0; - double temps=0; - double x=0; - double w=0; - double p1=0; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": N<=0!")) - return(EMPTY_VALUE); -//--- check - if(!CAp::Assert(CAp::Len(f)>=n,__FUNCTION__+": Length(F)threshold) - { - //--- use fast formula - j=-1; - s=1.0; - } -//--- Calculate using safe or fast barycentric formula - s1=0; - s2=0; - ca=MathCos(a0); - sa=MathSin(a0); - p1=1.0; -//--- calculation - for(i=0;i<=n-1;i++) - { - //--- Calculate X[i],W[i] - x=ca; - //--- check - if(i==0 || i==n-1) - w=0.5*p1; - else - w=1.0*p1; - //--- Proceed - if(i!=j) - { - v=s*w/(t-x); - s1=s1+v*f[i]; - s2=s2+v; - } - else - { - v=w; - s1=s1+v*f[i]; - s2=s2+v; - } - //--- Next CA,SA,P1 - temps=sa-(alpha*sa-beta*ca); - tempc=ca-(alpha*ca+beta*sa); - sa=temps; - ca=tempc; - p1=-p1; - } -//--- return result - return(s1/s2); - } -//+------------------------------------------------------------------+ -//| 1-dimensional spline inteprolant | -//+------------------------------------------------------------------+ -class CSpline1DInterpolant - { -public: - //--- variables - bool m_periodic; - int m_n; - int m_k; - //--- arrays - double m_x[]; - double m_c[]; - //--- constructor, destructor - CSpline1DInterpolant(void); - ~CSpline1DInterpolant(void); - //--- copy - void Copy(CSpline1DInterpolant &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CSpline1DInterpolant::CSpline1DInterpolant(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSpline1DInterpolant::~CSpline1DInterpolant(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CSpline1DInterpolant::Copy(CSpline1DInterpolant &obj) - { -//--- copy variables - m_periodic=obj.m_periodic; - m_n=obj.m_n; - m_k=obj.m_k; -//--- copy arrays - ArrayCopy(m_x,obj.m_x); - ArrayCopy(m_c,obj.m_c); - } -//+------------------------------------------------------------------+ -//| 1-dimensional spline inteprolant | -//+------------------------------------------------------------------+ -class CSpline1DInterpolantShell - { -private: - CSpline1DInterpolant m_innerobj; -public: - //--- constructors, destructor - CSpline1DInterpolantShell(void); - CSpline1DInterpolantShell(CSpline1DInterpolant &obj); - ~CSpline1DInterpolantShell(void); - //--- method - CSpline1DInterpolant *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CSpline1DInterpolantShell::CSpline1DInterpolantShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CSpline1DInterpolantShell::CSpline1DInterpolantShell(CSpline1DInterpolant &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSpline1DInterpolantShell::~CSpline1DInterpolantShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CSpline1DInterpolant *CSpline1DInterpolantShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| 1-dimensional spline interpolation | -//+------------------------------------------------------------------+ -class CSpline1D - { -private: - //--- private methods - static void Spline1DGridDiffCubicInternal(double &x[],double &y[],const int n,const int boundltype,const double boundl,const int boundrtype,const double boundr,double &d[],double &a1[],double &a2[],double &a3[],double &b[],double &dt[]); - static void HeapSortPoints(double &x[],double &y[],const int n); - static void HeapSortPPoints(double &x[],double &y[],int &p[],const int n); - static void SolveTridiagonal(double &a[],double &cb[],double &c[],double &cd[],const int n,double &x[]); - static void SolveCyclicTridiagonal(double &a[],double &cb[],double &c[],double &d[],const int n,double &x[]); - static double DiffThreePoint(double t,const double x0,const double f0,double x1,const double f1,double x2,const double f2); -public: - //--- constructor, destructor - CSpline1D(void); - ~CSpline1D(void); - //--- public methods - static void Spline1DBuildLinear(double &cx[],double &cy[],const int n,CSpline1DInterpolant &c); - static void Spline1DBuildCubic(double &cx[],double &cy[],const int n,const int boundltype,const double boundl,const int boundrtype,const double boundr,CSpline1DInterpolant &c); - static void Spline1DGridDiffCubic(double &cx[],double &cy[],const int n,const int boundltype,const double boundl,const int boundrtype,const double boundr,double &d[]); - static void Spline1DGridDiff2Cubic(double &cx[],double &cy[],const int n,const int boundltype,const double boundl,const int boundrtype,const double boundr,double &d1[],double &d2[]); - static void Spline1DConvCubic(double &cx[],double &cy[],const int n,const int boundltype,const double boundl,const int boundrtype,const double boundr,double &cx2[],const int n2,double &y2[]); - static void Spline1DConvDiffCubic(double &cx[],double &cy[],const int n,const int boundltype,const double boundl,const int boundrtype,const double boundr,double &cx2[],const int n2,double &y2[],double &d2[]); - static void Spline1DConvDiff2Cubic(double &cx[],double &cy[],const int n,const int boundltype,const double boundl,const int boundrtype,const double boundr,double &cx2[],const int n2,double &y2[],double &d2[],double &dd2[]); - static void Spline1DBuildCatmullRom(double &cx[],double &cy[],const int n,const int boundtype,const double tension,CSpline1DInterpolant &c); - static void Spline1DBuildHermite(double &cx[],double &cy[],double &cd[],const int n,CSpline1DInterpolant &c); - static void Spline1DBuildAkima(double &cx[],double &cy[],const int n,CSpline1DInterpolant &c); - static double Spline1DCalc(CSpline1DInterpolant &c,double x); - static void Spline1DDiff(CSpline1DInterpolant &c,double x,double &s,double &ds,double &d2s); - static void Spline1DCopy(CSpline1DInterpolant &c,CSpline1DInterpolant &cc); - static void Spline1DUnpack(CSpline1DInterpolant &c,int &n,CMatrixDouble &tbl); - static void Spline1DLinTransX(CSpline1DInterpolant &c,const double a,const double b); - static void Spline1DLinTransY(CSpline1DInterpolant &c,const double a,const double b); - static double Spline1DIntegrate(CSpline1DInterpolant &c,double x); - static void Spline1DConvDiffInternal(double &xold[],double &yold[],double &dold[],const int n,double &x2[],const int n2,double &y[],const bool needy,double &d1[],const bool needd1,double &d2[],const bool needd2); - static void HeapSortDPoints(double &x[],double &y[],double &d[],const int n); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CSpline1D::CSpline1D(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSpline1D::~CSpline1D(void) - { - - } -//+------------------------------------------------------------------+ -//| This subroutine builds linear spline interpolant | -//| INPUT PARAMETERS: | -//| X - spline nodes, array[0..N-1] | -//| Y - function values, array[0..N-1] | -//| N - points count (optional): | -//| * N>=2 | -//| * if given, only first N points are used to build | -//| spline | -//| * if not given, automatically detected from X/Y | -//| sizes (len(X) must be equal to len(Y)) | -//| OUTPUT PARAMETERS: | -//| C - spline interpolant | -//| ORDER OF POINTS | -//| Subroutine automatically sorts points, so caller may pass | -//| unsorted array. | -//+------------------------------------------------------------------+ -static void CSpline1D::Spline1DBuildLinear(double &cx[],double &cy[], - const int n,CSpline1DInterpolant &c) - { -//--- create a variable - int i=0; -//--- create arrays - double x[]; - double y[]; -//--- copy arrays - ArrayCopy(x,cx); - ArrayCopy(y,cy); -//--- check - if(!CAp::Assert(n>1,__FUNCTION__+": N<2!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(Y)=2 | -//| * if given, only first N points are used to | -//| build spline | -//| * if not given, automatically detected from | -//| X/Y sizes (len(X) must be equal to len(Y)) | -//| BoundLType - boundary condition type for the left boundary| -//| BoundL - left boundary condition (first or second | -//| derivative, depending on the BoundLType) | -//| BoundRType - boundary condition type for the right | -//| boundary | -//| BoundR - right boundary condition (first or second | -//| derivative, depending on the BoundRType) | -//| OUTPUT PARAMETERS: | -//| C - spline interpolant | -//| ORDER OF POINTS | -//| Subroutine automatically sorts points, so caller may pass | -//| unsorted array. | -//| SETTING BOUNDARY VALUES: | -//| The BoundLType/BoundRType parameters can have the following | -//| values: | -//| * -1, which corresonds to the periodic (cyclic) boundary | -//| conditions. In this case: | -//| * both BoundLType and BoundRType must be equal to -1. | -//| * BoundL/BoundR are ignored | -//| * Y[last] is ignored (it is assumed to be equal to | -//| Y[first]). | -//| * 0, which corresponds to the parabolically terminated | -//| spline (BoundL and/or BoundR are ignored). | -//| * 1, which corresponds to the first derivative boundary | -//| condition | -//| * 2, which corresponds to the second derivative boundary | -//| condition | -//| * by default, BoundType=0 is used | -//| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: | -//| Problems with periodic boundary conditions have | -//| Y[first_point]=Y[last_point]. However, this subroutine doesn't | -//| require you to specify equal values for the first and last | -//| points - it automatically forces them to be equal by copying | -//| Y[first_point] (corresponds to the leftmost, minimal X[]) to | -//| Y[last_point]. However it is recommended to pass consistent | -//| values of Y[], i.e. to make Y[first_point]=Y[last_point]. | -//+------------------------------------------------------------------+ -static void CSpline1D::Spline1DBuildCubic(double &cx[],double &cy[], - const int n,const int boundltype, - const double boundl,const int boundrtype, - const double boundr,CSpline1DInterpolant &c) - { -//--- create a variable - int ylen=0; -//--- create arrays - double a1[]; - double a2[]; - double a3[]; - double b[]; - double dt[]; - double d[]; - int p[]; - double x[]; - double y[]; -//--- copy arrays - ArrayCopy(x,cx); - ArrayCopy(y,cy); -//--- check correctness of boundary conditions - if(!CAp::Assert(((boundltype==-1 || boundltype==0) || boundltype==1) || boundltype==2,__FUNCTION__+": incorrect BoundLType!")) - return; -//--- check - if(!CAp::Assert(((boundrtype==-1 || boundrtype==0) || boundrtype==1) || boundrtype==2,__FUNCTION__+": incorrect BoundRType!")) - return; -//--- check - if(!CAp::Assert((boundrtype==-1 && boundltype==-1) || (boundrtype!=-1 && boundltype!=-1),__FUNCTION__+": incorrect BoundLType/BoundRType!")) - return; -//--- check - if(boundltype==1 || boundltype==2) - { - //--- check - if(!CAp::Assert(CMath::IsFinite(boundl),__FUNCTION__+": BoundL is infinite or NAN!")) - return; - } -//--- check - if(boundrtype==1 || boundrtype==2) - { - //--- check - if(!CAp::Assert(CMath::IsFinite(boundr),__FUNCTION__+": BoundR is infinite or NAN!")) - return; - } -//--- check lengths of arguments - if(!CAp::Assert(n>=2,__FUNCTION__+": N<2!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(Y)=2 | -//| * if given, only first N points are used | -//| * if not given, automatically detected from | -//| X/Y sizes (len(X) must be equal to len(Y)) | -//| BoundLType - boundary condition type for the left boundary| -//| BoundL - left boundary condition (first or second | -//| derivative, depending on the BoundLType) | -//| BoundRType - boundary condition type for the right | -//| boundary | -//| BoundR - right boundary condition (first or second | -//| derivative, depending on the BoundRType) | -//| OUTPUT PARAMETERS: | -//| D - derivative values at X[] | -//| ORDER OF POINTS | -//| Subroutine automatically sorts points, so caller may pass | -//| unsorted array. Derivative values are correctly reordered on | -//| return, so D[I] is always equal to S'(X[I]) independently of | -//| points order. | -//| SETTING BOUNDARY VALUES: | -//| The BoundLType/BoundRType parameters can have the following | -//| values: | -//| * -1, which corresonds to the periodic (cyclic) boundary | -//| conditions. In this case: | -//| * both BoundLType and BoundRType must be equal to -1. | -//| * BoundL/BoundR are ignored | -//| * Y[last] is ignored (it is assumed to be equal to | -//| Y[first]). | -//| * 0, which corresponds to the parabolically terminated | -//| spline (BoundL and/or BoundR are ignored). | -//| * 1, which corresponds to the first derivative boundary | -//| condition | -//| * 2, which corresponds to the second derivative boundary | -//| condition | -//| * by default, BoundType=0 is used | -//| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: | -//| Problems with periodic boundary conditions have | -//| Y[first_point]=Y[last_point]. However, this subroutine doesn't | -//| require you to specify equal values for the first and last | -//| points - it automatically forces them to be equal by copying | -//| Y[first_point] (corresponds to the leftmost, minimal X[]) to | -//| Y[last_point]. However it is recommended to pass consistent | -//| values of Y[], i.e. to make Y[first_point]=Y[last_point]. | -//+------------------------------------------------------------------+ -static void CSpline1D::Spline1DGridDiffCubic(double &cx[],double &cy[], - const int n,const int boundltype, - const double boundl,const int boundrtype, - const double boundr,double &d[]) - { -//--- create variables - int i=0; - int ylen=0; - int i_=0; -//--- create arrays - double a1[]; - double a2[]; - double a3[]; - double b[]; - double dt[]; - int p[]; - double x[]; - double y[]; -//--- copy arrays - ArrayCopy(x,cx); - ArrayCopy(y,cy); -//--- check correctness of boundary conditions - if(!CAp::Assert(((boundltype==-1 || boundltype==0) || boundltype==1) || boundltype==2,__FUNCTION__+": incorrect BoundLType!")) - return; -//--- check - if(!CAp::Assert(((boundrtype==-1 || boundrtype==0) || boundrtype==1) || boundrtype==2,__FUNCTION__+": incorrect BoundRType!")) - return; -//--- check - if(!CAp::Assert((boundrtype==-1 && boundltype==-1) || (boundrtype!=-1 && boundltype!=-1),__FUNCTION__+": incorrect BoundLType/BoundRType!")) - return; -//--- check - if(boundltype==1 || boundltype==2) - { - //--- check - if(!CAp::Assert(CMath::IsFinite(boundl),__FUNCTION__+": BoundL is infinite or NAN!")) - return; - } -//--- check - if(boundrtype==1 || boundrtype==2) - { - //--- check - if(!CAp::Assert(CMath::IsFinite(boundr),__FUNCTION__+": BoundR is infinite or NAN!")) - return; - } -//--- check lengths of arguments - if(!CAp::Assert(n>=2,__FUNCTION__+": N<2!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(Y)=2 | -//| * if given, only first N points are used | -//| * if not given, automatically detected from | -//| X/Y sizes (len(X) must be equal to len(Y)) | -//| BoundLType - boundary condition type for the left boundary| -//| BoundL - left boundary condition (first or second | -//| derivative, depending on the BoundLType) | -//| BoundRType - boundary condition type for the right | -//| boundary | -//| BoundR - right boundary condition (first or second | -//| derivative, depending on the BoundRType) | -//| OUTPUT PARAMETERS: | -//| D1 - S' values at X[] | -//| D2 - S'' values at X[] | -//| ORDER OF POINTS | -//| Subroutine automatically sorts points, so caller may pass | -//| unsorted array. Derivative values are correctly reordered on | -//| return, so D[I] is always equal to S'(X[I]) independently of | -//| points order. | -//| SETTING BOUNDARY VALUES: | -//| The BoundLType/BoundRType parameters can have the following | -//| values: | -//| * -1, which corresonds to the periodic (cyclic) boundary | -//| conditions. In this case: | -//| * both BoundLType and BoundRType must be equal to -1. | -//| * BoundL/BoundR are ignored | -//| * Y[last] is ignored (it is assumed to be equal to | -//| Y[first]). | -//| * 0, which corresponds to the parabolically terminated | -//| spline (BoundL and/or BoundR are ignored). | -//| * 1, which corresponds to the first derivative boundary | -//| condition | -//| * 2, which corresponds to the second derivative boundary | -//| condition | -//| * by default, BoundType=0 is used | -//| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: | -//| Problems with periodic boundary conditions have | -//| Y[first_point]=Y[last_point]. | -//| However, this subroutine doesn't require you to specify equal | -//| values for the first and last points - it automatically forces | -//| them to be equal by copying Y[first_point] (corresponds to the | -//| leftmost, minimal X[]) to Y[last_point]. However it is | -//| recommended to pass consistent values of Y[], i.e. to make | -//| Y[first_point]=Y[last_point]. | -//+------------------------------------------------------------------+ -static void CSpline1D::Spline1DGridDiff2Cubic(double &cx[],double &cy[], - const int n,const int boundltype, - const double boundl,const int boundrtype, - const double boundr,double &d1[],double &d2[]) - { -//--- create variables - int i=0; - int ylen=0; - double delta=0; - double delta2=0; - double delta3=0; - double s0=0; - double s1=0; - double s2=0; - double s3=0; - int i_=0; -//--- create arrays - double a1[]; - double a2[]; - double a3[]; - double b[]; - double dt[]; - int p[]; - double x[]; - double y[]; -//--- copy arrays - ArrayCopy(x,cx); - ArrayCopy(y,cy); -//--- check correctness of boundary conditions - if(!CAp::Assert(((boundltype==-1 || boundltype==0) || boundltype==1) || boundltype==2,__FUNCTION__+": incorrect BoundLType!")) - return; -//--- check - if(!CAp::Assert(((boundrtype==-1 || boundrtype==0) || boundrtype==1) || boundrtype==2,__FUNCTION__+": incorrect BoundRType!")) - return; -//--- check - if(!CAp::Assert((boundrtype==-1 && boundltype==-1) || (boundrtype!=-1 && boundltype!=-1),__FUNCTION__+": incorrect BoundLType/BoundRType!")) - return; -//--- check - if(boundltype==1 || boundltype==2) - { - //--- check - if(!CAp::Assert(CMath::IsFinite(boundl),__FUNCTION__+": BoundL is infinite or NAN!")) - return; - } -//--- check - if(boundrtype==1 || boundrtype==2) - { - //--- check - if(!CAp::Assert(CMath::IsFinite(boundr),__FUNCTION__+": BoundR is infinite or NAN!")) - return; - } -//--- check lengths of arguments - if(!CAp::Assert(n>=2,__FUNCTION__+": N<2!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(Y)=2 | -//| * if given, only first N points from X/Y are | -//| used | -//| * if not given, automatically detected from | -//| X/Y sizes (len(X) must be equal to len(Y)) | -//| BoundLType - boundary condition type for the left boundary| -//| BoundL - left boundary condition (first or second | -//| derivative, depending on the BoundLType) | -//| BoundRType - boundary condition type for the right | -//| boundary | -//| BoundR - right boundary condition (first or second | -//| derivative, depending on the BoundRType) | -//| N2 - new points count: | -//| * N2>=2 | -//| * if given, only first N2 points from X2 are | -//| used | -//| * if not given, automatically detected from | -//| X2 size | -//| OUTPUT PARAMETERS: | -//| F2 - function values at X2[] | -//| ORDER OF POINTS | -//| Subroutine automatically sorts points, so caller may pass | -//| unsorted array. Function values are correctly reordered on | -//| return, so F2[I] is always equal to S(X2[I]) independently of | -//| points order. | -//| SETTING BOUNDARY VALUES: | -//| The BoundLType/BoundRType parameters can have the following | -//| values: | -//| * -1, which corresonds to the periodic (cyclic) boundary | -//| conditions. In this case: | -//| * both BoundLType and BoundRType must be equal to -1. | -//| * BoundL/BoundR are ignored | -//| * Y[last] is ignored (it is assumed to be equal to | -//| Y[first]). | -//| * 0, which corresponds to the parabolically terminated | -//| spline (BoundL and/or BoundR are ignored). | -//| * 1, which corresponds to the first derivative boundary | -//| condition | -//| * 2, which corresponds to the second derivative boundary | -//| condition | -//| * by default, BoundType=0 is used | -//| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: | -//| Problems with periodic boundary conditions have | -//| Y[first_point]=Y[last_point]. However, this subroutine doesn't | -//| require you to specify equal values for the first and last | -//| points - it automatically forces them to be equal by copying | -//| Y[first_point] (corresponds to the leftmost, minimal X[]) to | -//| Y[last_point]. However it is recommended to pass consistent | -//| values of Y[], i.e. to make Y[first_point]=Y[last_point]. | -//+------------------------------------------------------------------+ -static void CSpline1D::Spline1DConvCubic(double &cx[],double &cy[], - const int n,const int boundltype, - const double boundl,const int boundrtype, - const double boundr,double &cx2[], - const int n2,double &y2[]) - { -//--- create variables - int i=0; - int ylen=0; - double t=0; - double t2=0; - int i_=0; -//--- create arrays - double a1[]; - double a2[]; - double a3[]; - double b[]; - double d[]; - double dt[]; - double d1[]; - double d2[]; - int p[]; - int p2[]; - double x[]; - double y[]; - double x2[]; -//--- copy arrays - ArrayCopy(x,cx); - ArrayCopy(y,cy); - ArrayCopy(x2,cx2); -//--- check correctness of boundary conditions - if(!CAp::Assert(((boundltype==-1 || boundltype==0) || boundltype==1) || boundltype==2,__FUNCTION__+": incorrect BoundLType!")) - return; -//--- check - if(!CAp::Assert(((boundrtype==-1 || boundrtype==0) || boundrtype==1) || boundrtype==2,__FUNCTION__+": incorrect BoundRType!")) - return; -//--- check - if(!CAp::Assert((boundrtype==-1 && boundltype==-1) || (boundrtype!=-1 && boundltype!=-1),__FUNCTION__+": incorrect BoundLType/BoundRType!")) - return; -//--- check - if(boundltype==1 || boundltype==2) - { - //--- check - if(!CAp::Assert(CMath::IsFinite(boundl),__FUNCTION__+": BoundL is infinite or NAN!")) - return; - } -//--- check - if(boundrtype==1 || boundrtype==2) - { - //--- check - if(!CAp::Assert(CMath::IsFinite(boundr),__FUNCTION__+": BoundR is infinite or NAN!")) - return; - } -//--- check lengths of arguments - if(!CAp::Assert(n>=2,__FUNCTION__+": N<2!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(Y)=2,__FUNCTION__+": N2<2!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x2)>=n2,__FUNCTION__+": Length(X2)=n2,__FUNCTION__+": internal error!")) - return; -//--- copy - for(i=0;i<=n2-1;i++) - dt[p2[i]]=y2[i]; - for(i_=0;i_<=n2-1;i_++) - y2[i_]=dt[i_]; - } -//+------------------------------------------------------------------+ -//| This function solves following problem: given table y[] of | -//| function values at old nodes x[] and new nodes x2[], it | -//| calculates and returns table of function values y2[] and | -//| derivatives d2[] (calculated at x2[]). | -//| This function yields same result as Spline1DBuildCubic() call | -//| followed by sequence of Spline1DDiff() calls, but it can be | -//| several times faster when called for ordered X[] and X2[]. | -//| INPUT PARAMETERS: | -//| X - old spline nodes | -//| Y - function values | -//| X2 - new spline nodes | -//| OPTIONAL PARAMETERS: | -//| N - points count: | -//| * N>=2 | -//| * if given, only first N points from X/Y are | -//| used | -//| * if not given, automatically detected from | -//| X/Y sizes (len(X) must be equal to len(Y)) | -//| BoundLType - boundary condition type for the left boundary| -//| BoundL - left boundary condition (first or second | -//| derivative, depending on the BoundLType) | -//| BoundRType - boundary condition type for the right | -//| boundary | -//| BoundR - right boundary condition (first or second | -//| derivative, depending on the BoundRType) | -//| N2 - new points count: | -//| * N2>=2 | -//| * if given, only first N2 points from X2 are | -//| used | -//| * if not given, automatically detected from | -//| X2 size | -//| OUTPUT PARAMETERS: | -//| F2 - function values at X2[] | -//| D2 - first derivatives at X2[] | -//| ORDER OF POINTS | -//| Subroutine automatically sorts points, so caller may pass | -//| unsorted array. Function values are correctly reordered on | -//| return, so F2[I] is always equal to S(X2[I]) independently of | -//| points order. | -//| SETTING BOUNDARY VALUES: | -//| The BoundLType/BoundRType parameters can have the following | -//| values: | -//| * -1, which corresonds to the periodic (cyclic) boundary | -//| conditions. In this case: | -//| * both BoundLType and BoundRType must be equal to -1. | -//| * BoundL/BoundR are ignored | -//| * Y[last] is ignored (it is assumed to be equal to | -//| Y[first]). | -//| * 0, which corresponds to the parabolically terminated | -//| spline (BoundL and/or BoundR are ignored). | -//| * 1, which corresponds to the first derivative boundary | -//| condition | -//| * 2, which corresponds to the second derivative boundary | -//| condition | -//| * by default, BoundType=0 is used | -//| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: | -//| Problems with periodic boundary conditions have | -//| Y[first_point]=Y[last_point]. However, this subroutine doesn't | -//| require you to specify equal values for the first and last | -//| points - it automatically forces them to be equal by copying | -//| Y[first_point] (corresponds to the leftmost, minimal X[]) to | -//| Y[last_point]. However it is recommended to pass consistent | -//| values of Y[], i.e. to make Y[first_point]=Y[last_point]. | -//+------------------------------------------------------------------+ -static void CSpline1D::Spline1DConvDiffCubic(double &cx[],double &cy[], - const int n,const int boundltype, - const double boundl,const int boundrtype, - const double boundr,double &cx2[], - const int n2,double &y2[],double &d2[]) - { -//--- create variables - int i=0; - int ylen=0; - double t=0; - double t2=0; - int i_=0; -//--- create arrays - double a1[]; - double a2[]; - double a3[]; - double b[]; - double d[]; - double dt[]; - double rt1[]; - int p[]; - int p2[]; - double x[]; - double y[]; - double x2[]; -//--- copy arrays - ArrayCopy(x,cx); - ArrayCopy(y,cy); - ArrayCopy(x2,cx2); -//--- check correctness of boundary conditions - if(!CAp::Assert(((boundltype==-1 || boundltype==0) || boundltype==1) || boundltype==2,__FUNCTION__+": incorrect BoundLType!")) - return; -//--- check - if(!CAp::Assert(((boundrtype==-1 || boundrtype==0) || boundrtype==1) || boundrtype==2,__FUNCTION__+": incorrect BoundRType!")) - return; -//--- check - if(!CAp::Assert((boundrtype==-1 && boundltype==-1) || (boundrtype!=-1 && boundltype!=-1),__FUNCTION__+": incorrect BoundLType/BoundRType!")) - return; -//--- check - if(boundltype==1 || boundltype==2) - { - //--- check - if(!CAp::Assert(CMath::IsFinite(boundl),__FUNCTION__+": BoundL is infinite or NAN!")) - return; - } -//--- check - if(boundrtype==1 || boundrtype==2) - { - //--- check - if(!CAp::Assert(CMath::IsFinite(boundr),__FUNCTION__+": BoundR is infinite or NAN!")) - return; - } -//--- check lengths of arguments - if(!CAp::Assert(n>=2,__FUNCTION__+": N<2!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(Y)=2,__FUNCTION__+"Spline1DConvDiffCubic: N2<2!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x2)>=n2,__FUNCTION__+": Length(X2)=n2,__FUNCTION__+": internal error!")) - return; -//--- copy - for(i=0;i<=n2-1;i++) - dt[p2[i]]=y2[i]; - for(i_=0;i_<=n2-1;i_++) - y2[i_]=dt[i_]; - for(i=0;i<=n2-1;i++) - dt[p2[i]]=d2[i]; - for(i_=0;i_<=n2-1;i_++) - d2[i_]=dt[i_]; - } -//+------------------------------------------------------------------+ -//| This function solves following problem: given table y[] of | -//| function values at old nodes x[] and new nodes x2[], it | -//| calculates and returns table of function values y2[], first and | -//| second derivatives d2[] and dd2[] (calculated at x2[]). | -//| This function yields same result as Spline1DBuildCubic() call | -//| followed by sequence of Spline1DDiff() calls, but it can be | -//| several times faster when called for ordered X[] and X2[]. | -//| INPUT PARAMETERS: | -//| X - old spline nodes | -//| Y - function values | -//| X2 - new spline nodes | -//| OPTIONAL PARAMETERS: | -//| N - points count: | -//| * N>=2 | -//| * if given, only first N points from X/Y are | -//| used | -//| * if not given, automatically detected from | -//| X/Y sizes (len(X) must be equal to len(Y)) | -//| BoundLType - boundary condition type for the left boundary| -//| BoundL - left boundary condition (first or second | -//| derivative, depending on the BoundLType) | -//| BoundRType - boundary condition type for the right | -//| boundary | -//| BoundR - right boundary condition (first or second | -//| derivative, depending on the BoundRType) | -//| N2 - new points count: | -//| * N2>=2 | -//| * if given, only first N2 points from X2 are | -//| used | -//| * if not given, automatically detected from | -//| X2 size | -//| OUTPUT PARAMETERS: | -//| F2 - function values at X2[] | -//| D2 - first derivatives at X2[] | -//| DD2 - second derivatives at X2[] | -//| ORDER OF POINTS | -//| Subroutine automatically sorts points, so caller may pass | -//| unsorted array. Function values are correctly reordered on | -//| return, so F2[I] is always equal to S(X2[I]) independently of | -//| points order. | -//| SETTING BOUNDARY VALUES: | -//| The BoundLType/BoundRType parameters can have the following | -//| values: | -//| * -1, which corresonds to the periodic (cyclic) boundary | -//| conditions. In this case: | -//| * both BoundLType and BoundRType must be equal to -1. | -//| * BoundL/BoundR are ignored | -//| * Y[last] is ignored (it is assumed to be equal to | -//| Y[first]). | -//| * 0, which corresponds to the parabolically terminated | -//| spline (BoundL and/or BoundR are ignored). | -//| * 1, which corresponds to the first derivative boundary | -//| condition | -//| * 2, which corresponds to the second derivative boundary | -//| condition | -//| * by default, BoundType=0 is used | -//| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: | -//| Problems with periodic boundary conditions have | -//| Y[first_point]=Y[last_point]. However, this subroutine doesn't | -//| require you to specify equal values for the first and last | -//| points - it automatically forces them to be equal by copying | -//| Y[first_point] (corresponds to the leftmost, minimal X[]) to | -//| Y[last_point]. However it is recommended to pass consistent | -//| values of Y[], i.e. to make Y[first_point]=Y[last_point]. | -//+------------------------------------------------------------------+ -static void CSpline1D::Spline1DConvDiff2Cubic(double &cx[],double &cy[], - const int n,const int boundltype, - const double boundl, - const int boundrtype, - const double boundr,double &cx2[], - const int n2,double &y2[], - double &d2[],double &dd2[]) - { -//--- create variables - int i=0; - int ylen=0; - double t=0; - double t2=0; - int i_=0; -//--- create arrays - double a1[]; - double a2[]; - double a3[]; - double b[]; - double d[]; - double dt[]; - int p[]; - int p2[]; - double x[]; - double y[]; - double x2[]; -//--- copy arrays - ArrayCopy(x,cx); - ArrayCopy(y,cy); - ArrayCopy(x2,cx2); -//--- check correctness of boundary conditions - if(!CAp::Assert(((boundltype==-1 || boundltype==0) || boundltype==1) || boundltype==2,__FUNCTION__+": incorrect BoundLType!")) - return; -//--- check - if(!CAp::Assert(((boundrtype==-1 || boundrtype==0) || boundrtype==1) || boundrtype==2,__FUNCTION__+": incorrect BoundRType!")) - return; -//--- check - if(!CAp::Assert((boundrtype==-1 && boundltype==-1) || (boundrtype!=-1 && boundltype!=-1),__FUNCTION__+": incorrect BoundLType/BoundRType!")) - return; -//--- check - if(boundltype==1 || boundltype==2) - { - //--- check - if(!CAp::Assert(CMath::IsFinite(boundl),__FUNCTION__+": BoundL is infinite or NAN!")) - return; - } -//--- check - if(boundrtype==1 || boundrtype==2) - { - //--- check - if(!CAp::Assert(CMath::IsFinite(boundr),__FUNCTION__+": BoundR is infinite or NAN!")) - return; - } -//--- check lengths of arguments - if(!CAp::Assert(n>=2,__FUNCTION__+": N<2!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(Y)=2,__FUNCTION__+": N2<2!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x2)>=n2,__FUNCTION__+": Length(X2)=n2,__FUNCTION__+": internal error!")) - return; -//--- copy - for(i=0;i<=n2-1;i++) - dt[p2[i]]=y2[i]; - for(i_=0;i_<=n2-1;i_++) - y2[i_]=dt[i_]; - for(i=0;i<=n2-1;i++) - dt[p2[i]]=d2[i]; - for(i_=0;i_<=n2-1;i_++) - d2[i_]=dt[i_]; - for(i=0;i<=n2-1;i++) - dt[p2[i]]=dd2[i]; - for(i_=0;i_<=n2-1;i_++) - dd2[i_]=dt[i_]; - } -//+------------------------------------------------------------------+ -//| This subroutine builds Catmull-Rom spline interpolant. | -//| INPUT PARAMETERS: | -//| X - spline nodes, array[0..N-1]. | -//| Y - function values, array[0..N-1]. | -//| OPTIONAL PARAMETERS: | -//| N - points count: | -//| * N>=2 | -//| * if given, only first N points are used to | -//| build spline | -//| * if not given, automatically detected from | -//| X/Y sizes (len(X) must be equal to len(Y)) | -//| BoundType - boundary condition type: | -//| * -1 for periodic boundary condition | -//| * 0 for parabolically terminated spline | -//| (default) | -//| Tension - tension parameter: | -//| * tension=0 corresponds to classic | -//| Catmull-Rom spline (default) | -//| * 0=2,__FUNCTION__+": N<2!")) - return; -//--- check - if(!CAp::Assert(boundtype==-1 || boundtype==0,__FUNCTION__+": incorrect BoundType!")) - return; -//--- check - if(!CAp::Assert((double)(tension)>=0.0,__FUNCTION__+": Tension<0!")) - return; -//--- check - if(!CAp::Assert((double)(tension)<=(double)(1),__FUNCTION__+": Tension>1!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(Y)=2 | -//| * if given, only first N points are used to | -//| build spline | -//| * if not given, automatically detected from | -//| X/Y sizes (len(X) must be equal to len(Y)) | -//| OUTPUT PARAMETERS: | -//| C - spline interpolant. | -//| ORDER OF POINTS | -//| Subroutine automatically sorts points, so caller may pass | -//| unsorted array. | -//+------------------------------------------------------------------+ -static void CSpline1D::Spline1DBuildHermite(double &cx[],double &cy[], - double &cd[],const int n, - CSpline1DInterpolant &c) - { -//--- create variables - int i=0; - double delta=0; - double delta2=0; - double delta3=0; -//--- create arrays - double x[]; - double y[]; - double d[]; -//--- copy arrays - ArrayCopy(x,cx); - ArrayCopy(y,cy); - ArrayCopy(d,cd); -//--- check - if(!CAp::Assert(n>=2,__FUNCTION__+": N<2!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(Y)=n,__FUNCTION__+": Length(D)=5 | -//| * if given, only first N points are used to | -//| build spline | -//| * if not given, automatically detected from | -//| X/Y sizes (len(X) must be equal to len(Y)) | -//| OUTPUT PARAMETERS: | -//| C - spline interpolant | -//| ORDER OF POINTS | -//| Subroutine automatically sorts points, so caller may pass | -//| unsorted array. | -//+------------------------------------------------------------------+ -static void CSpline1D::Spline1DBuildAkima(double &cx[],double &cy[], - const int n,CSpline1DInterpolant &c) - { -//--- create a variable - int i=0; -//--- create arrays - double d[]; - double w[]; - double diff[]; - double x[]; - double y[]; -//--- copy arrays - ArrayCopy(x,cx); - ArrayCopy(y,cy); -//--- check - if(!CAp::Assert(n>=5,__FUNCTION__+": N<5!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(Y)=x) - r=m; - else - l=m; - } -//--- Interpolation - x=x-c.m_x[l]; - m=4*l; -//--- return result - return(c.m_c[m]+x*(c.m_c[m+1]+x*(c.m_c[m+2]+x*c.m_c[m+3]))); - } -//+------------------------------------------------------------------+ -//| This subroutine differentiates the spline. | -//| INPUT PARAMETERS: | -//| C - spline interpolant. | -//| X - point | -//| Result: | -//| S - S(x) | -//| DS - S'(x) | -//| D2S - S''(x) | -//+------------------------------------------------------------------+ -static void CSpline1D::Spline1DDiff(CSpline1DInterpolant &c,double x, - double &s,double &ds,double &d2s) - { -//--- create variables - int l=0; - int r=0; - int m=0; - double t=0; -//--- initialization - s=0; - ds=0; - d2s=0; -//--- check - if(!CAp::Assert(c.m_k==3,__FUNCTION__+": internal error")) - return; -//--- check - if(!CAp::Assert(!CInfOrNaN::IsInfinity(x),__FUNCTION__+": infinite X!")) - return; -//--- special case: NaN - if(CInfOrNaN::IsNaN(x)) - { - //--- change values - s=CInfOrNaN::NaN(); - ds=CInfOrNaN::NaN(); - d2s=CInfOrNaN::NaN(); - //--- exit the function - return; - } -//--- correct if periodic - if(c.m_periodic) - CApServ::ApPeriodicMap(x,c.m_x[0],c.m_x[c.m_n-1],t); -//--- Binary search - l=0; - r=c.m_n-2+1; - while(l!=r-1) - { - m=(l+r)/2; - //--- check - if(c.m_x[m]>=x) - r=m; - else - l=m; - } -//--- Differentiation - x=x-c.m_x[l]; - m=4*l; - s=c.m_c[m]+x*(c.m_c[m+1]+x*(c.m_c[m+2]+x*c.m_c[m+3])); - ds=c.m_c[m+1]+2*x*c.m_c[m+2]+3*CMath::Sqr(x)*c.m_c[m+3]; - d2s=2*c.m_c[m+2]+6*x*c.m_c[m+3]; - } -//+------------------------------------------------------------------+ -//| This subroutine makes the copy of the spline. | -//| INPUT PARAMETERS: | -//| C - spline interpolant. | -//| Result: | -//| CC - spline copy | -//+------------------------------------------------------------------+ -static void CSpline1D::Spline1DCopy(CSpline1DInterpolant &c,CSpline1DInterpolant &cc) - { -//--- create a variable - int i_=0; -//--- change values - cc.m_periodic=c.m_periodic; - cc.m_n=c.m_n; - cc.m_k=c.m_k; -//--- allocation - ArrayResizeAL(cc.m_x,cc.m_n); -//--- copy - for(i_=0;i_<=cc.m_n-1;i_++) - cc.m_x[i_]=c.m_x[i_]; -//--- allocation - ArrayResizeAL(cc.m_c,(cc.m_k+1)*(cc.m_n-1)); -//--- copy - for(i_=0;i_<=(cc.m_k+1)*(cc.m_n-1)-1;i_++) - cc.m_c[i_]=c.m_c[i_]; - } -//+------------------------------------------------------------------+ -//| This subroutine unpacks the spline into the coefficients table. | -//| INPUT PARAMETERS: | -//| C - spline interpolant. | -//| X - point | -//| Result: | -//| Tbl - coefficients table, unpacked format, array[0..N-2, | -//| 0..5]. | -//| For I = 0...N-2: | -//| Tbl[I,0] = X[i] | -//| Tbl[I,1] = X[i+1] | -//| Tbl[I,2] = C0 | -//| Tbl[I,3] = C1 | -//| Tbl[I,4] = C2 | -//| Tbl[I,5] = C3 | -//| On [x[i], x[i+1]] spline is equals to: | -//| S(x) = C0 + C1*t + C2*t^2 + C3*t^3 | -//| t = x-x[i] | -//+------------------------------------------------------------------+ -static void CSpline1D::Spline1DUnpack(CSpline1DInterpolant &c,int &n, - CMatrixDouble &tbl) - { -//--- create variables - int i=0; - int j=0; -//--- allocation - tbl.Resize(c.m_n-2+1,2+c.m_k+1); -//--- initialization - n=c.m_n; -//--- Fill - for(i=0;i<=n-2;i++) - { - tbl[i].Set(0,c.m_x[i]); - tbl[i].Set(1,c.m_x[i+1]); - for(j=0;j<=c.m_k;j++) - tbl[i].Set(2+j,c.m_c[(c.m_k+1)*i+j]); - } - } -//+------------------------------------------------------------------+ -//| This subroutine performs linear transformation of the spline | -//| argument. | -//| INPUT PARAMETERS: | -//| C - spline interpolant. | -//| A, B- transformation coefficients: x = A*t + B | -//| Result: | -//| C - transformed spline | -//+------------------------------------------------------------------+ -static void CSpline1D::Spline1DLinTransX(CSpline1DInterpolant &c,const double a, - const double b) - { -//--- create variables - int i=0; - int j=0; - int n=0; - double v=0; - double dv=0; - double d2v=0; -//--- create arrays - double x[]; - double y[]; - double d[]; -//--- initialization - n=c.m_n; -//--- Special case: A=0 - if(a==0.0) - { - v=Spline1DCalc(c,b); - for(i=0;i<=n-2;i++) - { - c.m_c[(c.m_k+1)*i]=v; - for(j=1;j<=c.m_k;j++) - c.m_c[(c.m_k+1)*i+j]=0; - } - //--- exit the function - return; - } -//--- General case: A<>0. -//--- Unpack,X,Y,dY/dX. -//--- Scale and pack again. - if(!CAp::Assert(c.m_k==3,__FUNCTION__+": internal error")) - return; -//--- allocation - ArrayResizeAL(x,n); - ArrayResizeAL(y,n); - ArrayResizeAL(d,n); -//--- calculation - for(i=0;i<=n-1;i++) - { - x[i]=c.m_x[i]; - Spline1DDiff(c,x[i],v,dv,d2v); - x[i]=(x[i]-b)/a; - y[i]=v; - d[i]=a*dv; - } -//--- function call - Spline1DBuildHermite(x,y,d,n,c); - } -//+------------------------------------------------------------------+ -//| This subroutine performs linear transformation of the spline. | -//| INPUT PARAMETERS: | -//| C - spline interpolant. | -//| A,B- transformation coefficients: S2(x)=A*S(x) + B | -//| Result: | -//| C - transformed spline | -//+------------------------------------------------------------------+ -static void CSpline1D::Spline1DLinTransY(CSpline1DInterpolant &c,const double a, - const double b) - { -//--- create variables - int i=0; - int j=0; - int n=0; -//--- initialization - n=c.m_n; -//--- calculation - for(i=0;i<=n-2;i++) - { - c.m_c[(c.m_k+1)*i]=a*c.m_c[(c.m_k+1)*i]+b; - for(j=1;j<=c.m_k;j++) - c.m_c[(c.m_k+1)*i+j]=a*c.m_c[(c.m_k+1)*i+j]; - } - } -//+------------------------------------------------------------------+ -//| This subroutine integrates the spline. | -//| INPUT PARAMETERS: | -//| C - spline interpolant. | -//| X - right bound of the integration interval [a, x], | -//| here 'a' denotes min(x[]) | -//| Result: | -//| integral(S(t)dt,a,x) | -//+------------------------------------------------------------------+ -static double CSpline1D::Spline1DIntegrate(CSpline1DInterpolant &c,double x) - { -//--- create variables - double result=0; - int n=0; - int i=0; - int j=0; - int l=0; - int r=0; - int m=0; - double w=0; - double v=0; - double t=0; - double intab=0; - double additionalterm=0; -//--- initialization - n=c.m_n; -//--- Periodic splines require special treatment. We make -//--- following transformation: -//--- integral(S(t)dt,A,X)=integral(S(t)dt,A,Z)+AdditionalTerm -//--- here X may lie outside of [A,B],Z lies strictly in [A,B], -//--- AdditionalTerm is equals to integral(S(t)dt,A,B) times some -//--- integer number (may be zero). - if(c.m_periodic && (xc.m_x[c.m_n-1])) - { - //--- compute integral(S(x)dx,A,B) - intab=0; - for(i=0;i<=c.m_n-2;i++) - { - w=c.m_x[i+1]-c.m_x[i]; - m=(c.m_k+1)*i; - intab=intab+c.m_c[m]*w; - v=w; - for(j=1;j<=c.m_k;j++) - { - v=v*w; - intab=intab+c.m_c[m+j]*v/(j+1); - } - } - //--- map X into [A,B] - CApServ::ApPeriodicMap(x,c.m_x[0],c.m_x[c.m_n-1],t); - additionalterm=t*intab; - } - else - additionalterm=0; -//--- Binary search in the [ x[0],...,x[n-2] ] (x[n-1] is not included) - l=0; - r=n-2+1; - while(l!=r-1) - { - m=(l+r)/2; - //--- check - if(c.m_x[m]>=x) - r=m; - else - l=m; - } -//--- Integration - result=0; - for(i=0;i<=l-1;i++) - { - w=c.m_x[i+1]-c.m_x[i]; - m=(c.m_k+1)*i; - result=result+c.m_c[m]*w; - v=w; - //--- calculation - for(j=1;j<=c.m_k;j++) - { - v=v*w; - result=result+c.m_c[m+j]*v/(j+1); - } - } -//--- change values - w=x-c.m_x[l]; - m=(c.m_k+1)*l; - v=w; - result=result+c.m_c[m]*w; -//--- calculation - for(j=1;j<=c.m_k;j++) - { - v=v*w; - result=result+c.m_c[m+j]*v/(j+1); - } -//--- return result - return(result+additionalterm); - } -//+------------------------------------------------------------------+ -//| Internal version of Spline1DConvDiff | -//| Converts from Hermite spline given by grid XOld to new grid X2 | -//| INPUT PARAMETERS: | -//| XOld - old grid | -//| YOld - values at old grid | -//| DOld - first derivative at old grid | -//| N - grid size | -//| X2 - new grid | -//| N2 - new grid size | -//| Y - possibly preallocated output array | -//| (reallocate if too small) | -//| NeedY - do we need Y? | -//| D1 - possibly preallocated output array | -//| (reallocate if too small) | -//| NeedD1 - do we need D1? | -//| D2 - possibly preallocated output array | -//| (reallocate if too small) | -//| NeedD2 - do we need D1? | -//| OUTPUT ARRAYS: | -//| Y - values, if needed | -//| D1 - first derivative, if needed | -//| D2 - second derivative, if needed | -//+------------------------------------------------------------------+ -static void CSpline1D::Spline1DConvDiffInternal(double &xold[],double &yold[], - double &dold[],const int n, - double &x2[],const int n2, - double &y[],const bool needy, - double &d1[],const bool needd1, - double &d2[],const bool needd2) - { -//--- create variables - int intervalindex=0; - int pointindex=0; - bool havetoadvance; - double c0=0; - double c1=0; - double c2=0; - double c3=0; - double a=0; - double b=0; - double w=0; - double w2=0; - double w3=0; - double fa=0; - double fb=0; - double da=0; - double db=0; - double t=0; -//--- Prepare space - if(needy && CAp::Len(y)=n2) - break; - t=x2[pointindex]; - //--- do we need to advance interval? - havetoadvance=false; - //--- check - if(intervalindex==-1) - havetoadvance=true; - else - { - //--- check - if(intervalindex=b; - } - //--- check - if(havetoadvance) - { - //--- change values - intervalindex=intervalindex+1; - a=xold[intervalindex]; - b=xold[intervalindex+1]; - w=b-a; - w2=w*w; - w3=w*w2; - fa=yold[intervalindex]; - fb=yold[intervalindex+1]; - da=dold[intervalindex]; - db=dold[intervalindex+1]; - c0=fa; - c1=da; - c2=(3*(fb-fa)-2*da*w-db*w)/w2; - c3=(2*(fa-fb)+da*w+db*w)/w3; - continue; - } - //--- Calculate spline and its derivatives using power basis - t=t-a; - if(needy) - y[pointindex]=c0+t*(c1+t*(c2+t*c3)); - //--- check - if(needd1) - d1[pointindex]=c1+2*t*c2+3*t*t*c3; - //--- check - if(needd2) - d2[pointindex]=2*c2+6*t*c3; - //--- change value - pointindex=pointindex+1; - } - } -//+------------------------------------------------------------------+ -//| Internal subroutine. Heap sort. | -//+------------------------------------------------------------------+ -static void CSpline1D::HeapSortDPoints(double &x[],double &y[],double &d[], - const int n) - { -//--- create variables - int i=0; - int i_=0; -//--- create arrays - double rbuf[]; - int ibuf[]; - double rbuf2[]; - int ibuf2[]; -//--- allocation - ArrayResizeAL(ibuf,n); - ArrayResizeAL(rbuf,n); - for(i=0;i<=n-1;i++) - ibuf[i]=i; -//--- function call - CTSort::TagSortFastI(x,ibuf,rbuf2,ibuf2,n); -//--- copy - for(i=0;i<=n-1;i++) - rbuf[i]=y[ibuf[i]]; - for(i_=0;i_<=n-1;i_++) - y[i_]=rbuf[i_]; - for(i=0;i<=n-1;i++) - rbuf[i]=d[ibuf[i]]; - for(i_=0;i_<=n-1;i_++) - d[i_]=rbuf[i_]; - } -//+------------------------------------------------------------------+ -//| Internal version of Spline1DGridDiffCubic. | -//| Accepts pre-ordered X/Y, temporary arrays (which may be | -//| preallocated, if you want to save time, or not) and output array | -//| (which may be preallocated too). | -//| Y is passed as var-parameter because we may need to force last | -//| element to be equal to the first one (if periodic boundary | -//| conditions are specified). | -//+------------------------------------------------------------------+ -static void CSpline1D::Spline1DGridDiffCubicInternal(double &x[],double &y[], - const int n,const int boundltype, - const double boundl, - const int boundrtype, - const double boundr, - double &d[],double &a1[], - double &a2[],double &a3[], - double &b[],double &dt[]) - { -//--- create variables - int i=0; - int i_=0; -//--- allocate arrays - if(CAp::Len(d)=0;k--) - x[k]=(d[k]-c[k]*x[k+1])/b[k]; - } -//+------------------------------------------------------------------+ -//| Internal subroutine. Cyclic tridiagonal solver. Solves | -//| ( B[0] C[0] A[0] ) | -//| ( A[1] B[1] C[1] ) | -//| ( A[2] B[2] C[2] ) | -//| ( .......... ) * X=D | -//| ( .......... ) | -//| ( A[N-2] B[N-2] C[N-2] ) | -//| ( C[N-1] A[N-1] B[N-1] ) | -//+------------------------------------------------------------------+ -static void CSpline1D::SolveCyclicTridiagonal(double &a[],double &cb[], - double &c[],double &d[], - const int n,double &x[]) - { -//--- create variables - int k=0; - double alpha=0; - double beta=0; - double gamma=0; -//--- create arrays - double y[]; - double z[]; - double u[]; - double b[]; -//--- copy array - ArrayCopy(b,cb); -//--- check - if(CAp::Len(x)0 | -//| * if given, only leading N elements of X/Y are used | -//| * if not given, automatically determined from sizes | -//| of X/Y | -//| M - number of basis functions (= polynomial_degree + 1), | -//| M>=1 | -//| OUTPUT PARAMETERS: | -//| Info- same format as in LSFitLinearW() subroutine: | -//| * Info>0 task is solved | -//| * Info<=0 an error occured: | -//| -4 means inconvergence of internal SVD | -//| P - interpolant in barycentric form. | -//| Rep - report, same format as in LSFitLinearW() subroutine. | -//| Following fields are set: | -//| * RMSError rms error on the (X,Y). | -//| * AvgError average error on the (X,Y). | -//| * AvgRelError average relative error on the | -//| non-zero Y | -//| * MaxError maximum error | -//| NON-WEIGHTED ERRORS ARE CALCULATED | -//| NOTES: | -//| you can convert P from barycentric form to the power or | -//| Chebyshev basis with PolynomialBar2Pow() or | -//| PolynomialBar2Cheb() functions from POLINT subpackage. | -//+------------------------------------------------------------------+ -static void CLSFit::PolynomialFit(double &x[],double &y[],const int n, - const int m,int &info, - CBarycentricInterpolant &p, - CPolynomialFitReport &rep) - { -//--- create a variable - int i=0; -//--- create arrays - double w[]; - double xc[]; - double yc[]; - int dc[]; -//--- initialization - info=0; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(m>0,__FUNCTION__+": M<=0!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(Y)0. | -//| * if given, only leading N elements of X/Y/W are used| -//| * if not given, automatically determined from sizes | -//| of X/Y/W | -//| XC - points where polynomial values/derivatives are | -//| constrained, array[0..K-1]. | -//| YC - values of constraints, array[0..K-1] | -//| DC - array[0..K-1], types of constraints: | -//| * DC[i]=0 means that P(XC[i])=YC[i] | -//| * DC[i]=1 means that P'(XC[i])=YC[i] | -//| SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS | -//| K - number of constraints, 0<=K=1 | -//| OUTPUT PARAMETERS: | -//| Info- same format as in LSFitLinearW() subroutine: | -//| * Info>0 task is solved | -//| * Info<=0 an error occured: | -//| -4 means inconvergence of internal SVD | -//| -3 means inconsistent constraints | -//| P - interpolant in barycentric form. | -//| Rep - report, same format as in LSFitLinearW() subroutine. | -//| Following fields are set: | -//| * RMSError rms error on the (X,Y). | -//| * AvgError average error on the (X,Y). | -//| * AvgRelError average relative error on the | -//| non-zero Y | -//| * MaxError maximum error | -//| NON-WEIGHTED ERRORS ARE CALCULATED | -//| IMPORTANT: | -//| this subroitine doesn't calculate task's condition number | -//| for K<>0. | -//| NOTES: | -//| you can convert P from barycentric form to the power or | -//| Chebyshev basis with PolynomialBar2Pow() or | -//| PolynomialBar2Cheb() functions from POLINT subpackage. | -//| SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: | -//| Setting constraints can lead to undesired results, like | -//| ill-conditioned behavior, or inconsistency being detected. | -//| From the other side, it allows us to improve quality of the fit. | -//| Here we summarize our experience with constrained regression | -//| splines: | -//| * even simple constraints can be inconsistent, see Wikipedia | -//| article on this subject: | -//| http://en.wikipedia.org/wiki/Birkhoff_interpolation | -//| * the greater is M (given fixed constraints), the more chances | -//| that constraints will be consistent | -//| * in the general case, consistency of constraints is NOT | -//| GUARANTEED. | -//| * in the one special cases, however, we can guarantee | -//| consistency. This case is: M>1 and constraints on the | -//| function values (NOT DERIVATIVES) | -//| Our final recommendation is to use constraints WHEN AND ONLY when| -//| you can't solve your task without them. Anything beyond special | -//| cases given above is not guaranteed and may result in | -//| inconsistency. | -//+------------------------------------------------------------------+ -static void CLSFit::PolynomialFitWC(double &cx[],double &cy[],double &cw[], - const int n,double &cxc[],double &cyc[], - int &dc[],const int k,const int m, - int &info,CBarycentricInterpolant &p, - CPolynomialFitReport &rep) - { -//--- create variables - double xa=0; - double xb=0; - double sa=0; - double sb=0; - int i=0; - int j=0; - double u=0; - double v=0; - double s=0; - int relcnt=0; -//--- create arrays - double xoriginal[]; - double yoriginal[]; - double y2[]; - double w2[]; - double tmp[]; - double tmp2[]; - double bx[]; - double by[]; - double bw[]; - double x[]; - double y[]; - double w[]; - double xc[]; - double yc[]; -//--- object of class - CLSFitReport lrep; -//--- copy arrays - ArrayCopy(x,cx); - ArrayCopy(y,cy); - ArrayCopy(w,cw); - ArrayCopy(xc,cxc); - ArrayCopy(yc,cyc); -//--- initialization - info=0; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(m>0,__FUNCTION__+": M<=0!")) - return; -//--- check - if(!CAp::Assert(k>=0,__FUNCTION__+": K<0!")) - return; -//--- check - if(!CAp::Assert(k=M!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(Y)=n,__FUNCTION__+": Length(W)=k,__FUNCTION__+": Length(XC)=k,__FUNCTION__+": Length(YC)=k,__FUNCTION__+": Length(DC)0. | -//| XC - points where function values/derivatives are | -//| constrained, array[0..K-1]. | -//| YC - values of constraints, array[0..K-1] | -//| DC - array[0..K-1], types of constraints: | -//| * DC[i]=0 means that S(XC[i])=YC[i] | -//| * DC[i]=1 means that S'(XC[i])=YC[i] | -//| SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS | -//| K - number of constraints, 0<=K=2. | -//| OUTPUT PARAMETERS: | -//| Info- same format as in LSFitLinearWC() subroutine. | -//| * Info>0 task is solved | -//| * Info<=0 an error occured: | -//| -4 means inconvergence of internal SVD | -//| -3 means inconsistent constraints | -//| -1 means another errors in parameters | -//| passed (N<=0, for example) | -//| B - barycentric interpolant. | -//| Rep - report, same format as in LSFitLinearWC() subroutine.| -//| Following fields are set: | -//| * DBest best value of the D parameter | -//| * RMSError rms error on the (X,Y). | -//| * AvgError average error on the (X,Y). | -//| * AvgRelError average relative error on the | -//| non-zero Y | -//| * MaxError maximum error | -//| NON-WEIGHTED ERRORS ARE CALCULATED | -//| IMPORTANT: | -//| this subroutine doesn't calculate task's condition number | -//| for K<>0. | -//| SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: | -//| Setting constraints can lead to undesired results, like | -//| ill-conditioned behavior, or inconsistency being detected. From | -//| the other side, it allows us to improve quality of the fit. Here | -//| we summarize our experience with constrained barycentric | -//| interpolants: | -//| * excessive constraints can be inconsistent. Floater-Hormann | -//| basis functions aren't as flexible as splines (although they | -//| are very smooth). | -//| * the more evenly constraints are spread across [min(x),max(x)], | -//| the more chances that they will be consistent | -//| * the greater is M (given fixed constraints), the more chances | -//| that constraints will be consistent | -//| * in the general case, consistency of constraints IS NOT | -//| GUARANTEED. | -//| * in the several special cases, however, we CAN guarantee | -//| consistency. | -//| * one of this cases is constraints on the function VALUES at the | -//| interval boundaries. Note that consustency of the constraints | -//| on the function DERIVATIVES is NOT guaranteed (you can use in | -//| such cases cubic splines which are more flexible). | -//| * another special case is ONE constraint on the function value | -//| (OR, but not AND, derivative) anywhere in the interval | -//| Our final recommendation is to use constraints WHEN AND ONLY | -//| WHEN you can't solve your task without them. Anything beyond | -//| special cases given above is not guaranteed and may result in | -//| inconsistency. | -//+------------------------------------------------------------------+ -static void CLSFit::BarycentricFitFloaterHormannWC(double &x[],double &y[], - double &w[],const int n, - double &xc[],double &yc[], - int &dc[],const int k, - const int m,int &info, - CBarycentricInterpolant &b, - CBarycentricFitReport &rep) - { -//--- create variables - int d=0; - int i=0; - double wrmscur=0; - double wrmsbest=0; - int locinfo=0; -//--- objects of classes - CBarycentricInterpolant locb; - CBarycentricFitReport locrep; -//--- initialization - info=0; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(m>0,__FUNCTION__+": M<=0!")) - return; -//--- check - if(!CAp::Assert(k>=0,__FUNCTION__+": K<0!")) - return; -//--- check - if(!CAp::Assert(k=M!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(Y)=n,__FUNCTION__+": Length(W)=k,__FUNCTION__+": Length(XC)=k,__FUNCTION__+": Length(YC)=k,__FUNCTION__+": Length(DC)0,__FUNCTION__+": unexpected result from BarycentricFitWCFixedD!")) - return; - //--- check - if(locinfo>0) - { - //--- Calculate weghted RMS - wrmscur=0; - for(i=0;i<=n-1;i++) - wrmscur=wrmscur+CMath::Sqr(w[i]*(y[i]-CRatInt::BarycentricCalc(locb,x[i]))); - wrmscur=MathSqrt(wrmscur/n); - //--- check - if(wrmscur0. | -//| M - number of basis functions ( = number_of_nodes), M>=2.| -//| OUTPUT PARAMETERS: | -//| Info- same format as in LSFitLinearWC() subroutine. | -//| * Info>0 task is solved | -//| * Info<=0 an error occured: | -//| -4 means inconvergence of internal SVD | -//| -3 means inconsistent constraints | -//| B - barycentric interpolant. | -//| Rep - report, same format as in LSFitLinearWC() subroutine.| -//| Following fields are set: | -//| * DBest best value of the D parameter | -//| * RMSError rms error on the (X,Y). | -//| * AvgError average error on the (X,Y). | -//| * AvgRelError average relative error on the | -//| non-zero Y | -//| * MaxError maximum error | -//| NON-WEIGHTED ERRORS ARE CALCULATED | -//+------------------------------------------------------------------+ -static void CLSFit::BarycentricFitFloaterHormann(double &x[],double &y[], - const int n,const int m, - int &info,CBarycentricInterpolant &b, - CBarycentricFitReport &rep) - { -//--- create arrays - double w[]; - double xc[]; - double yc[]; - int dc[]; -//--- create a variable - int i=0; -//--- initialization - info=0; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(m>0,__FUNCTION__+": M<=0!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(Y)0. | -//| M - number of basis functions ( = number_of_nodes), M>=2.| -//| OUTPUT PARAMETERS: | -//| Info- same format as in LSFitLinearWC() subroutine. | -//| * Info>0 task is solved | -//| * Info<=0 an error occured: | -//| -4 means inconvergence of internal SVD | -//| -3 means inconsistent constraints | -//| B - barycentric interpolant. | -//| Rep - report, same format as in LSFitLinearWC() subroutine.| -//| Following fields are set: | -//| * DBest best value of the D parameter | -//| * RMSError rms error on the (X,Y). | -//| * AvgError average error on the (X,Y). | -//| * AvgRelError average relative error on the | -//| non-zero Y | -//| * MaxError maximum error | -//| NON-WEIGHTED ERRORS ARE CALCULATED | -//+------------------------------------------------------------------+ -static void CLSFit::Spline1DFitPenalized(double &cx[],double &cy[], - const int n,const int m, - const double rho,int &info, - CSpline1DInterpolant &s, - CSpline1DFitReport &rep) - { -//--- create a variable - int i=0; -//--- create arrays - double w[]; - double x[]; - double y[]; -//--- copy arrays - ArrayCopy(x,cx); - ArrayCopy(y,cy); -//--- initialization - info=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(m>=4,__FUNCTION__+": M<4!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(Y)0 | -//| * if given, only first N elements of X/Y/W are | -//| processed | -//| * if not given, automatically determined from X/Y/W | -//| sizes | -//| M - number of basis functions ( = number_of_nodes), M>=4.| -//| Rho - regularization constant passed by user. It penalizes | -//| nonlinearity in the regression spline. It is | -//| logarithmically scaled, i.e. actual value of | -//| regularization constant is calculated as 10^Rho. It | -//| is automatically scaled so that: | -//| * Rho=2.0 corresponds to moderate amount of | -//| nonlinearity | -//| * generally, it should be somewhere in the | -//| [-8.0,+8.0] | -//| If you do not want to penalize nonlineary, | -//| pass small Rho. Values as low as -15 should work. | -//| OUTPUT PARAMETERS: | -//| Info- same format as in LSFitLinearWC() subroutine. | -//| * Info>0 task is solved | -//| * Info<=0 an error occured: | -//| -4 means inconvergence of internal SVD | -//| or Cholesky decomposition; problem | -//| may be too ill-conditioned (very | -//| rare) | -//| S - spline interpolant. | -//| Rep - Following fields are set: | -//| * RMSError rms error on the (X,Y). | -//| * AvgError average error on the (X,Y). | -//| * AvgRelError average relative error on the | -//| non-zero Y | -//| * MaxError maximum error | -//| NON-WEIGHTED ERRORS ARE CALCULATED | -//| IMPORTANT: | -//| this subroitine doesn't calculate task's condition number | -//| for K<>0. | -//| NOTE 1: additional nodes are added to the spline outside of the | -//| fitting interval to force linearity when xmax(x,xc). It is done for consistency - we penalize | -//| non-linearity at [min(x,xc),max(x,xc)], so it is natural to | -//| force linearity outside of this interval. | -//| NOTE 2: function automatically sorts points, so caller may pass | -//| unsorted array. | -//+------------------------------------------------------------------+ -static void CLSFit::Spline1DFitPenalizedW(double &cx[],double &cy[], - double &cw[],const int n, - const int m,double rho, - int &info,CSpline1DInterpolant &s, - CSpline1DFitReport &rep) - { -//--- create variables - int i=0; - int j=0; - int b=0; - double v=0; - double relcnt=0; - double xa=0; - double xb=0; - double sa=0; - double sb=0; - double pdecay=0; - double tdecay=0; - double fdmax=0; - double admax=0; - double fa=0; - double ga=0; - double fb=0; - double gb=0; - double lambdav=0; - int i_=0; - int i1_=0; -//--- create arrays - double xoriginal[]; - double yoriginal[]; - double fcolumn[]; - double y2[]; - double w2[]; - double xc[]; - double yc[]; - int dc[]; - double bx[]; - double by[]; - double bd1[]; - double bd2[]; - double tx[]; - double ty[]; - double td[]; - double rightpart[]; - double c[]; - double tmp0[]; - double x[]; - double y[]; - double w[]; -//--- create matrix - CMatrixDouble fmatrix; - CMatrixDouble amatrix; - CMatrixDouble d2matrix; - CMatrixDouble nmatrix; -//--- objects of classes - CSpline1DInterpolant bs; - CFblsLinCgState cgstate; -//--- copy arrays - ArrayCopy(x,cx); - ArrayCopy(y,cy); - ArrayCopy(w,cw); -//--- initialization - info=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(m>=4,__FUNCTION__+": M<4!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(Y)=n,__FUNCTION__+": Length(W)v) - rho=v; - lambdav=MathPow(10,rho); -//--- Sort X,Y,W - CSpline1D::HeapSortDPoints(x,y,w,n); -//--- Scale X,Y,XC,YC - LSFitScaleXY(x,y,w,n,xc,yc,dc,0,xa,xb,sa,sb,xoriginal,yoriginal); -//--- Allocate space - fmatrix.Resize(n,m); - amatrix.Resize(m,m); - d2matrix.Resize(m,m); - ArrayResizeAL(bx,m); - ArrayResizeAL(by,m); - ArrayResizeAL(fcolumn,n); - nmatrix.Resize(m,m); - ArrayResizeAL(rightpart,m); - ArrayResizeAL(tmp0,MathMax(m,n)); - ArrayResizeAL(c,m); -//--- Fill: -//--- * FMatrix by values of basis functions -//--- * TmpAMatrix by second derivatives of I-th function at J-th point -//--- * CMatrix by constraints - fdmax=0; - for(b=0;b<=m-1;b++) - { - //--- Prepare I-th basis function - for(j=0;j<=m-1;j++) - { - bx[j]=(double)(2*j)/(double)(m-1)-1; - by[j]=0; - } - by[b]=1; - //--- function call - CSpline1D::Spline1DGridDiff2Cubic(bx,by,m,2,0.0,2,0.0,bd1,bd2); - //--- function call - CSpline1D::Spline1DBuildCubic(bx,by,m,2,0.0,2,0.0,bs); - //--- Calculate B-th column of FMatrix - //--- Update FDMax (maximum column norm) - CSpline1D::Spline1DConvCubic(bx,by,m,2,0.0,2,0.0,x,n,fcolumn); - for(i_=0;i_<=n-1;i_++) - fmatrix[i_].Set(b,fcolumn[i_]); - v=0; - for(i=0;i<=n-1;i++) - v=v+CMath::Sqr(w[i]*fcolumn[i]); - fdmax=MathMax(fdmax,v); - //--- Fill temporary with second derivatives of basis function - for(i_=0;i_<=m-1;i_++) - d2matrix[b].Set(i_,bd2[i_]); - } -//--- * calculate penalty matrix A -//--- * calculate max of diagonal elements of A -//--- * calculate PDecay - coefficient before penalty matrix - for(i=0;i<=m-1;i++) - { - for(j=i;j<=m-1;j++) - { - //--- calculate integral(B_i''*B_j'') where B_i and B_j are - //--- i-th and j-th basis splines. - //--- B_i and B_j are piecewise linear functions. - v=0; - for(b=0;b<=m-2;b++) - { - //--- change values - fa=d2matrix[i][b]; - fb=d2matrix[i][b+1]; - ga=d2matrix[j][b]; - gb=d2matrix[j][b+1]; - v=v+(bx[b+1]-bx[b])*(fa*ga+(fa*(gb-ga)+ga*(fb-fa))/2+(fb-fa)*(gb-ga)/3); - } - amatrix[i].Set(j,v); - amatrix[j].Set(i,v); - } - } -//--- change values - admax=0; - for(i=0;i<=m-1;i++) - admax=MathMax(admax,MathAbs(amatrix[i][i])); - pdecay=lambdav*fdmax/admax; -//--- Calculate TDecay for Tikhonov regularization - tdecay=fdmax*(1+pdecay)*10*CMath::m_machineepsilon; -//--- Prepare system -//--- NOTE: FMatrix is spoiled during this process - for(i=0;i<=n-1;i++) - { - v=w[i]; - for(i_=0;i_<=m-1;i_++) - fmatrix[i].Set(i_,v*fmatrix[i][i_]); - } -//--- function call - CAblas::RMatrixGemm(m,m,n,1.0,fmatrix,0,0,1,fmatrix,0,0,0,0.0,nmatrix,0,0); - for(i=0;i<=m-1;i++) - { - for(j=0;j<=m-1;j++) - nmatrix[i].Set(j,nmatrix[i][j]+pdecay*amatrix[i][j]); - } -//--- calculation - for(i=0;i<=m-1;i++) - nmatrix[i].Set(i,nmatrix[i][i]+tdecay); - for(i=0;i<=m-1;i++) - rightpart[i]=0; -//--- change values - for(i=0;i<=n-1;i++) - { - v=y[i]*w[i]; - for(i_=0;i_<=m-1;i_++) - rightpart[i_]=rightpart[i_]+v*fmatrix[i][i_]; - } -//--- Solve system - if(!CTrFac::SPDMatrixCholesky(nmatrix,m,true)) - { - info=-4; - return; - } -//--- function call - CFbls::FblsCholeskySolve(nmatrix,1.0,m,true,rightpart,tmp0); -//--- copy - for(i_=0;i_<=m-1;i_++) - c[i_]=rightpart[i_]; -//--- add nodes to force linearity outside of the fitting interval - CSpline1D::Spline1DGridDiffCubic(bx,c,m,2,0.0,2,0.0,bd1); -//--- allocation - ArrayResizeAL(tx,m+2); - ArrayResizeAL(ty,m+2); - ArrayResizeAL(td,m+2); -//--- copy - i1_=-1; - for(i_=1;i_<=m;i_++) - tx[i_]=bx[i_+i1_]; - i1_=-1; - for(i_=1;i_<=m;i_++) - ty[i_]=rightpart[i_+i1_]; - i1_=-1; - for(i_=1;i_<=m;i_++) - td[i_]=bd1[i_+i1_]; -//--- change values - tx[0]=tx[1]-(tx[2]-tx[1]); - ty[0]=ty[1]-td[1]*(tx[2]-tx[1]); - td[0]=td[1]; - tx[m+1]=tx[m]+(tx[m]-tx[m-1]); - ty[m+1]=ty[m]+td[m]*(tx[m]-tx[m-1]); - td[m+1]=td[m]; -//--- function call - CSpline1D::Spline1DBuildHermite(tx,ty,td,m+2,s); -//--- function call - CSpline1D::Spline1DLinTransX(s,2/(xb-xa),-((xa+xb)/(xb-xa))); -//--- function call - CSpline1D::Spline1DLinTransY(s,sb-sa,sa); -//--- change value - info=1; -//--- Fill report - rep.m_rmserror=0; - rep.m_avgerror=0; - rep.m_avgrelerror=0; - rep.m_maxerror=0; - relcnt=0; -//--- function call - CSpline1D::Spline1DConvCubic(bx,rightpart,m,2,0.0,2,0.0,x,n,fcolumn); -//--- calculation - for(i=0;i<=n-1;i++) - { - //--- change values - v=(sb-sa)*fcolumn[i]+sa; - rep.m_rmserror=rep.m_rmserror+CMath::Sqr(v-yoriginal[i]); - rep.m_avgerror=rep.m_avgerror+MathAbs(v-yoriginal[i]); - //--- check - if(yoriginal[i]!=0.0) - { - rep.m_avgrelerror=rep.m_avgrelerror+MathAbs(v-yoriginal[i])/MathAbs(yoriginal[i]); - relcnt=relcnt+1; - } - rep.m_maxerror=MathMax(rep.m_maxerror,MathAbs(v-yoriginal[i])); - } -//--- change values - rep.m_rmserror=MathSqrt(rep.m_rmserror/n); - rep.m_avgerror=rep.m_avgerror/n; -//--- check - if(relcnt!=0.0) - rep.m_avgrelerror=rep.m_avgrelerror/relcnt; - } -//+------------------------------------------------------------------+ -//| Weighted fitting by cubic spline, with constraints on function | -//| values or derivatives. | -//| Equidistant grid with M-2 nodes on [min(x,xc),max(x,xc)] is used | -//| to build basis functions. Basis functions are cubic splines with | -//| continuous second derivatives and non-fixed first derivatives at | -//| interval ends. Small regularizing term is used when solving | -//| constrained tasks (to improve stability). | -//| Task is linear, so linear least squares solver is used. | -//| Complexity of this computational scheme is O(N*M^2), mostly | -//| dominated by least squares solver | -//| SEE ALSO | -//| Spline1DFitHermiteWC() - fitting by Hermite splines (more | -//| flexible, less smooth) | -//| Spline1DFitCubic() - "lightweight" fitting by cubic | -//| splines, without invididual | -//| weights and constraints | -//| INPUT PARAMETERS: | -//| X - points, array[0..N-1]. | -//| Y - function values, array[0..N-1]. | -//| W - weights, array[0..N-1] | -//| Each summand in square sum of approximation | -//| deviations from given values is multiplied by the | -//| square of corresponding weight. Fill it by 1's if you| -//| don't want to solve weighted task. | -//| N - number of points (optional): | -//| * N>0 | -//| * if given, only first N elements of X/Y/W are | -//| processed | -//| * if not given, automatically determined from X/Y/W | -//| sizes | -//| XC - points where spline values/derivatives are | -//| constrained, array[0..K-1]. | -//| YC - values of constraints, array[0..K-1] | -//| DC - array[0..K-1], types of constraints: | -//| * DC[i]=0 means that S(XC[i])=YC[i] | -//| * DC[i]=1 means that S'(XC[i])=YC[i] | -//| SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS | -//| K - number of constraints (optional): | -//| * 0<=K=4. | -//| OUTPUT PARAMETERS: | -//| Info- same format as in LSFitLinearWC() subroutine. | -//| * Info>0 task is solved | -//| * Info<=0 an error occured: | -//| -4 means inconvergence of internal SVD | -//| -3 means inconsistent constraints | -//| S - spline interpolant. | -//| Rep - report, same format as in LSFitLinearWC() subroutine.| -//| Following fields are set: | -//| * RMSError rms error on the (X,Y). | -//| * AvgError average error on the (X,Y). | -//| * AvgRelError average relative error on the | -//| non-zero Y | -//| * MaxError maximum error | -//| NON-WEIGHTED ERRORS ARE CALCULATED | -//| IMPORTANT: | -//| this subroitine doesn't calculate task's condition number | -//| for K<>0. | -//| ORDER OF POINTS | -//| Subroutine automatically sorts points, so caller may pass | -//| unsorted array. | -//| SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: | -//| Setting constraints can lead to undesired results, like | -//| ill-conditioned behavior, or inconsistency being detected. From | -//| the other side, it allows us to improve quality of the fit. | -//| Here we summarize our experience with constrained regression | -//| splines: | -//| * excessive constraints can be inconsistent. Splines are | -//| piecewise cubic functions, and it is easy to create an | -//| example, where large number of constraints concentrated in | -//| small area will result in inconsistency. Just because spline | -//| is not flexible enough to satisfy all of them. And same | -//| constraints spread across the [min(x),max(x)] will be | -//| perfectly consistent. | -//| * the more evenly constraints are spread across [min(x),max(x)], | -//| the more chances that they will be consistent | -//| * the greater is M (given fixed constraints), the more chances | -//| that constraints will be consistent | -//| * in the general case, consistency of constraints IS NOT | -//| GUARANTEED. | -//| * in the several special cases, however, we CAN guarantee | -//| consistency. | -//| * one of this cases is constraints on the function values | -//| AND/OR its derivatives at the interval boundaries. | -//| * another special case is ONE constraint on the function value | -//| (OR, but not AND, derivative) anywhere in the interval | -//| Our final recommendation is to use constraints WHEN AND ONLY WHEN| -//| you can't solve your task without them. Anything beyond special | -//| cases given above is not guaranteed and may result in | -//| inconsistency. | -//+------------------------------------------------------------------+ -static void CLSFit::Spline1DFitCubicWC(double &x[],double &y[],double &w[], - const int n,double &xc[],double &yc[], - int &dc[],const int k,const int m, - int &info,CSpline1DInterpolant &s, - CSpline1DFitReport &rep) - { -//--- create a variable - int i=0; -//--- initialization - info=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(m>=4,__FUNCTION__+": M<4!")) - return; -//--- check - if(!CAp::Assert(k>=0,__FUNCTION__+": K<0!")) - return; -//--- check - if(!CAp::Assert(k=M!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(Y)=n,__FUNCTION__+": Length(W)=k,__FUNCTION__+": Length(XC)=k,__FUNCTION__+": Length(YC)=k,__FUNCTION__+": Length(DC)0 | -//| * if given, only first N elements of X/Y/W are | -//| processed | -//| * if not given, automatically determined from X/Y/W | -//| sizes | -//| XC - points where spline values/derivatives are | -//| constrained, array[0..K-1]. | -//| YC - values of constraints, array[0..K-1] | -//| DC - array[0..K-1], types of constraints: | -//| * DC[i]=0 means that S(XC[i])=YC[i] | -//| * DC[i]=1 means that S'(XC[i])=YC[i] | -//| SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS | -//| K - number of constraints (optional): | -//| * 0<=K=4, | -//| M IS EVEN! | -//| OUTPUT PARAMETERS: | -//| Info- same format as in LSFitLinearW() subroutine: | -//| * Info>0 task is solved | -//| * Info<=0 an error occured: | -//| -4 means inconvergence of internal SVD | -//| -3 means inconsistent constraints | -//| -2 means odd M was passed (which is not | -//| supported) | -//| -1 means another errors in parameters | -//| passed (N<=0, for example) | -//| S - spline interpolant. | -//| Rep - report, same format as in LSFitLinearW() subroutine. | -//| Following fields are set: | -//| * RMSError rms error on the (X,Y). | -//| * AvgError average error on the (X,Y). | -//| * AvgRelError average relative error on the | -//| non-zero Y | -//| * MaxError maximum error | -//| NON-WEIGHTED ERRORS ARE CALCULATED | -//| IMPORTANT: | -//| this subroitine doesn't calculate task's condition number | -//| for K<>0. | -//| IMPORTANT: | -//| this subroitine supports only even M's | -//| ORDER OF POINTS | -//| ubroutine automatically sorts points, so caller may pass | -//| unsorted array. | -//| SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: | -//| Setting constraints can lead to undesired results, like | -//| ill-conditioned behavior, or inconsistency being detected. From | -//| the other side, it allows us to improve quality of the fit. Here | -//| we summarize our experience with constrained regression splines:| -//| * excessive constraints can be inconsistent. Splines are | -//| piecewise cubic functions, and it is easy to create an example,| -//| where large number of constraints concentrated in small area | -//| will result in inconsistency. Just because spline is not | -//| flexible enough to satisfy all of them. And same constraints | -//| spread across the [min(x),max(x)] will be perfectly consistent.| -//| * the more evenly constraints are spread across [min(x),max(x)], | -//| the more chances that they will be consistent | -//| * the greater is M (given fixed constraints), the more chances | -//| that constraints will be consistent | -//| * in the general case, consistency of constraints is NOT | -//| GUARANTEED. | -//| * in the several special cases, however, we can guarantee | -//| consistency. | -//| * one of this cases is M>=4 and constraints on the function | -//| value (AND/OR its derivative) at the interval boundaries. | -//| * another special case is M>=4 and ONE constraint on the | -//| function value (OR, BUT NOT AND, derivative) anywhere in | -//| [min(x),max(x)] | -//| Our final recommendation is to use constraints WHEN AND ONLY when| -//| you can't solve your task without them. Anything beyond special | -//| cases given above is not guaranteed and may result in | -//| inconsistency. | -//+------------------------------------------------------------------+ -static void CLSFit::Spline1DFitHermiteWC(double &x[],double &y[],double &w[], - const int n,double &xc[],double &yc[], - int &dc[],const int k,const int m, - int &info,CSpline1DInterpolant &s, - CSpline1DFitReport &rep) - { -//--- create a variable - int i=0; -//--- initialization - info=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(m>=4,__FUNCTION__+": M<4!")) - return; -//--- check - if(!CAp::Assert(m%2==0,__FUNCTION__+": M is odd!")) - return; -//--- check - if(!CAp::Assert(k>=0,__FUNCTION__+": K<0!")) - return; -//--- check - if(!CAp::Assert(k=M!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(Y)=n,__FUNCTION__+": Length(W)=k,__FUNCTION__+": Length(XC)=k,__FUNCTION__+": Length(YC)=k,__FUNCTION__+": Length(DC)=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(m>=4,__FUNCTION__+": M<4!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(Y)=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(m>=4,__FUNCTION__+": M<4!")) - return; -//--- check - if(!CAp::Assert(m%2==0,__FUNCTION__+": M is odd!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(Y)=1. | -//| M - number of basis functions, M>=1. | -//| OUTPUT PARAMETERS: | -//| Info - error code: | -//| * -4 internal SVD decomposition subroutine | -//| failed (very rare and for degenerate | -//| systems only) | -//| * -1 incorrect N/M were specified | -//| * 1 task is solved | -//| C - decomposition coefficients, array[0..M-1] | -//| Rep - fitting report. Following fields are set: | -//| * Rep.TaskRCond reciprocal of condition | -//| number | -//| * RMSError rms error on the (X,Y). | -//| * AvgError average error on the (X,Y). | -//| * AvgRelError average relative error on the| -//| non-zero Y | -//| * MaxError maximum error | -//| NON-WEIGHTED ERRORS ARE | -//| CALCULATED | -//+------------------------------------------------------------------+ -static void CLSFit::LSFitLinearW(double &y[],double &w[],CMatrixDouble &fmatrix, - const int n,const int m,int &info, - double &c[],CLSFitReport &rep) - { -//--- initialization - info=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(m>=1,__FUNCTION__+": M<1!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(y)>=n,__FUNCTION__+": length(Y)=n,__FUNCTION__+": length(W)=n,__FUNCTION__+": rows(FMatrix)=m,__FUNCTION__+": cols(FMatrix)=1. | -//| M - number of basis functions, M>=1. | -//| K - number of constraints, 0 <= K < M | -//| K=0 corresponds to absence of constraints. | -//| OUTPUT PARAMETERS: | -//| Info - error code: | -//| * -4 internal SVD decomposition subroutine | -//| failed (very rare and for degenerate | -//| systems only) | -//| * -3 either too many constraints (M or more), | -//| degenerate constraints (some constraints | -//| are repetead twice) or inconsistent | -//| constraints were specified. | -//| * 1 task is solved | -//| C - decomposition coefficients, array[0..M-1] | -//| Rep - fitting report. Following fields are set: | -//| * RMSError rms error on the (X,Y). | -//| * AvgError average error on the (X,Y). | -//| * AvgRelError average relative error on the| -//| non-zero Y | -//| * MaxError maximum error | -//| NON-WEIGHTED ERRORS ARE | -//| CALCULATED | -//| IMPORTANT: | -//| this subroitine doesn't calculate task's condition number | -//| for K<>0. | -//+------------------------------------------------------------------+ -static void CLSFit::LSFitLinearWC(double &cy[],double &w[],CMatrixDouble &fmatrix, - CMatrixDouble &ccmatrix,const int n, - const int m,const int k,int &info, - double &c[],CLSFitReport &rep) - { -//--- create variables - int i=0; - int j=0; - double v=0; - int i_=0; -//--- create arrays - double tau[]; - double tmp[]; - double c0[]; - double y[]; -//--- create matrix - CMatrixDouble q; - CMatrixDouble f2; - CMatrixDouble cmatrix; -//--- copy array - ArrayCopy(y,cy); -//--- copy matrix - cmatrix=ccmatrix; -//--- initialization - info=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(m>=1,__FUNCTION__+": M<1!")) - return; -//--- check - if(!CAp::Assert(k>=0,__FUNCTION__+": K<0!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(y)>=n,__FUNCTION__+": length(Y)=n,__FUNCTION__+": length(W)=n,__FUNCTION__+": rows(FMatrix)=m,__FUNCTION__+": cols(FMatrix)=k,__FUNCTION__+": rows(CMatrix)=m+1 || k==0,__FUNCTION__+": cols(CMatrix)=m) - { - info=-3; - return; - } -//--- Solve - if(k==0) - { - //--- no constraints - LSFitLinearInternal(y,w,fmatrix,n,m,info,c,rep); - } - else - { - //--- First,find general form solution of constraints system: - //--- * factorize C=L*Q - //--- * unpack Q - //--- * fill upper part of C with zeros (for RCond) - //--- We got C=C0+Q2'*y where Q2 is lower M-K rows of Q. - COrtFac::RMatrixLQ(cmatrix,k,m,tau); - COrtFac::RMatrixLQUnpackQ(cmatrix,k,m,tau,m,q); - for(i=0;i<=k-1;i++) - { - for(j=i+1;j<=m-1;j++) - cmatrix[i].Set(j,0.0); - } - //--- check - if(CRCond::RMatrixLURCondInf(cmatrix,k)<1000*CMath::m_machineepsilon) - { - info=-3; - return; - } - //--- allocation - ArrayResizeAL(tmp,k); - //--- calculation - for(i=0;i<=k-1;i++) - { - //--- check - if(i>0) - { - v=0.0; - for(i_=0;i_<=i-1;i_++) - v+=cmatrix[i][i_]*tmp[i_]; - } - else - v=0; - //--- change values - tmp[i]=(cmatrix[i][m]-v)/cmatrix[i][i]; - } - //--- allocation - ArrayResizeAL(c0,m); - //--- calculation - for(i=0;i<=m-1;i++) - c0[i]=0; - for(i=0;i<=k-1;i++) - { - v=tmp[i]; - for(i_=0;i_<=m-1;i_++) - c0[i_]=c0[i_]+v*q[i][i_]; - } - //--- Second,prepare modified matrix F2=F*Q2' and solve modified task - ArrayResizeAL(tmp,MathMax(n,m)+1); - f2.Resize(n,m-k); - //--- function call - CBlas::MatrixVectorMultiply(fmatrix,0,n-1,0,m-1,false,c0,0,m-1,-1.0,y,0,n-1,1.0); - //--- function call - CBlas::MatrixMatrixMultiply(fmatrix,0,n-1,0,m-1,false,q,k,m-1,0,m-1,true,1.0,f2,0,n-1,0,m-k-1,0.0,tmp); - //--- function call - LSFitLinearInternal(y,w,f2,n,m-k,info,tmp,rep); - rep.m_taskrcond=-1; - //--- check - if(info<=0) - return; - //--- then,convert back to original answer: C=C0 + Q2'*Y0 - ArrayResizeAL(c,m); - for(i_=0;i_<=m-1;i_++) - c[i_]=c0[i_]; - //--- function call - CBlas::MatrixVectorMultiply(q,k,m-1,0,m-1,true,tmp,0,m-k-1,1.0,c,0,m-1,1.0); - } - } -//+------------------------------------------------------------------+ -//| Linear least squares fitting. | -//| QR decomposition is used to reduce task to MxM, then triangular | -//| solver or SVD-based solver is used depending on condition number | -//| of the system. It allows to maximize speed and retain decent | -//| accuracy. | -//| INPUT PARAMETERS: | -//| Y - array[0..N-1] Function values in N points. | -//| FMatrix - a table of basis functions values, | -//| array[0..N-1, 0..M-1]. | -//| FMatrix[I, J] - value of J-th basis function in | -//| I-th point. | -//| N - number of points used. N>=1. | -//| M - number of basis functions, M>=1. | -//| OUTPUT PARAMETERS: | -//| Info - error code: | -//| * -4 internal SVD decomposition subroutine | -//| failed (very rare and for degenerate | -//| systems only) | -//| * 1 task is solved | -//| C - decomposition coefficients, array[0..M-1] | -//| Rep - fitting report. Following fields are set: | -//| * Rep.TaskRCond reciprocal of condition | -//| number | -//| * RMSError rms error on the (X,Y). | -//| * AvgError average error on the (X,Y). | -//| * AvgRelError average relative error on the| -//| non-zero Y | -//| * MaxError maximum error | -//| NON-WEIGHTED ERRORS ARE | -//| CALCULATED | -//+------------------------------------------------------------------+ -static void CLSFit::LSFitLinear(double &y[],CMatrixDouble &fmatrix, - const int n,const int m,int &info, - double &c[],CLSFitReport &rep) - { -//--- create a variable - int i=0; -//--- create array - double w[]; -//--- initialization - info=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(m>=1,__FUNCTION__+": M<1!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(y)>=n,__FUNCTION__+": length(Y)=n,__FUNCTION__+": rows(FMatrix)=m,__FUNCTION__+": cols(FMatrix)=1. | -//| M - number of basis functions, M>=1. | -//| K - number of constraints, 0 <= K < M | -//| K=0 corresponds to absence of constraints. | -//| OUTPUT PARAMETERS: | -//| Info - error code: | -//| * -4 internal SVD decomposition subroutine | -//| failed (very rare and for degenerate | -//| systems only) | -//| * -3 either too many constraints (M or more), | -//| degenerate constraints (some constraints | -//| are repetead twice) or inconsistent | -//| constraints were specified. | -//| * 1 task is solved | -//| C - decomposition coefficients, array[0..M-1] | -//| Rep - fitting report. Following fields are set: | -//| * RMSError rms error on the (X,Y). | -//| * AvgError average error on the (X,Y). | -//| * AvgRelError average relative error on the| -//| non-zero Y | -//| * MaxError maximum error | -//| NON-WEIGHTED ERRORS ARE | -//| CALCULATED | -//| IMPORTANT: | -//| this subroitine doesn't calculate task's condition number | -//| for K<>0. | -//+------------------------------------------------------------------+ -static void CLSFit::LSFitLinearC(double &cy[],CMatrixDouble &fmatrix, - CMatrixDouble &cmatrix,const int n, - const int m,const int k,int &info, - double &c[],CLSFitReport &rep) - { -//--- create a variable - int i=0; -//--- create arrays - double w[]; - double y[]; -//--- copy array - ArrayCopy(y,cy); -//--- initialization - info=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(m>=1,__FUNCTION__+": M<1!")) - return; -//--- check - if(!CAp::Assert(k>=0,__FUNCTION__+": K<0!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(y)>=n,__FUNCTION__+": length(Y)=n,__FUNCTION__+": rows(FMatrix)=m,__FUNCTION__+": cols(FMatrix)=k,__FUNCTION__+": rows(CMatrix)=m+1 || k==0,__FUNCTION__+": cols(CMatrix)1 | -//| M - dimension of space | -//| K - number of parameters being fitted | -//| DiffStep- numerical differentiation step; | -//| should not be very small or large; | -//| large = loss of accuracy | -//| small = growth of round-off errors | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//+------------------------------------------------------------------+ -static void CLSFit::LSFitCreateWF(CMatrixDouble &x,double &y[],double &w[], - double &c[],const int n,const int m, - const int k,const double diffstep, - CLSFitState &state) - { -//--- create variables - int i=0; - int i_=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(m>=1,__FUNCTION__+": M<1!")) - return; -//--- check - if(!CAp::Assert(k>=1,__FUNCTION__+": K<1!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(c)>=k,__FUNCTION__+": length(C)=n,__FUNCTION__+": length(Y)=n,__FUNCTION__+": length(W)=n,__FUNCTION__+": rows(X)=m,__FUNCTION__+": cols(X)0.0,__FUNCTION__+": DiffStep<=0!")) - return; -//--- initialization - state.m_npoints=n; - state.m_nweights=n; - state.m_wkind=1; - state.m_m=m; - state.m_k=k; -//--- function call - LSFitSetCond(state,0.0,0.0,0); -//--- function call - LSFitSetStpMax(state,0.0); -//--- function call - LSFitSetXRep(state,false); -//--- allocation - state.m_taskx.Resize(n,m); - ArrayResizeAL(state.m_tasky,n); - ArrayResizeAL(state.m_w,n); - ArrayResizeAL(state.m_c,k); - ArrayResizeAL(state.m_x,m); -//--- copy - for(i_=0;i_<=k-1;i_++) - state.m_c[i_]=c[i_]; - for(i_=0;i_<=n-1;i_++) - state.m_w[i_]=w[i_]; - for(i=0;i<=n-1;i++) - { - for(i_=0;i_<=m-1;i_++) - state.m_taskx[i].Set(i_,x[i][i_]); - state.m_tasky[i]=y[i]; - } -//--- allocation - ArrayResizeAL(state.m_s,k); - ArrayResizeAL(state.m_bndl,k); - ArrayResizeAL(state.m_bndu,k); -//--- change values - for(i=0;i<=k-1;i++) - { - state.m_s[i]=1.0; - state.m_bndl[i]=CInfOrNaN::NegativeInfinity(); - state.m_bndu[i]=CInfOrNaN::PositiveInfinity(); - } -//--- change values - state.m_optalgo=0; - state.m_prevnpt=-1; - state.m_prevalgo=-1; -//--- function call - CMinLM::MinLMCreateV(k,n,state.m_c,diffstep,state.m_optstate); -//--- function call - LSFitClearRequestFields(state); -//--- allocation - ArrayResizeAL(state.m_rstate.ia,5); - ArrayResizeAL(state.m_rstate.ra,3); - state.m_rstate.stage=-1; - } -//+------------------------------------------------------------------+ -//| Nonlinear least squares fitting using function values only. | -//| Combination of numerical differentiation and secant updates is | -//| used to obtain function Jacobian. | -//| Nonlinear task min(F(c)) is solved, where | -//| F(c) = (f(c,x[0])-y[0])^2 + ... + (f(c,x[n-1])-y[n-1])^2, | -//| * N is a number of points, | -//| * M is a dimension of a space points belong to, | -//| * K is a dimension of a space of parameters being fitted, | -//| * w is an N-dimensional vector of weight coefficients, | -//| * x is a set of N points, each of them is an M-dimensional | -//| vector, | -//| * c is a K-dimensional vector of parameters being fitted | -//| This subroutine uses only f(c,x[i]). | -//| INPUT PARAMETERS: | -//| X - array[0..N-1,0..M-1], points (one row = one | -//| point) | -//| Y - array[0..N-1], function values. | -//| C - array[0..K-1], initial approximation to the | -//| solution, | -//| N - number of points, N>1 | -//| M - dimension of space | -//| K - number of parameters being fitted | -//| DiffStep- numerical differentiation step; | -//| should not be very small or large; | -//| large = loss of accuracy | -//| small = growth of round-off errors | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//+------------------------------------------------------------------+ -static void CLSFit::LSFitCreateF(CMatrixDouble &x,double &y[],double &c[], - const int n,const int m,const int k, - const double diffstep,CLSFitState &state) - { -//--- create variables - int i=0; - int i_=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(m>=1,__FUNCTION__+": M<1!")) - return; -//--- check - if(!CAp::Assert(k>=1,__FUNCTION__+": K<1!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(c)>=k,__FUNCTION__+": length(C)=n,__FUNCTION__+": length(Y)=n,__FUNCTION__+": rows(X)=m,__FUNCTION__+": cols(X)=n,__FUNCTION__+": rows(X)=m,__FUNCTION__+": cols(X)0.0,__FUNCTION__+": DiffStep<=0!")) - return; -//--- initialization - state.m_npoints=n; - state.m_wkind=0; - state.m_m=m; - state.m_k=k; -//--- function call - LSFitSetCond(state,0.0,0.0,0); -//--- function call - LSFitSetStpMax(state,0.0); -//--- function call - LSFitSetXRep(state,false); -//--- allocation - state.m_taskx.Resize(n,m); - ArrayResizeAL(state.m_tasky,n); - ArrayResizeAL(state.m_c,k); - ArrayResizeAL(state.m_x,m); -//--- copy - for(i_=0;i_<=k-1;i_++) - state.m_c[i_]=c[i_]; - for(i=0;i<=n-1;i++) - { - for(i_=0;i_<=m-1;i_++) - state.m_taskx[i].Set(i_,x[i][i_]); - state.m_tasky[i]=y[i]; - } -//--- allocation - ArrayResizeAL(state.m_s,k); - ArrayResizeAL(state.m_bndl,k); - ArrayResizeAL(state.m_bndu,k); -//--- change values - for(i=0;i<=k-1;i++) - { - state.m_s[i]=1.0; - state.m_bndl[i]=CInfOrNaN::NegativeInfinity(); - state.m_bndu[i]=CInfOrNaN::PositiveInfinity(); - } -//--- change values - state.m_optalgo=0; - state.m_prevnpt=-1; - state.m_prevalgo=-1; -//--- function call - CMinLM::MinLMCreateV(k,n,state.m_c,diffstep,state.m_optstate); -//--- function call - LSFitClearRequestFields(state); -//--- allocation - ArrayResizeAL(state.m_rstate.ia,5); - ArrayResizeAL(state.m_rstate.ra,3); - state.m_rstate.stage=-1; - } -//+------------------------------------------------------------------+ -//| Weighted nonlinear least squares fitting using gradient only. | -//| Nonlinear task min(F(c)) is solved, where | -//| F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + | -//| + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, | -//| * N is a number of points, | -//| * M is a dimension of a space points belong to, | -//| * K is a dimension of a space of parameters being fitted, | -//| * w is an N-dimensional vector of weight coefficients, | -//| * x is a set of N points, each of them is an M-dimensional | -//| vector, | -//| * c is a K-dimensional vector of parameters being fitted | -//| This subroutine uses only f(c,x[i]) and its gradient. | -//| INPUT PARAMETERS: | -//| X - array[0..N-1,0..M-1], points (one row = one | -//| point) | -//| Y - array[0..N-1], function values. | -//| W - weights, array[0..N-1] | -//| C - array[0..K-1], initial approximation to the | -//| solution, | -//| N - number of points, N>1 | -//| M - dimension of space | -//| K - number of parameters being fitted | -//| CheapFG - boolean flag, which is: | -//| * True if both function and gradient calculation | -//| complexity are less than O(M^2). An | -//| improved algorithm can be used which | -//| corresponds to FGJ scheme from MINLM unit.| -//| * False otherwise. | -//| Standard Jacibian-bases | -//| Levenberg-Marquardt algo will be used (FJ | -//| scheme). | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| See also: | -//| LSFitResults | -//| LSFitCreateFG (fitting without weights) | -//| LSFitCreateWFGH (fitting using Hessian) | -//| LSFitCreateFGH (fitting using Hessian, without weights) | -//+------------------------------------------------------------------+ -static void CLSFit::LSFitCreateWFG(CMatrixDouble &x,double &y[],double &w[], - double &c[],const int n,const int m, - const int k,bool cheapfg,CLSFitState &state) - { -//--- create variables - int i=0; - int i_=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(m>=1,__FUNCTION__+": M<1!")) - return; -//--- check - if(!CAp::Assert(k>=1,__FUNCTION__+": K<1!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(c)>=k,__FUNCTION__+": length(C)=n,__FUNCTION__+": length(Y)=n,__FUNCTION__+": length(W)=n,__FUNCTION__+": rows(X)=m,__FUNCTION__+": cols(X)1 | -//| M - dimension of space | -//| K - number of parameters being fitted | -//| CheapFG - boolean flag, which is: | -//| * True if both function and gradient calculation| -//| complexity are less than O(M^2). An | -//| improved algorithm can be used which | -//| corresponds to FGJ scheme from MINLM | -//| unit. | -//| * False otherwise. | -//| Standard Jacibian-bases | -//| Levenberg-Marquardt algo will be used | -//| (FJ scheme). | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//+------------------------------------------------------------------+ -static void CLSFit::LSFitCreateFG(CMatrixDouble &x,double &y[],double &c[], - const int n,const int m,const int k, - const bool cheapfg,CLSFitState &state) - { -//--- create variables - int i=0; - int i_=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(m>=1,__FUNCTION__+": M<1!")) - return; -//--- check - if(!CAp::Assert(k>=1,__FUNCTION__+": K<1!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(c)>=k,__FUNCTION__+": length(C)=n,__FUNCTION__+": length(Y)=n,__FUNCTION__+": rows(X)=m,__FUNCTION__+": cols(X)=n,__FUNCTION__+": rows(X)=m,__FUNCTION__+": cols(X)1 | -//| M - dimension of space | -//| K - number of parameters being fitted | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//+------------------------------------------------------------------+ -static void CLSFit::LSFitCreateWFGH(CMatrixDouble &x,double &y[],double &w[], - double &c[],const int n,const int m, - const int k,CLSFitState &state) - { -//--- create variables - int i=0; - int i_=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(m>=1,__FUNCTION__+": M<1!")) - return; -//--- check - if(!CAp::Assert(k>=1,__FUNCTION__+": K<1!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(c)>=k,__FUNCTION__+": length(C)=n,__FUNCTION__+": length(Y)=n,__FUNCTION__+": length(W)=n,__FUNCTION__+": rows(X)=m,__FUNCTION__+": cols(X)1 | -//| M - dimension of space | -//| K - number of parameters being fitted | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//+------------------------------------------------------------------+ -static void CLSFit::LSFitCreateFGH(CMatrixDouble &x,double &y[],double &c[], - const int n,const int m,const int k, - CLSFitState &state) - { -//--- create variables - int i=0; - int i_=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(m>=1,__FUNCTION__+": M<1!")) - return; -//--- check - if(!CAp::Assert(k>=1,__FUNCTION__+": K<1!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(c)>=k,__FUNCTION__+": length(C)=n,__FUNCTION__+": length(Y)=n,__FUNCTION__+": rows(X)=m,__FUNCTION__+": cols(X)=0 | -//| The subroutine finishes its work if on k+1-th | -//| iteration the condition |v|<=EpsX is fulfilled, | -//| where: | -//| * |.| means Euclidian norm | -//| * v - scaled step vector, v[i]=dx[i]/s[i] | -//| * dx - ste pvector, dx=X(k+1)-X(k) | -//| * s - scaling coefficients set by LSFitSetScale()| -//| MaxIts - maximum number of iterations. If MaxIts=0, the | -//| number of iterations is unlimited. Only | -//| Levenberg-Marquardt iterations are counted | -//| (L-BFGS/CG iterations are NOT counted because | -//| their cost is very low compared to that of LM). | -//| NOTE | -//| Passing EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to| -//| automatic stopping criterion selection (according to the scheme | -//| used by MINLM unit). | -//+------------------------------------------------------------------+ -static void CLSFit::LSFitSetCond(CLSFitState &state,const double epsf, - const double epsx,const int maxits) - { -//--- check - if(!CAp::Assert(CMath::IsFinite(epsf),__FUNCTION__+": EpsF is not finite!")) - return; -//--- check - if(!CAp::Assert((double)(epsf)>=0.0,__FUNCTION__+": negative EpsF!")) - return; -//--- check - if(!CAp::Assert(CMath::IsFinite(epsx),__FUNCTION__+": EpsX is not finite!")) - return; -//--- check - if(!CAp::Assert((double)(epsx)>=0.0,__FUNCTION__+": negative EpsX!")) - return; -//--- check - if(!CAp::Assert(maxits>=0,__FUNCTION__+": negative MaxIts!")) - return; -//--- change values - state.m_epsf=epsf; - state.m_epsx=epsx; - state.m_maxits=maxits; - } -//+------------------------------------------------------------------+ -//| This function sets maximum step length | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| StpMax - maximum step length, >=0. Set StpMax to 0.0, if | -//| you don't want to limit step length. | -//| Use this subroutine when you optimize target function which | -//| contains exp() or other fast growing functions, and optimization | -//| algorithm makes too large steps which leads to overflow. This | -//| function allows us to reject steps that are too large (and | -//| therefore expose us to the possible overflow) without actually | -//| calculating function value at the x+stp*d. | -//| NOTE: non-zero StpMax leads to moderate performance degradation | -//| because intermediate step of preconditioned L-BFGS optimization | -//| is incompatible with limits on step size. | -//+------------------------------------------------------------------+ -static void CLSFit::LSFitSetStpMax(CLSFitState &state,const double stpmax) - { -//--- check - if(!CAp::Assert(stpmax>=0.0,__FUNCTION__+": StpMax<0!")) - return; -//--- change value - state.m_stpmax=stpmax; - } -//+------------------------------------------------------------------+ -//| This function turns on/off reporting. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NeedXRep- whether iteration reports are needed or not | -//| When reports are needed, State.C (current parameters) and State. | -//| F (current value of fitting function) are reported. | -//+------------------------------------------------------------------+ -static void CLSFit::LSFitSetXRep(CLSFitState &state,const bool needxrep) - { -//--- change value - state.m_xrep=needxrep; - } -//+------------------------------------------------------------------+ -//| This function sets scaling coefficients for underlying optimizer.| -//| ALGLIB optimizers use scaling matrices to test stopping | -//| conditions (step size and gradient are scaled before comparison | -//| with tolerances). Scale of the I-th variable is a translation | -//| invariant measure of: | -//| a) "how large" the variable is | -//| b) how large the step should be to make significant changes in | -//| the function | -//| Generally, scale is NOT considered to be a form of | -//| preconditioner. But LM optimizer is unique in that it uses | -//| scaling matrix both in the stopping condition tests and as | -//| Marquardt damping factor. | -//| Proper scaling is very important for the algorithm performance. | -//| It is less important for the quality of results, but still has | -//| some influence (it is easier to converge when variables are | -//| properly scaled, so premature stopping is possible when very | -//| badly scalled variables are combined with relaxed stopping | -//| conditions). | -//| INPUT PARAMETERS: | -//| State - structure stores algorithm state | -//| S - array[N], non-zero scaling coefficients | -//| S[i] may be negative, sign doesn't matter. | -//+------------------------------------------------------------------+ -static void CLSFit::LSFitSetScale(CLSFitState &state,double &s[]) - { -//--- create a variable - int i=0; -//--- check - if(!CAp::Assert(CAp::Len(s)>=state.m_k,__FUNCTION__+": Length(S)=k,__FUNCTION__+": Length(BndL)=k,__FUNCTION__+": Length(BndU)BndU[i]")) - return; - } - //--- change values - state.m_bndl[i]=bndl[i]; - state.m_bndu[i]=bndu[i]; - } - } -//+------------------------------------------------------------------+ -//| Nonlinear least squares fitting results. | -//| Called after return from LSFitFit(). | -//| INPUT PARAMETERS: | -//| State - algorithm state | -//| OUTPUT PARAMETERS: | -//| Info - completetion code: | -//| * 1 relative function improvement is no | -//| more than EpsF. | -//| * 2 relative step is no more than EpsX. | -//| * 4 gradient norm is no more than EpsG | -//| * 5 MaxIts steps was taken | -//| * 7 stopping conditions are too | -//| stringent, further improvement is | -//| impossible | -//| C - array[0..K-1], solution | -//| Rep - optimization report. Following fields are set: | -//| * Rep.TerminationType completetion code: | -//| * RMSError rms error on the (X,Y). | -//| * AvgError average error on the (X,Y). | -//| * AvgRelError average relative error on the| -//| non-zero Y | -//| * MaxError maximum error | -//| NON-WEIGHTED ERRORS ARE | -//| CALCULATED | -//| * WRMSError weighted rms error on the | -//| (X,Y). | -//+------------------------------------------------------------------+ -static void CLSFit::LSFitResults(CLSFitState &state,int &info,double &c[], - CLSFitReport &rep) - { -//--- create a variable - int i_=0; -//--- initialization - info=state.m_repterminationtype; -//--- check - if(info>0) - { - //--- allocation - ArrayResizeAL(c,state.m_k); - for(i_=0;i_<=state.m_k-1;i_++) - c[i_]=state.m_c[i_]; - //--- change values - rep.m_rmserror=state.m_reprmserror; - rep.m_wrmserror=state.m_repwrmserror; - rep.m_avgerror=state.m_repavgerror; - rep.m_avgrelerror=state.m_repavgrelerror; - rep.m_maxerror=state.m_repmaxerror; - rep.m_iterationscount=state.m_repiterationscount; - } - } -//+------------------------------------------------------------------+ -//| Internal subroutine: automatic scaling for LLS tasks. | -//| NEVER CALL IT DIRECTLY! | -//| Maps abscissas to [-1,1], standartizes ordinates and | -//| correspondingly scales constraints. It also scales weights so | -//| that max(W[i])=1 | -//| Transformations performed: | -//| * X, XC [XA,XB] => [-1,+1] | -//| transformation makes min(X)=-1, max(X)=+1 | -//| * Y [SA,SB] => [0,1] | -//| transformation makes mean(Y)=0, stddev(Y)=1 | -//| * YC transformed accordingly to SA, SB, DC[I] | -//+------------------------------------------------------------------+ -static void CLSFit::LSFitScaleXY(double &x[],double &y[],double &w[], - const int n,double &xc[],double &yc[], - int &dc[],const int k,double &xa, - double &xb,double &sa,double &sb, - double &xoriginal[],double &yoriginal[]) - { -//--- create variables - double xmin=0; - double xmax=0; - int i=0; - double mx=0; - int i_=0; -//--- initialization - xa=0; - xb=0; - sa=0; - sb=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": incorrect N")) - return; -//--- check - if(!CAp::Assert(k>=0,__FUNCTION__+": incorrect K")) - return; -//--- Calculate xmin/xmax. -//--- Force xmin<>xmax. - xmin=x[0]; - xmax=x[0]; - for(i=1;i<=n-1;i++) - { - xmin=MathMin(xmin,x[i]); - xmax=MathMax(xmax,x[i]); - } - for(i=0;i<=k-1;i++) - { - xmin=MathMin(xmin,xc[i]); - xmax=MathMax(xmax,xc[i]); - } -//--- check - if(xmin==xmax) - { - //--- check - if(xmin==0.0) - { - xmin=-1; - xmax=1; - } - else - { - //--- check - if(xmin>0.0) - xmin=0.5*xmin; - else - xmax=0.5*xmax; - } - } -//--- Transform abscissas: map [XA,XB] to [0,1] -//--- Store old X[] in XOriginal[] (it will be used -//--- to calculate relative error). - ArrayResizeAL(xoriginal,n); - for(i_=0;i_<=n-1;i_++) - xoriginal[i_]=x[i_]; -//--- change values - xa=xmin; - xb=xmax; - for(i=0;i<=n-1;i++) - x[i]=2*(x[i]-0.5*(xa+xb))/(xb-xa); -//--- calculation - for(i=0;i<=k-1;i++) - { - //--- check - if(!CAp::Assert(dc[i]>=0,__FUNCTION__+": internal error!")) - return; - xc[i]=2*(xc[i]-0.5*(xa+xb))/(xb-xa); - yc[i]=yc[i]*MathPow(0.5*(xb-xa),dc[i]); - } -//--- Transform function values: map [SA,SB] to [0,1] -//--- SA=mean(Y), -//--- SB=SA+stddev(Y). -//--- Store old Y[] in YOriginal[] (it will be used -//--- to calculate relative error). - ArrayResizeAL(yoriginal,n); - for(i_=0;i_<=n-1;i_++) - yoriginal[i_]=y[i_]; - sa=0; - for(i=0;i<=n-1;i++) - sa=sa+y[i]; - sa=sa/n; -//--- change value - sb=0; - for(i=0;i<=n-1;i++) - sb=sb+CMath::Sqr(y[i]-sa); - sb=MathSqrt(sb/n)+sa; -//--- check - if(sb==sa) - sb=2*sa; -//--- check - if(sb==sa) - sb=sa+1; - for(i=0;i<=n-1;i++) - y[i]=(y[i]-sa)/(sb-sa); - for(i=0;i<=k-1;i++) - { - //--- check - if(dc[i]==0) - yc[i]=(yc[i]-sa)/(sb-sa); - else - yc[i]=yc[i]/(sb-sa); - } -//--- Scale weights - mx=0; - for(i=0;i<=n-1;i++) - mx=MathMax(mx,MathAbs(w[i])); -//--- check - if(mx!=0.0) - { - for(i=0;i<=n-1;i++) - w[i]=w[i]/mx; - } - } -//+------------------------------------------------------------------+ -//| Internal spline fitting subroutine | -//+------------------------------------------------------------------+ -static void CLSFit::Spline1DFitInternal(const int st,double &cx[],double &cy[], - double &cw[],const int n,double &cxc[], - double &cyc[],int &dc[],const int k, - const int m,int &info, - CSpline1DInterpolant &s, - CSpline1DFitReport &rep) - { -//--- create variables - double v0=0; - double v1=0; - double v2=0; - double mx=0; - int i=0; - int j=0; - int relcnt=0; - double xa=0; - double xb=0; - double sa=0; - double sb=0; - double bl=0; - double br=0; - double decay=0; - int i_=0; -//--- create arrays - double y2[]; - double w2[]; - double sx[]; - double sy[]; - double sd[]; - double tmp[]; - double xoriginal[]; - double yoriginal[]; - double x[]; - double y[]; - double w[]; - double xc[]; - double yc[]; -//--- create matrix - CMatrixDouble fmatrix; - CMatrixDouble cmatrix; -//--- objects of classes - CLSFitReport lrep; - CSpline1DInterpolant s2; -//--- copy arrays - ArrayCopy(x,cx); - ArrayCopy(y,cy); - ArrayCopy(w,cw); - ArrayCopy(xc,cxc); - ArrayCopy(yc,cyc); -//--- initialization - info=0; -//--- check - if(!CAp::Assert(st==0 || st==1,__FUNCTION__+": internal error!")) - return; -//--- check - if(st==0 && m<4) - { - info=-1; - return; - } -//--- check - if(st==1 && m<4) - { - info=-1; - return; - } -//--- check - if((n<1 || k<0) || k>=m) - { - info=-1; - return; - } - for(i=0;i<=k-1;i++) - { - info=0; - //--- check - if(dc[i]<0) - info=-1; - //--- check - if(dc[i]>1) - info=-1; - //--- check - if(info<0) - return; - } -//--- check - if(st==1 && m%2!=0) - { - //--- Hermite fitter must have even number of basis functions - info=-2; - return; - } -//--- weight decay for correct handling of task which becomes -//--- degenerate after constraints are applied - decay=10000*CMath::m_machineepsilon; -//--- Scale X,Y,XC,YC - LSFitScaleXY(x,y,w,n,xc,yc,dc,k,xa,xb,sa,sb,xoriginal,yoriginal); -//--- allocate space,initialize: -//--- * SX - grid for basis functions -//--- * SY - values of basis functions at grid points -//--- * FMatrix- values of basis functions at X[] -//--- * CMatrix- values (derivatives) of basis functions at XC[] - ArrayResizeAL(y2,n+m); - ArrayResizeAL(w2,n+m); - fmatrix.Resize(n+m,m); -//--- check - if(k>0) - cmatrix.Resize(k,m+1); -//--- check - if(st==0) - { - //--- allocate space for cubic spline - ArrayResizeAL(sx,m-2); - ArrayResizeAL(sy,m-2); - for(j=0;j<=m-2-1;j++) - sx[j]=(double)(2*j)/(double)(m-2-1)-1; - } -//--- check - if(st==1) - { - //--- allocate space for Hermite spline - ArrayResizeAL(sx,m/2); - ArrayResizeAL(sy,m/2); - ArrayResizeAL(sd,m/2); - for(j=0;j<=m/2-1;j++) - sx[j]=(double)(2*j)/(double)(m/2-1)-1; - } -//--- Prepare design and constraints matrices: -//--- * fill constraints matrix -//--- * fill first N rows of design matrix with values -//--- * fill next M rows of design matrix with regularizing term -//--- * append M zeros to Y -//--- * append M elements,mean(abs(W)) each,to W - for(j=0;j<=m-1;j++) - { - //--- prepare Jth basis function - if(st==0) - { - //--- cubic spline basis - for(i=0;i<=m-2-1;i++) - sy[i]=0; - bl=0; - br=0; - //--- check - if(j=0 && dc[i]<=2,__FUNCTION__+": internal error!")) - return; - //--- function call - CSpline1D::Spline1DDiff(s2,xc[i],v0,v1,v2); - //--- check - if(dc[i]==0) - cmatrix[i].Set(j,v0); - //--- check - if(dc[i]==1) - cmatrix[i].Set(j,v1); - //--- check - if(dc[i]==2) - cmatrix[i].Set(j,v2); - } - } -//--- calculation - for(i=0;i<=k-1;i++) - cmatrix[i].Set(m,yc[i]); - for(i=0;i<=m-1;i++) - { - for(j=0;j<=m-1;j++) - { - //--- check - if(i==j) - fmatrix[n+i].Set(j,decay); - else - fmatrix[n+i].Set(j,0); - } - } -//--- allocation - ArrayResizeAL(y2,n+m); - ArrayResizeAL(w2,n+m); -//--- copy - for(i_=0;i_<=n-1;i_++) - y2[i_]=y[i_]; - for(i_=0;i_<=n-1;i_++) - w2[i_]=w[i_]; -//--- change value - mx=0; - for(i=0;i<=n-1;i++) - mx=mx+MathAbs(w[i]); - mx=mx/n; - for(i=0;i<=m-1;i++) - { - y2[n+i]=0; - w2[n+i]=mx; - } -//--- Solve constrained task - if(k>0) - { - //--- solve using regularization - LSFitLinearWC(y2,w2,fmatrix,cmatrix,n+m,m,k,info,tmp,lrep); - } - else - { - //--- no constraints,no regularization needed - LSFitLinearWC(y,w,fmatrix,cmatrix,n,m,k,info,tmp,lrep); - } -//--- check - if(info<0) - return; -//--- Generate spline and scale it - if(st==0) - { - //--- cubic spline basis - for(i_=0;i_<=m-2-1;i_++) - sy[i_]=tmp[i_]; - //--- function call - CSpline1D::Spline1DBuildCubic(sx,sy,m-2,1,tmp[m-2],1,tmp[m-1],s); - } -//--- check - if(st==1) - { - //--- Hermite basis - for(i=0;i<=m/2-1;i++) - { - sy[i]=tmp[2*i]; - sd[i]=tmp[2*i+1]; - } - //--- function call - CSpline1D::Spline1DBuildHermite(sx,sy,sd,m/2,s); - } -//--- function call - CSpline1D::Spline1DLinTransX(s,2/(xb-xa),-((xa+xb)/(xb-xa))); -//--- function call - CSpline1D::Spline1DLinTransY(s,sb-sa,sa); -//--- Scale absolute errors obtained from LSFitLinearW. -//--- Relative error should be calculated separately -//--- (because of shifting/scaling of the task) - rep.m_taskrcond=lrep.m_taskrcond; - rep.m_rmserror=lrep.m_rmserror*(sb-sa); - rep.m_avgerror=lrep.m_avgerror*(sb-sa); - rep.m_maxerror=lrep.m_maxerror*(sb-sa); - rep.m_avgrelerror=0; - relcnt=0; - for(i=0;i<=n-1;i++) - { - //--- check - if(yoriginal[i]!=0.0) - { - rep.m_avgrelerror=rep.m_avgrelerror+MathAbs(CSpline1D::Spline1DCalc(s,xoriginal[i])-yoriginal[i])/MathAbs(yoriginal[i]); - relcnt=relcnt+1; - } - } -//--- check - if(relcnt!=0) - rep.m_avgrelerror=rep.m_avgrelerror/relcnt; - } -//+------------------------------------------------------------------+ -//| Internal fitting subroutine | -//+------------------------------------------------------------------+ -static void CLSFit::LSFitLinearInternal(double &y[],double &w[], - CMatrixDouble &fmatrix,const int n, - const int m,int &info,double &c[], - CLSFitReport &rep) - { -//--- create variables - double threshold=0; - int i=0; - int j=0; - double v=0; - int relcnt=0; - int i_=0; -//--- create arrays - double b[]; - double wmod[]; - double tau[]; - double sv[]; - double tmp[]; - double utb[]; - double sutb[]; -//--- create matrix - CMatrixDouble ft; - CMatrixDouble q; - CMatrixDouble l; - CMatrixDouble r; - CMatrixDouble u; - CMatrixDouble vt; -//--- initialization - info=0; -//--- check - if(n<1 || m<1) - { - info=-1; - return; - } -//--- initialization - info=1; - threshold=MathSqrt(CMath::m_machineepsilon); -//--- Degenerate case,needs special handling - if(n=M. Generate design matrix and reduce to N=M using -//--- QR decomposition. - ft.Resize(n,m); - ArrayResizeAL(b,n); - for(j=0;j<=n-1;j++) - { - v=w[j]; - for(i_=0;i_<=m-1;i_++) - ft[j].Set(i_,v*fmatrix[j][i_]); - b[j]=w[j]*y[j]; - } -//--- function call - COrtFac::RMatrixQR(ft,n,m,tau); -//--- function call - COrtFac::RMatrixQRUnpackQ(ft,n,m,tau,m,q); -//--- function call - COrtFac::RMatrixQRUnpackR(ft,n,m,r); -//--- allocation - ArrayResizeAL(tmp,m); - for(i=0;i<=m-1;i++) - tmp[i]=0; -//--- calculation - for(i=0;i<=n-1;i++) - { - v=b[i]; - for(i_=0;i_<=m-1;i_++) - tmp[i_]=tmp[i_]+v*q[i][i_]; - } -//--- allocation - ArrayResizeAL(b,m); -//--- copy - for(i_=0;i_<=m-1;i_++) - b[i_]=tmp[i_]; -//--- R contains reduced MxM design upper triangular matrix, -//--- B contains reduced Mx1 right part. -//--- Determine system condition number and decide -//--- should we use triangular solver (faster) or -//--- SVD-based solver (more stable). -//--- We can use LU-based RCond estimator for this task. - rep.m_taskrcond=CRCond::RMatrixLURCondInf(r,m); -//--- check - if(rep.m_taskrcond>threshold) - { - //--- use QR-based solver - ArrayResizeAL(c,m); - c[m-1]=b[m-1]/r[m-1][m-1]; - //--- calculation - for(i=m-2;i>=0;i--) - { - v=0.0; - for(i_=i+1;i_<=m-1;i_++) - v+=r[i][i_]*c[i_]; - c[i]=(b[i]-v)/r[i][i]; - } - } - else - { - //--- use SVD-based solver - if(!CSingValueDecompose::RMatrixSVD(r,m,m,1,1,2,sv,u,vt)) - { - info=-4; - return; - } - //--- allocation - ArrayResizeAL(utb,m); - ArrayResizeAL(sutb,m); - for(i=0;i<=m-1;i++) - utb[i]=0; - //--- calculation - for(i=0;i<=m-1;i++) - { - v=b[i]; - for(i_=0;i_<=m-1;i_++) - utb[i_]=utb[i_]+v*u[i][i_]; - } - //--- check - if(sv[0]>0.0) - { - rep.m_taskrcond=sv[m-1]/sv[0]; - for(i=0;i<=m-1;i++) - { - //--- check - if(sv[i]>threshold*sv[0]) - sutb[i]=utb[i]/sv[i]; - else - sutb[i]=0; - } - } - else - { - //--- change values - rep.m_taskrcond=0; - for(i=0;i<=m-1;i++) - sutb[i]=0; - } - //--- allocation - ArrayResizeAL(c,m); - for(i=0;i<=m-1;i++) - c[i]=0; - //--- calculation - for(i=0;i<=m-1;i++) - { - v=sutb[i]; - for(i_=0;i_<=m-1;i_++) - c[i_]=c[i_]+v*vt[i][i_]; - } - } -//--- calculate errors - rep.m_rmserror=0; - rep.m_avgerror=0; - rep.m_avgrelerror=0; - rep.m_maxerror=0; - relcnt=0; -//--- calculation - for(i=0;i<=n-1;i++) - { - v=0.0; - for(i_=0;i_<=m-1;i_++) - v+=fmatrix[i][i_]*c[i_]; - //--- change values - rep.m_rmserror=rep.m_rmserror+CMath::Sqr(v-y[i]); - rep.m_avgerror=rep.m_avgerror+MathAbs(v-y[i]); - //--- check - if(y[i]!=0.0) - { - rep.m_avgrelerror=rep.m_avgrelerror+MathAbs(v-y[i])/MathAbs(y[i]); - relcnt=relcnt+1; - } - rep.m_maxerror=MathMax(rep.m_maxerror,MathAbs(v-y[i])); - } -//--- change values - rep.m_rmserror=MathSqrt(rep.m_rmserror/n); - rep.m_avgerror=rep.m_avgerror/n; -//--- check - if(relcnt!=0) - rep.m_avgrelerror=rep.m_avgrelerror/relcnt; - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static void CLSFit::LSFitClearRequestFields(CLSFitState &state) - { -//--- change values - state.m_needf=false; - state.m_needfg=false; - state.m_needfgh=false; - state.m_xupdated=false; - } -//+------------------------------------------------------------------+ -//| Internal subroutine, calculates barycentric basis functions. | -//| Used for efficient simultaneous calculation of N basis functions.| -//+------------------------------------------------------------------+ -static void CLSFit::BarycentricCalcBasis(CBarycentricInterpolant &b, - const double t,double &y[]) - { -//--- create variables - double s2=0; - double s=0; - double v=0; - int i=0; - int j=0; - int i_=0; -//--- special case: N=1 - if(b.m_n==1) - { - y[0]=1; - return; - } -//--- Here we assume that task is normalized,i.m_e.: -//--- 1. abs(Y[i])<=1 -//--- 2. abs(W[i])<=1 -//--- 3. X[] is ordered -//--- First,we decide: should we use "safe" formula (guarded -//--- against overflow) or fast one? - s=MathAbs(t-b.m_x[0]); - for(i=0;i<=b.m_n-1;i++) - { - v=b.m_x[i]; - //--- check - if(v==t) - { - for(j=0;j<=b.m_n-1;j++) - y[j]=0; - y[i]=1; - //--- exit the function - return; - } - //--- change value - v=MathAbs(t-v); - //--- check - if(v0. | -//| XC - points where polynomial values/derivatives are | -//| constrained, array[0..K-1]. | -//| YC - values of constraints, array[0..K-1] | -//| DC - array[0..K-1], types of constraints: | -//| * DC[i]=0 means that P(XC[i])=YC[i] | -//| * DC[i]=1 means that P'(XC[i])=YC[i] | -//| K - number of constraints, 0<=K=1 | -//| OUTPUT PARAMETERS: | -//| Info- same format as in LSFitLinearW() subroutine: | -//| * Info>0 task is solved | -//| * Info<=0 an error occured: | -//| -4 means inconvergence of internal SVD | -//| -3 means inconsistent constraints | -//| C - interpolant in Chebyshev form; [-1,+1] is used as | -//| base interval | -//| Rep - report, same format as in LSFitLinearW() subroutine. | -//| Following fields are set: | -//| * RMSError rms error on the (X,Y). | -//| * AvgError average error on the (X,Y). | -//| * AvgRelError average relative error on the | -//| non-zero Y | -//| * MaxError maximum error | -//| NON-WEIGHTED ERRORS ARE CALCULATED | -//| IMPORTANT: | -//| this subroitine doesn't calculate task's condition number for| -//| K<>0. | -//+------------------------------------------------------------------+ -static void CLSFit::InternalChebyshevFit(double &x[],double &y[],double &w[], - const int n,double &cxc[],double &cyc[], - int &dc[],const int k,const int m, - int &info,double &c[],CLSFitReport &rep) - { -//--- create variables - int i=0; - int j=0; - double mx=0; - double decay=0; - int i_=0; -//--- create arrays - double y2[]; - double w2[]; - double tmp[]; - double tmp2[]; - double tmpdiff[]; - double bx[]; - double by[]; - double bw[]; - double xc[]; - double yc[]; -//--- create matrix - CMatrixDouble fmatrix; - CMatrixDouble cmatrix; -//--- copy arrays - ArrayCopy(xc,cxc); - ArrayCopy(yc,cyc); -//--- initialization - info=0; -//--- weight decay for correct handling of task which becomes -//--- degenerate after constraints are applied - decay=10000*CMath::m_machineepsilon; -//--- allocate space,initialize/fill: -//--- * FMatrix- values of basis functions at X[] -//--- * CMatrix- values (derivatives) of basis functions at XC[] -//--- * fill constraints matrix -//--- * fill first N rows of design matrix with values -//--- * fill next M rows of design matrix with regularizing term -//--- * append M zeros to Y -//--- * append M elements,mean(abs(W)) each,to W - ArrayResizeAL(y2,n+m); - ArrayResizeAL(w2,n+m); - ArrayResizeAL(tmp,m); - ArrayResizeAL(tmpdiff,m); - fmatrix.Resize(n+m,m); -//--- check - if(k>0) - cmatrix.Resize(k,m+1); -//--- Fill design matrix,Y2,W2: -//--- * first N rows with basis functions for original points -//--- * next M rows with decay terms - for(i=0;i<=n-1;i++) - { - //--- prepare Ith row - //--- use Tmp for calculations to avoid multidimensional arrays overhead - for(j=0;j<=m-1;j++) - { - //--- check - if(j==0) - tmp[j]=1; - else - { - //--- check - if(j==1) - tmp[j]=x[i]; - else - tmp[j]=2*x[i]*tmp[j-1]-tmp[j-2]; - } - } - //--- copy - for(i_=0;i_<=m-1;i_++) - fmatrix[i].Set(i_,tmp[i_]); - } -//--- calculation - for(i=0;i<=m-1;i++) - { - for(j=0;j<=m-1;j++) - { - //--- check - if(i==j) - fmatrix[n+i].Set(j,decay); - else - fmatrix[n+i].Set(j,0); - } - } -//--- copy - for(i_=0;i_<=n-1;i_++) - y2[i_]=y[i_]; - for(i_=0;i_<=n-1;i_++) - w2[i_]=w[i_]; -//--- change value - mx=0; - for(i=0;i<=n-1;i++) - mx=mx+MathAbs(w[i]); - mx=mx/n; -//--- change values - for(i=0;i<=m-1;i++) - { - y2[n+i]=0; - w2[n+i]=mx; - } -//--- fill constraints matrix - for(i=0;i<=k-1;i++) - { - //--- prepare Ith row - //--- use Tmp for basis function values, - //--- TmpDiff for basos function derivatives - for(j=0;j<=m-1;j++) - { - //--- check - if(j==0) - { - tmp[j]=1; - tmpdiff[j]=0; - } - else - { - //--- check - if(j==1) - { - tmp[j]=xc[i]; - tmpdiff[j]=1; - } - else - { - tmp[j]=2*xc[i]*tmp[j-1]-tmp[j-2]; - tmpdiff[j]=2*(tmp[j-1]+xc[i]*tmpdiff[j-1])-tmpdiff[j-2]; - } - } - } - //--- check - if(dc[i]==0) - { - for(i_=0;i_<=m-1;i_++) - cmatrix[i].Set(i_,tmp[i_]); - } - //--- check - if(dc[i]==1) - { - for(i_=0;i_<=m-1;i_++) - cmatrix[i].Set(i_,tmpdiff[i_]); - } - cmatrix[i].Set(m,yc[i]); - } -//--- Solve constrained task - if(k>0) - { - //--- solve using regularization - LSFitLinearWC(y2,w2,fmatrix,cmatrix,n+m,m,k,info,c,rep); - } - else - { - //--- no constraints,no regularization needed - LSFitLinearWC(y,w,fmatrix,cmatrix,n,m,0,info,c,rep); - } -//--- check - if(info<0) - return; - } -//+------------------------------------------------------------------+ -//| Internal Floater-Hormann fitting subroutine for fixed D | -//+------------------------------------------------------------------+ -static void CLSFit::BarycentricFitWCFixedD(double &cx[],double &cy[], - double &cw[],const int n, - double &cxc[],double &cyc[], - int &dc[],const int k,const int m, - const int d,int &info, - CBarycentricInterpolant &b, - CBarycentricFitReport &rep) - { -//--- create variables - double v0=0; - double v1=0; - double mx=0; - int i=0; - int j=0; - int relcnt=0; - double xa=0; - double xb=0; - double sa=0; - double sb=0; - double decay=0; - int i_=0; -//--- create arrays - double y2[]; - double w2[]; - double sx[]; - double sy[]; - double sbf[]; - double xoriginal[]; - double yoriginal[]; - double tmp[]; - double x[]; - double y[]; - double w[]; - double xc[]; - double yc[]; -//--- create matrix - CMatrixDouble fmatrix; - CMatrixDouble cmatrix; -//--- objects of classes - CLSFitReport lrep; - CBarycentricInterpolant b2; -//--- copy arrays - ArrayCopy(x,cx); - ArrayCopy(y,cy); - ArrayCopy(w,cw); - ArrayCopy(xc,cxc); - ArrayCopy(yc,cyc); -//--- initialization - info=0; -//--- check - if(((n<1 || m<2) || k<0) || k>=m) - { - info=-1; - return; - } - for(i=0;i<=k-1;i++) - { - info=0; - //--- check - if(dc[i]<0) - info=-1; - //--- check - if(dc[i]>1) - info=-1; - //--- check - if(info<0) - return; - } -//--- weight decay for correct handling of task which becomes -//--- degenerate after constraints are applied - decay=10000*CMath::m_machineepsilon; -//--- Scale X,Y,XC,YC - LSFitScaleXY(x,y,w,n,xc,yc,dc,k,xa,xb,sa,sb,xoriginal,yoriginal); -//--- allocate space,initialize: -//--- * FMatrix- values of basis functions at X[] -//--- * CMatrix- values (derivatives) of basis functions at XC[] - ArrayResizeAL(y2,n+m); - ArrayResizeAL(w2,n+m); - fmatrix.Resize(n+m,m); -//--- check - if(k>0) - cmatrix.Resize(k,m+1); -//--- allocation - ArrayResizeAL(y2,n+m); - ArrayResizeAL(w2,n+m); -//--- Prepare design and constraints matrices: -//--- * fill constraints matrix -//--- * fill first N rows of design matrix with values -//--- * fill next M rows of design matrix with regularizing term -//--- * append M zeros to Y -//--- * append M elements,mean(abs(W)) each,to W - ArrayResizeAL(sx,m); - ArrayResizeAL(sy,m); - ArrayResizeAL(sbf,m); - for(j=0;j<=m-1;j++) - sx[j]=(double)(2*j)/(double)(m-1)-1; - for(i=0;i<=m-1;i++) - sy[i]=1; -//--- function call - CRatInt::BarycentricBuildFloaterHormann(sx,sy,m,d,b2); -//--- change value - mx=0; -//--- calculation - for(i=0;i<=n-1;i++) - { - //--- function call - BarycentricCalcBasis(b2,x[i],sbf); - for(i_=0;i_<=m-1;i_++) - fmatrix[i].Set(i_,sbf[i_]); - //--- change values - y2[i]=y[i]; - w2[i]=w[i]; - mx=mx+MathAbs(w[i])/n; - } -//--- calculation - for(i=0;i<=m-1;i++) - { - for(j=0;j<=m-1;j++) - { - //--- check - if(i==j) - fmatrix[n+i].Set(j,decay); - else - fmatrix[n+i].Set(j,0); - } - //--- change values - y2[n+i]=0; - w2[n+i]=mx; - } -//--- check - if(k>0) - { - for(j=0;j<=m-1;j++) - { - for(i=0;i<=m-1;i++) - sy[i]=0; - sy[j]=1; - //--- function call - CRatInt::BarycentricBuildFloaterHormann(sx,sy,m,d,b2); - //--- calculation - for(i=0;i<=k-1;i++) - { - //--- check - if(!CAp::Assert(dc[i]>=0 && dc[i]<=1,__FUNCTION__+": internal error!")) - return; - //--- function call - CRatInt::BarycentricDiff1(b2,xc[i],v0,v1); - //--- check - if(dc[i]==0) - cmatrix[i].Set(j,v0); - //--- check - if(dc[i]==1) - cmatrix[i].Set(j,v1); - } - } - for(i=0;i<=k-1;i++) - cmatrix[i].Set(m,yc[i]); - } -//--- Solve constrained task - if(k>0) - { - //--- solve using regularization - LSFitLinearWC(y2,w2,fmatrix,cmatrix,n+m,m,k,info,tmp,lrep); - } - else - { - //--- no constraints,no regularization needed - LSFitLinearWC(y,w,fmatrix,cmatrix,n,m,k,info,tmp,lrep); - } -//--- check - if(info<0) - return; -//--- Generate interpolant and scale it - for(i_=0;i_<=m-1;i_++) - sy[i_]=tmp[i_]; -//--- function call - CRatInt::BarycentricBuildFloaterHormann(sx,sy,m,d,b); -//--- function call - CRatInt::BarycentricLinTransX(b,2/(xb-xa),-((xa+xb)/(xb-xa))); -//--- function call - CRatInt::BarycentricLinTransY(b,sb-sa,sa); -//--- Scale absolute errors obtained from LSFitLinearW. -//--- Relative error should be calculated separately -//--- (because of shifting/scaling of the task) - rep.m_taskrcond=lrep.m_taskrcond; - rep.m_rmserror=lrep.m_rmserror*(sb-sa); - rep.m_avgerror=lrep.m_avgerror*(sb-sa); - rep.m_maxerror=lrep.m_maxerror*(sb-sa); - rep.m_avgrelerror=0; - relcnt=0; - for(i=0;i<=n-1;i++) - { - //--- check - if(yoriginal[i]!=0.0) - { - rep.m_avgrelerror=rep.m_avgrelerror+MathAbs(CRatInt::BarycentricCalc(b,xoriginal[i])-yoriginal[i])/MathAbs(yoriginal[i]); - relcnt=relcnt+1; - } - } -//--- check - if(relcnt!=0) - rep.m_avgrelerror=rep.m_avgrelerror/relcnt; - } -//+------------------------------------------------------------------+ -//| NOTES: | -//| 1. this algorithm is somewhat unusual because it works with | -//| parameterized function f(C,X), where X is a function argument | -//| (we have many points which are characterized by different | -//| argument values), and C is a parameter to fit. | -//| For example, if we want to do linear fit by f(c0,c1,x) = | -//| = c0*x+c1, then x will be argument, and {c0,c1} will be | -//| parameters. | -//| It is important to understand that this algorithm finds | -//| minimum in the space of function PARAMETERS (not arguments), | -//| so it needs derivatives of f() with respect to C, not X. | -//| In the example above it will need f=c0*x+c1 and | -//| {df/dc0,df/dc1} = {x,1} instead of {df/dx} = {c0}. | -//| 2. Callback functions accept C as the first parameter, and X as | -//| the second | -//| 3. If state was created with LSFitCreateFG(), algorithm needs | -//| just function and its gradient, but if state was created with | -//| LSFitCreateFGH(), algorithm will need function, gradient and | -//| Hessian. | -//| According to the said above, there ase several versions of | -//| this function, which accept different sets of callbacks. | -//| This flexibility opens way to subtle errors - you may create | -//| state with LSFitCreateFGH() (optimization using Hessian), but | -//| call function which does not accept Hessian. So when algorithm| -//| will request Hessian, there will be no callback to call. In | -//| this case exception will be thrown. | -//| Be careful to avoid such errors because there is no way to | -//| find them at compile time - you can see them at runtime only. | -//+------------------------------------------------------------------+ -static bool CLSFit::LSFitIteration(CLSFitState &state) - { -//--- create variables - int n=0; - int m=0; - int k=0; - int i=0; - int j=0; - double v=0; - double vv=0; - double relcnt=0; - int i_=0; -//--- Reverse communication preparations -//--- I know it looks ugly,but it works the same way -//--- anywhere from C++ to Python. -// -//--- This code initializes locals by: -//--- * random values determined during code -//--- generation - on first subroutine call -//--- * values from previous call - on subsequent calls - if(state.m_rstate.stage>=0) - { - //--- initialization - n=state.m_rstate.ia[0]; - m=state.m_rstate.ia[1]; - k=state.m_rstate.ia[2]; - i=state.m_rstate.ia[3]; - j=state.m_rstate.ia[4]; - v=state.m_rstate.ra[0]; - vv=state.m_rstate.ra[1]; - relcnt=state.m_rstate.ra[2]; - } - else - { - //--- initialization - n=-983; - m=-989; - k=-834; - i=900; - j=-287; - v=364; - vv=214; - relcnt=-338; - } -//--- check - if(state.m_rstate.stage==0) - { - //--- change value - state.m_needf=false; - //--- check - if(state.m_wkind==1) - vv=state.m_w[i]; - else - vv=1.0; - //--- change values - state.m_optstate.m_fi[i]=vv*(state.m_f-state.m_tasky[i]); - i=i+1; - //--- function call, return result - return(Func_lbl_11(state,n,m,k,i,j,v,vv,relcnt)); - } -//--- check - if(state.m_rstate.stage==1) - { - //--- change value - state.m_needf=false; - //--- check - if(state.m_wkind==1) - vv=state.m_w[i]; - else - vv=1.0; - //--- change values - state.m_optstate.m_f=state.m_optstate.m_f+CMath::Sqr(vv*(state.m_f-state.m_tasky[i])); - i=i+1; - //--- function call, return result - return(Func_lbl_16(state,n,m,k,i,j,v,vv,relcnt)); - } -//--- check - if(state.m_rstate.stage==2) - { - //--- change value - state.m_needfg=false; - //--- check - if(state.m_wkind==1) - vv=state.m_w[i]; - else - vv=1.0; - //--- change values - state.m_optstate.m_f=state.m_optstate.m_f+CMath::Sqr(vv*(state.m_f-state.m_tasky[i])); - v=CMath::Sqr(vv)*2*(state.m_f-state.m_tasky[i]); - for(i_=0;i_<=k-1;i_++) - state.m_optstate.m_g[i_]=state.m_optstate.m_g[i_]+v*state.m_g[i_]; - i=i+1; - //--- function call, return result - return(Func_lbl_21(state,n,m,k,i,j,v,vv,relcnt)); - } -//--- check - if(state.m_rstate.stage==3) - { - //--- change value - state.m_needfg=false; - //--- check - if(state.m_wkind==1) - vv=state.m_w[i]; - else - vv=1.0; - //--- change values - state.m_optstate.m_fi[i]=vv*(state.m_f-state.m_tasky[i]); - for(i_=0;i_<=k-1;i_++) - state.m_optstate.m_j[i].Set(i_,vv*state.m_g[i_]); - i=i+1; - //--- function call, return result - return(Func_lbl_26(state,n,m,k,i,j,v,vv,relcnt)); - } -//--- check - if(state.m_rstate.stage==4) - { - //--- change value - state.m_needfgh=false; - //--- check - if(state.m_wkind==1) - vv=state.m_w[i]; - else - vv=1.0; - //--- change values - state.m_optstate.m_f=state.m_optstate.m_f+CMath::Sqr(vv*(state.m_f-state.m_tasky[i])); - v=CMath::Sqr(vv)*2*(state.m_f-state.m_tasky[i]); - for(i_=0;i_<=k-1;i_++) - state.m_optstate.m_g[i_]=state.m_optstate.m_g[i_]+v*state.m_g[i_]; - //--- calculation - for(j=0;j<=k-1;j++) - { - v=2*CMath::Sqr(vv)*state.m_g[j]; - for(i_=0;i_<=k-1;i_++) - state.m_optstate.m_h[j].Set(i_,state.m_optstate.m_h[j][i_]+v*state.m_g[i_]); - v=2*CMath::Sqr(vv)*(state.m_f-state.m_tasky[i]); - for(i_=0;i_<=k-1;i_++) - state.m_optstate.m_h[j].Set(i_,state.m_optstate.m_h[j][i_]+v*state.m_h[j][i_]); - } - i=i+1; - //--- function call, return result - return(Func_lbl_31(state,n,m,k,i,j,v,vv,relcnt)); - } -//--- check - if(state.m_rstate.stage==5) - { - //--- change value - state.m_xupdated=false; - //--- function call, return result - return(Func_lbl_7(state,n,m,k,i,j,v,vv,relcnt)); - } -//--- check - if(state.m_rstate.stage==6) - { - //--- change values - state.m_needf=false; - v=state.m_f; - //--- check - if(state.m_wkind==1) - vv=state.m_w[i]; - else - vv=1.0; - //--- change values - state.m_reprmserror=state.m_reprmserror+CMath::Sqr(v-state.m_tasky[i]); - state.m_repwrmserror=state.m_repwrmserror+CMath::Sqr(vv*(v-state.m_tasky[i])); - state.m_repavgerror=state.m_repavgerror+MathAbs(v-state.m_tasky[i]); - //--- check - if(state.m_tasky[i]!=0.0) - { - state.m_repavgrelerror=state.m_repavgrelerror+MathAbs(v-state.m_tasky[i])/MathAbs(state.m_tasky[i]); - relcnt=relcnt+1; - } - //--- change values - state.m_repmaxerror=MathMax(state.m_repmaxerror,MathAbs(v-state.m_tasky[i])); - i=i+1; - //--- function call, return result - return(Func_lbl_38(state,n,m,k,i,j,v,vv,relcnt)); - } -//--- Routine body -//--- init - if(state.m_wkind==1) - { - //--- check - if(!CAp::Assert(state.m_npoints==state.m_nweights,__FUNCTION__+": number of points is not equal to the number of weights")) - return(false); - } -//--- change values - n=state.m_npoints; - m=state.m_m; - k=state.m_k; -//--- function call - CMinLM::MinLMSetCond(state.m_optstate,0.0,state.m_epsf,state.m_epsx,state.m_maxits); -//--- function call - CMinLM::MinLMSetStpMax(state.m_optstate,state.m_stpmax); -//--- function call - CMinLM::MinLMSetXRep(state.m_optstate,state.m_xrep); -//--- function call - CMinLM::MinLMSetScale(state.m_optstate,state.m_s); -//--- function call - CMinLM::MinLMSetBC(state.m_optstate,state.m_bndl,state.m_bndu); -//--- Optimize - return(Func_lbl_7(state,n,m,k,i,j,v,vv,relcnt)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for LSFitIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static void CLSFit::Func_lbl_rcomm(CLSFitState &state,int n,int m,int k,int i, - int j,double v,double vv,double relcnt) - { -//--- Saving state - state.m_rstate.ia[0]=n; - state.m_rstate.ia[1]=m; - state.m_rstate.ia[2]=k; - state.m_rstate.ia[3]=i; - state.m_rstate.ia[4]=j; - state.m_rstate.ra[0]=v; - state.m_rstate.ra[1]=vv; - state.m_rstate.ra[2]=relcnt; - } -//+------------------------------------------------------------------+ -//| Auxiliary function for LSFitIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CLSFit::Func_lbl_7(CLSFitState &state,int &n,int &m,int &k,int &i, - int &j,double &v,double &vv,double &relcnt) - { -//--- check - if(!CMinLM::MinLMIteration(state.m_optstate)) - { - //--- function call - CMinLM::MinLMResults(state.m_optstate,state.m_c,state.m_optrep); - //--- change values - state.m_repterminationtype=state.m_optrep.m_terminationtype; - state.m_repiterationscount=state.m_optrep.m_iterationscount; - //--- calculate errors - if(state.m_repterminationtype<=0) - return(false); - //--- change values - state.m_reprmserror=0; - state.m_repwrmserror=0; - state.m_repavgerror=0; - state.m_repavgrelerror=0; - state.m_repmaxerror=0; - relcnt=0; - i=0; - //--- function call, return result - return(Func_lbl_38(state,n,m,k,i,j,v,vv,relcnt)); - } -//--- check - if(!state.m_optstate.m_needfi) - { - //--- check - if(!state.m_optstate.m_needf) - return(Func_lbl_14(state,n,m,k,i,j,v,vv,relcnt)); - //--- calculate F=sum (wi*(f(xi,c)-yi))^2 - state.m_optstate.m_f=0; - i=0; - //--- function call, return result - return(Func_lbl_16(state,n,m,k,i,j,v,vv,relcnt)); - } -//--- calculate f[]=wi*(f(xi,c)-yi) - i=0; -//--- function call, return result - return(Func_lbl_11(state,n,m,k,i,j,v,vv,relcnt)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for LSFitIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CLSFit::Func_lbl_11(CLSFitState &state,int &n,int &m,int &k,int &i, - int &j,double &v,double &vv,double &relcnt) - { -//--- check - if(i>n-1) - return(Func_lbl_7(state,n,m,k,i,j,v,vv,relcnt)); -//--- copy - for(int i_=0;i_<=k-1;i_++) - state.m_c[i_]=state.m_optstate.m_x[i_]; - for(int i_=0;i_<=m-1;i_++) - state.m_x[i_]=state.m_taskx[i][i_]; - state.m_pointindex=i; -//--- function call - LSFitClearRequestFields(state); -//--- change values - state.m_needf=true; - state.m_rstate.stage=0; -//--- Saving state - Func_lbl_rcomm(state,n,m,k,i,j,v,vv,relcnt); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for LSFitIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CLSFit::Func_lbl_14(CLSFitState &state,int &n,int &m,int &k,int &i, - int &j,double &v,double &vv,double &relcnt) - { -//--- check - if(!state.m_optstate.m_needfg) - { - //--- check - if(!state.m_optstate.m_needfij) - return(Func_lbl_24(state,n,m,k,i,j,v,vv,relcnt)); - //--- calculate Fi/jac(Fi) - i=0; - //--- function call, return result - return(Func_lbl_26(state,n,m,k,i,j,v,vv,relcnt)); - } -//--- calculate F/gradF - state.m_optstate.m_f=0; - for(i=0;i<=k-1;i++) - state.m_optstate.m_g[i]=0; - i=0; -//--- function call, return result - return(Func_lbl_21(state,n,m,k,i,j,v,vv,relcnt)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for LSFitIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CLSFit::Func_lbl_16(CLSFitState &state,int &n,int &m,int &k,int &i, - int &j,double &v,double &vv,double &relcnt) - { -//--- check - if(i>n-1) - return(Func_lbl_7(state,n,m,k,i,j,v,vv,relcnt)); -//--- copy - for(int i_=0;i_<=k-1;i_++) - state.m_c[i_]=state.m_optstate.m_x[i_]; - for(int i_=0;i_<=m-1;i_++) - state.m_x[i_]=state.m_taskx[i][i_]; - state.m_pointindex=i; -//--- function call - LSFitClearRequestFields(state); -//--- change values - state.m_needf=true; - state.m_rstate.stage=1; -//--- Saving state - Func_lbl_rcomm(state,n,m,k,i,j,v,vv,relcnt); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for LSFitIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CLSFit::Func_lbl_21(CLSFitState &state,int &n,int &m,int &k,int &i, - int &j,double &v,double &vv,double &relcnt) - { -//--- check - if(i>n-1) - return(Func_lbl_7(state,n,m,k,i,j,v,vv,relcnt)); -//--- copy - for(int i_=0;i_<=k-1;i_++) - state.m_c[i_]=state.m_optstate.m_x[i_]; - for(int i_=0;i_<=m-1;i_++) - state.m_x[i_]=state.m_taskx[i][i_]; - state.m_pointindex=i; -//--- function call - LSFitClearRequestFields(state); -//--- change values - state.m_needfg=true; - state.m_rstate.stage=2; -//--- Saving state - Func_lbl_rcomm(state,n,m,k,i,j,v,vv,relcnt); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for LSFitIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CLSFit::Func_lbl_24(CLSFitState &state,int &n,int &m,int &k,int &i, - int &j,double &v,double &vv,double &relcnt) - { -//--- check - if(!state.m_optstate.m_needfgh) - return(Func_lbl_29(state,n,m,k,i,j,v,vv,relcnt)); -//--- calculate F/grad(F)/hess(F) - state.m_optstate.m_f=0; - for(i=0;i<=k-1;i++) - state.m_optstate.m_g[i]=0; - for(i=0;i<=k-1;i++) - { - for(j=0;j<=k-1;j++) - state.m_optstate.m_h[i].Set(j,0); - } -//--- change value - i=0; -//--- function call, return result - return(Func_lbl_31(state,n,m,k,i,j,v,vv,relcnt)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for LSFitIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CLSFit::Func_lbl_26(CLSFitState &state,int &n,int &m,int &k,int &i, - int &j,double &v,double &vv,double &relcnt) - { -//--- check - if(i>n-1) - return(Func_lbl_7(state,n,m,k,i,j,v,vv,relcnt)); -//--- copy - for(int i_=0;i_<=k-1;i_++) - state.m_c[i_]=state.m_optstate.m_x[i_]; - for(int i_=0;i_<=m-1;i_++) - state.m_x[i_]=state.m_taskx[i][i_]; - state.m_pointindex=i; -//--- function call - LSFitClearRequestFields(state); -//--- change values - state.m_needfg=true; - state.m_rstate.stage=3; -//--- Saving state - Func_lbl_rcomm(state,n,m,k,i,j,v,vv,relcnt); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for LSFitIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CLSFit::Func_lbl_29(CLSFitState &state,int &n,int &m,int &k,int &i, - int &j,double &v,double &vv,double &relcnt) - { -//--- check - if(!state.m_optstate.m_xupdated) - return(Func_lbl_7(state,n,m,k,i,j,v,vv,relcnt)); -//--- Report new iteration - for(int i_=0;i_<=k-1;i_++) - state.m_c[i_]=state.m_optstate.m_x[i_]; - state.m_f=state.m_optstate.m_f; -//--- function call - LSFitClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_rstate.stage=5; -//--- Saving state - Func_lbl_rcomm(state,n,m,k,i,j,v,vv,relcnt); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for LSFitIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CLSFit::Func_lbl_31(CLSFitState &state,int &n,int &m,int &k,int &i, - int &j,double &v,double &vv,double &relcnt) - { -//--- check - if(i>n-1) - return(Func_lbl_7(state,n,m,k,i,j,v,vv,relcnt)); -//--- copy - for(int i_=0;i_<=k-1;i_++) - state.m_c[i_]=state.m_optstate.m_x[i_]; - for(int i_=0;i_<=m-1;i_++) - state.m_x[i_]=state.m_taskx[i][i_]; - state.m_pointindex=i; -//--- function call - LSFitClearRequestFields(state); -//--- change values - state.m_needfgh=true; - state.m_rstate.stage=4; -//--- Saving state - Func_lbl_rcomm(state,n,m,k,i,j,v,vv,relcnt); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for LSFitIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CLSFit::Func_lbl_38(CLSFitState &state,int &n,int &m,int &k,int &i, - int &j,double &v,double &vv,double &relcnt) - { -//--- check - if(i>n-1) - { - //--- change values - state.m_reprmserror=MathSqrt(state.m_reprmserror/n); - state.m_repwrmserror=MathSqrt(state.m_repwrmserror/n); - state.m_repavgerror=state.m_repavgerror/n; - //--- check - if(relcnt!=0.0) - state.m_repavgrelerror=state.m_repavgrelerror/relcnt; - //--- return result - return(false); - } -//--- copy - for(int i_=0;i_<=k-1;i_++) - state.m_c[i_]=state.m_c[i_]; - for(int i_=0;i_<=m-1;i_++) - state.m_x[i_]=state.m_taskx[i][i_]; - state.m_pointindex=i; -//--- function call - LSFitClearRequestFields(state); -//--- change values - state.m_needf=true; - state.m_rstate.stage=6; -//--- Saving state - Func_lbl_rcomm(state,n,m,k,i,j,v,vv,relcnt); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Parametric spline inteprolant: 2-dimensional curve. | -//| You should not try to access its members directly - use | -//| PSpline2XXXXXXXX() functions instead. | -//+------------------------------------------------------------------+ -class CPSpline2Interpolant - { -public: - //--- variables - int m_n; - bool m_periodic; - CSpline1DInterpolant m_x; - CSpline1DInterpolant m_y; - //--- array - double m_p[]; - //--- constructor, destructor - CPSpline2Interpolant(void); - ~CPSpline2Interpolant(void); - //--- copy - void Copy(CPSpline2Interpolant &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CPSpline2Interpolant::CPSpline2Interpolant(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CPSpline2Interpolant::~CPSpline2Interpolant(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CPSpline2Interpolant::Copy(CPSpline2Interpolant &obj) - { -//--- copy variables - m_n=obj.m_n; - m_periodic=obj.m_periodic; - m_x.Copy(obj.m_x); - m_y.Copy(obj.m_y); -//--- copy array - ArrayCopy(m_p,obj.m_p); - } -//+------------------------------------------------------------------+ -//| Parametric spline inteprolant: 2-dimensional curve. | -//| You should not try to access its members directly - use | -//| PSpline2XXXXXXXX() functions instead. | -//+------------------------------------------------------------------+ -class CPSpline2InterpolantShell - { -private: - CPSpline2Interpolant m_innerobj; -public: - //--- constructors, destructor - CPSpline2InterpolantShell(void); - CPSpline2InterpolantShell(CPSpline2Interpolant &obj); - ~CPSpline2InterpolantShell(void); - //--- method - CPSpline2Interpolant *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CPSpline2InterpolantShell::CPSpline2InterpolantShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CPSpline2InterpolantShell::CPSpline2InterpolantShell(CPSpline2Interpolant &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CPSpline2InterpolantShell::~CPSpline2InterpolantShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CPSpline2Interpolant *CPSpline2InterpolantShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Parametric spline inteprolant: 3-dimensional curve. | -//| You should not try to access its members directly - use | -//| PSpline3XXXXXXXX() functions instead. | -//+------------------------------------------------------------------+ -class CPSpline3Interpolant - { -public: - //--- variables - int m_n; - bool m_periodic; - CSpline1DInterpolant m_x; - CSpline1DInterpolant m_y; - CSpline1DInterpolant m_z; - //--- array - double m_p[]; - //--- constructor, destructor - CPSpline3Interpolant(void); - ~CPSpline3Interpolant(void); - //--- copy - void Copy(CPSpline3Interpolant &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CPSpline3Interpolant::CPSpline3Interpolant(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CPSpline3Interpolant::~CPSpline3Interpolant(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CPSpline3Interpolant::Copy(CPSpline3Interpolant &obj) - { -//--- copy variables - m_n=obj.m_n; - m_periodic=obj.m_periodic; - m_x.Copy(obj.m_x); - m_y.Copy(obj.m_y); - m_z.Copy(obj.m_z); -//--- copy array - ArrayCopy(m_p,obj.m_p); - } -//+------------------------------------------------------------------+ -//| Parametric spline inteprolant: 3-dimensional curve. | -//| You should not try to access its members directly - use | -//| PSpline3XXXXXXXX() functions instead. | -//+------------------------------------------------------------------+ -class CPSpline3InterpolantShell - { -private: - CPSpline3Interpolant m_innerobj; -public: - //--- constructors, destructor - CPSpline3InterpolantShell(void); - CPSpline3InterpolantShell(CPSpline3Interpolant &obj); - ~CPSpline3InterpolantShell(void); - //--- method - CPSpline3Interpolant *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CPSpline3InterpolantShell::CPSpline3InterpolantShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CPSpline3InterpolantShell::CPSpline3InterpolantShell(CPSpline3Interpolant &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CPSpline3InterpolantShell::~CPSpline3InterpolantShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CPSpline3Interpolant *CPSpline3InterpolantShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Parametric spline | -//+------------------------------------------------------------------+ -class CPSpline - { -private: - //--- private methods - static void PSpline2Par(CMatrixDouble &xy,const int n,const int pt,double &p[]); - static void PSpline3Par(CMatrixDouble &xy,const int n,const int pt,double &p[]); -public: - //--- constructor, destructor - CPSpline(void); - ~CPSpline(void); - //--- public methods - static void PSpline2Build(CMatrixDouble &cxy,const int n,const int st,const int pt,CPSpline2Interpolant &p); - static void PSpline3Build(CMatrixDouble &cxy,const int n,const int st,const int pt,CPSpline3Interpolant &p); - static void PSpline2BuildPeriodic(CMatrixDouble &cxy,const int n,const int st,const int pt,CPSpline2Interpolant &p); - static void PSpline3BuildPeriodic(CMatrixDouble &cxy,const int n,const int st,const int pt,CPSpline3Interpolant &p); - static void PSpline2ParameterValues(CPSpline2Interpolant &p,int &n,double &t[]); - static void PSpline3ParameterValues(CPSpline3Interpolant &p,int &n,double &t[]); - static void PSpline2Calc(CPSpline2Interpolant &p,double t,double &x,double &y); - static void PSpline3Calc(CPSpline3Interpolant &p,double t,double &x,double &y,double &z); - static void PSpline2Tangent(CPSpline2Interpolant &p,double t,double &x,double &y); - static void PSpline3Tangent(CPSpline3Interpolant &p,double t,double &x,double &y,double &z); - static void PSpline2Diff(CPSpline2Interpolant &p,double t,double &x,double &dx,double &y,double &dy); - static void PSpline3Diff(CPSpline3Interpolant &p,double t,double &x,double &dx,double &y,double &dy,double &z,double &dz); - static void PSpline2Diff2(CPSpline2Interpolant &p,double t,double &x,double &dx,double &d2x,double &y,double &dy,double &d2y); - static void PSpline3Diff2(CPSpline3Interpolant &p,double t,double &x,double &dx,double &d2x,double &y,double &dy,double &d2y,double &z,double &dz,double &d2z); - static double PSpline2ArcLength(CPSpline2Interpolant &p,const double a,const double b); - static double PSpline3ArcLength(CPSpline3Interpolant &p,const double a,const double b); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CPSpline::CPSpline(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CPSpline::~CPSpline(void) - { - - } -//+------------------------------------------------------------------+ -//| This function builds non-periodic 2-dimensional parametric | -//| spline which starts at (X[0],Y[0]) and ends at (X[N-1],Y[N-1]). | -//| INPUT PARAMETERS: | -//| XY - points, array[0..N-1,0..1]. | -//| XY[I,0:1] corresponds to the Ith point. | -//| Order of points is important! | -//| N - points count, N>=5 for Akima splines, N>=2 for other | -//| types of splines. | -//| ST - spline type: | -//| * 0 Akima spline | -//| * 1 parabolically terminated Catmull-Rom spline | -//| (Tension=0) | -//| * 2 parabolically terminated cubic spline | -//| PT - parameterization type: | -//| * 0 uniform | -//| * 1 chord length | -//| * 2 centripetal | -//| OUTPUT PARAMETERS: | -//| P - parametric spline interpolant | -//| NOTES: | -//| * this function assumes that there all consequent points are | -//| distinct. I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), | -//| (x2,y2)<>(x3,y3) and so on. However, non-consequent points may | -//| coincide, i.e. we can have (x0,y0) = (x2,y2). | -//+------------------------------------------------------------------+ -static void CPSpline::PSpline2Build(CMatrixDouble &cxy,const int n, - const int st,const int pt, - CPSpline2Interpolant &p) - { -//--- create a variable - int i_=0; -//--- create array - double tmp[]; -//--- copy matrix - CMatrixDouble xy; - xy=cxy; -//--- check - if(!CAp::Assert(st>=0 && st<=2,__FUNCTION__+": incorrect spline type!")) - return; -//--- check - if(!CAp::Assert(pt>=0 && pt<=2,__FUNCTION__+": incorrect parameterization type!")) - return; -//--- check - if(st==0) - { - //--- check - if(!CAp::Assert(n>=5,__FUNCTION__+": N<5 (minimum value for Akima splines)!")) - return; - } - else - { - //--- check - if(!CAp::Assert(n>=2,__FUNCTION__+": N<2!")) - return; - } -//--- Prepare - p.m_n=n; - p.m_periodic=false; -//--- allocation - ArrayResizeAL(tmp,n); -//--- Build parameterization,check that all parameters are distinct - PSpline2Par(xy,n,pt,p.m_p); -//--- check - if(!CAp::Assert(CApServ::AreDistinct(p.m_p,n),__FUNCTION__+": consequent points are too close!")) - return; -//--- Build splines - if(st==0) - { - //--- copy - for(i_=0;i_<=n-1;i_++) - tmp[i_]=xy[i_][0]; - //--- function call - CSpline1D::Spline1DBuildAkima(p.m_p,tmp,n,p.m_x); - //--- copy - for(i_=0;i_<=n-1;i_++) - tmp[i_]=xy[i_][1]; - //--- function call - CSpline1D::Spline1DBuildAkima(p.m_p,tmp,n,p.m_y); - } -//--- check - if(st==1) - { - //--- copy - for(i_=0;i_<=n-1;i_++) - tmp[i_]=xy[i_][0]; - //--- function call - CSpline1D::Spline1DBuildCatmullRom(p.m_p,tmp,n,0,0.0,p.m_x); - //--- copy - for(i_=0;i_<=n-1;i_++) - tmp[i_]=xy[i_][1]; - //--- function call - CSpline1D::Spline1DBuildCatmullRom(p.m_p,tmp,n,0,0.0,p.m_y); - } -//--- check - if(st==2) - { - //--- copy - for(i_=0;i_<=n-1;i_++) - tmp[i_]=xy[i_][0]; - //--- function call - CSpline1D::Spline1DBuildCubic(p.m_p,tmp,n,0,0.0,0,0.0,p.m_x); - //--- copy - for(i_=0;i_<=n-1;i_++) - tmp[i_]=xy[i_][1]; - //--- function call - CSpline1D::Spline1DBuildCubic(p.m_p,tmp,n,0,0.0,0,0.0,p.m_y); - } - } -//+------------------------------------------------------------------+ -//| This function builds non-periodic 3-dimensional parametric spline| -//| which starts at (X[0],Y[0],Z[0]) and ends at | -//| (X[N-1],Y[N-1],Z[N-1]). | -//| Same as PSpline2Build() function, but for 3D, so we won't | -//| duplicate its description here. | -//+------------------------------------------------------------------+ -static void CPSpline::PSpline3Build(CMatrixDouble &cxy,const int n, - const int st,const int pt, - CPSpline3Interpolant &p) - { -//--- create a variable - int i_=0; -//--- create array - double tmp[]; -//--- copy matrix - CMatrixDouble xy; - xy=cxy; -//--- check - if(!CAp::Assert(st>=0 && st<=2,__FUNCTION__+": incorrect spline type!")) - return; -//--- check - if(!CAp::Assert(pt>=0 && pt<=2,__FUNCTION__+": incorrect parameterization type!")) - return; -//--- check - if(st==0) - { - //--- check - if(!CAp::Assert(n>=5,__FUNCTION__+": N<5 (minimum value for Akima splines)!")) - return; - } - else - { - //--- check - if(!CAp::Assert(n>=2,__FUNCTION__+"PSpline3Build: N<2!")) - return; - } -//--- Prepare - p.m_n=n; - p.m_periodic=false; -//--- allocation - ArrayResizeAL(tmp,n); -//--- Build parameterization,check that all parameters are distinct - PSpline3Par(xy,n,pt,p.m_p); -//--- check - if(!CAp::Assert(CApServ::AreDistinct(p.m_p,n),__FUNCTION__+": consequent points are too close!")) - return; -//--- Build splines - if(st==0) - { - //--- copy - for(i_=0;i_<=n-1;i_++) - tmp[i_]=xy[i_][0]; - //--- function call - CSpline1D::Spline1DBuildAkima(p.m_p,tmp,n,p.m_x); - //--- copy - for(i_=0;i_<=n-1;i_++) - tmp[i_]=xy[i_][1]; - //--- function call - CSpline1D::Spline1DBuildAkima(p.m_p,tmp,n,p.m_y); - //--- copy - for(i_=0;i_<=n-1;i_++) - tmp[i_]=xy[i_][2]; - //--- function call - CSpline1D::Spline1DBuildAkima(p.m_p,tmp,n,p.m_z); - } -//--- check - if(st==1) - { - //--- copy - for(i_=0;i_<=n-1;i_++) - tmp[i_]=xy[i_][0]; - //--- function call - CSpline1D::Spline1DBuildCatmullRom(p.m_p,tmp,n,0,0.0,p.m_x); - //--- copy - for(i_=0;i_<=n-1;i_++) - tmp[i_]=xy[i_][1]; - //--- function call - CSpline1D::Spline1DBuildCatmullRom(p.m_p,tmp,n,0,0.0,p.m_y); - //--- copy - for(i_=0;i_<=n-1;i_++) - tmp[i_]=xy[i_][2]; - //--- function call - CSpline1D::Spline1DBuildCatmullRom(p.m_p,tmp,n,0,0.0,p.m_z); - } -//--- check - if(st==2) - { - //--- copy - for(i_=0;i_<=n-1;i_++) - tmp[i_]=xy[i_][0]; - //--- function call - CSpline1D::Spline1DBuildCubic(p.m_p,tmp,n,0,0.0,0,0.0,p.m_x); - //--- copy - for(i_=0;i_<=n-1;i_++) - tmp[i_]=xy[i_][1]; - //--- function call - CSpline1D::Spline1DBuildCubic(p.m_p,tmp,n,0,0.0,0,0.0,p.m_y); - //--- copy - for(i_=0;i_<=n-1;i_++) - tmp[i_]=xy[i_][2]; - //--- function call - CSpline1D::Spline1DBuildCubic(p.m_p,tmp,n,0,0.0,0,0.0,p.m_z); - } - } -//+------------------------------------------------------------------+ -//| This function builds periodic 2-dimensional parametric spline | -//| which starts at (X[0],Y[0]), goes through all points to | -//| (X[N-1],Y[N-1]) and then back to (X[0],Y[0]). | -//| INPUT PARAMETERS: | -//| XY - points, array[0..N-1,0..1]. | -//| XY[I,0:1] corresponds to the Ith point. | -//| XY[N-1,0:1] must be different from XY[0,0:1]. | -//| Order of points is important! | -//| N - points count, N>=3 for other types of splines. | -//| ST - spline type: | -//| * 1 Catmull-Rom spline (Tension=0) with cyclic | -//| boundary conditions | -//| * 2 cubic spline with cyclic boundary conditions | -//| PT - parameterization type: | -//| * 0 uniform | -//| * 1 chord length | -//| * 2 centripetal | -//| OUTPUT PARAMETERS: | -//| P - parametric spline interpolant | -//| NOTES: | -//| * this function assumes that there all consequent points are | -//| distinct. I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), | -//| (x2,y2)<>(x3,y3) and so on. However, non-consequent points may | -//| coincide, i.e. we can have (x0,y0) = (x2,y2). | -//| * last point of sequence is NOT equal to the first point. You | -//| shouldn't make curve "explicitly periodic" by making them | -//| equal. | -//+------------------------------------------------------------------+ -static void CPSpline::PSpline2BuildPeriodic(CMatrixDouble &cxy,const int n, - const int st,const int pt, - CPSpline2Interpolant &p) - { -//--- create a variable - int i_=0; -//--- create array - double tmp[]; -//--- create matrix - CMatrixDouble xyp; - CMatrixDouble xy; -//--- copy matrix - xy=cxy; -//--- check - if(!CAp::Assert(st>=1 && st<=2,__FUNCTION__+": incorrect spline type!")) - return; -//--- check - if(!CAp::Assert(pt>=0 && pt<=2,__FUNCTION__+": incorrect parameterization type!")) - return; -//--- check - if(!CAp::Assert(n>=3,__FUNCTION__+": N<3!")) - return; -//--- Prepare - p.m_n=n; - p.m_periodic=true; -//--- allocation - ArrayResizeAL(tmp,n+1); - xyp.Resize(n+1,2); -//--- change values - for(i_=0;i_<=n-1;i_++) - xyp[i_].Set(0,xy[i_][0]); - for(i_=0;i_<=n-1;i_++) - xyp[i_].Set(1,xy[i_][1]); - for(i_=0;i_<=1;i_++) - xyp[n].Set(i_,xy[0][i_]); -//--- Build parameterization,check that all parameters are distinct - PSpline2Par(xyp,n+1,pt,p.m_p); -//--- check - if(!CAp::Assert(CApServ::AreDistinct(p.m_p,n+1),__FUNCTION__+": consequent (or first and last) points are too close!")) - return; -//--- Build splines - if(st==1) - { - //--- copy - for(i_=0;i_<=n;i_++) - tmp[i_]=xyp[i_][0]; - //--- function call - CSpline1D::Spline1DBuildCatmullRom(p.m_p,tmp,n+1,-1,0.0,p.m_x); - //--- copy - for(i_=0;i_<=n;i_++) - tmp[i_]=xyp[i_][1]; - //--- function call - CSpline1D::Spline1DBuildCatmullRom(p.m_p,tmp,n+1,-1,0.0,p.m_y); - } -//--- check - if(st==2) - { - //--- copy - for(i_=0;i_<=n;i_++) - tmp[i_]=xyp[i_][0]; - //--- function call - CSpline1D::Spline1DBuildCubic(p.m_p,tmp,n+1,-1,0.0,-1,0.0,p.m_x); - //--- copy - for(i_=0;i_<=n;i_++) - tmp[i_]=xyp[i_][1]; - //--- function call - CSpline1D::Spline1DBuildCubic(p.m_p,tmp,n+1,-1,0.0,-1,0.0,p.m_y); - } - } -//+------------------------------------------------------------------+ -//| This function builds periodic 3-dimensional parametric spline | -//| which starts at (X[0],Y[0],Z[0]), goes through all points to | -//| (X[N-1],Y[N-1],Z[N-1]) and then back to (X[0],Y[0],Z[0]). | -//| Same as PSpline2Build() function, but for 3D, so we won't | -//| duplicate its description here. | -//+------------------------------------------------------------------+ -static void CPSpline::PSpline3BuildPeriodic(CMatrixDouble &cxy,const int n, - const int st,const int pt, - CPSpline3Interpolant &p) - { -//--- create a variable - int i_=0; -//--- create array - double tmp[]; -//--- create matrix - CMatrixDouble xyp; - CMatrixDouble xy; -//--- copy matrix - xy=cxy; -//--- check - if(!CAp::Assert(st>=1 && st<=2,__FUNCTION__+": incorrect spline type!")) - return; -//--- check - if(!CAp::Assert(pt>=0 && pt<=2,__FUNCTION__+": incorrect parameterization type!")) - return; -//--- check - if(!CAp::Assert(n>=3,__FUNCTION__+": N<3!")) - return; -//--- Prepare - p.m_n=n; - p.m_periodic=true; -//--- allocation - ArrayResizeAL(tmp,n+1); - xyp.Resize(n+1,3); -//--- change values - for(i_=0;i_<=n-1;i_++) - xyp[i_].Set(0,xy[i_][0]); - for(i_=0;i_<=n-1;i_++) - xyp[i_].Set(1,xy[i_][1]); - for(i_=0;i_<=n-1;i_++) - xyp[i_].Set(2,xy[i_][2]); - for(i_=0;i_<=2;i_++) - xyp[n].Set(i_,xy[0][i_]); -//--- Build parameterization,check that all parameters are distinct - PSpline3Par(xyp,n+1,pt,p.m_p); -//--- check - if(!CAp::Assert(CApServ::AreDistinct(p.m_p,n+1),__FUNCTION__+": consequent (or first and last) points are too close!")) - return; -//--- Build splines - if(st==1) - { - //--- copy - for(i_=0;i_<=n;i_++) - tmp[i_]=xyp[i_][0]; - //--- function call - CSpline1D::Spline1DBuildCatmullRom(p.m_p,tmp,n+1,-1,0.0,p.m_x); - //--- copy - for(i_=0;i_<=n;i_++) - tmp[i_]=xyp[i_][1]; - //--- function call - CSpline1D::Spline1DBuildCatmullRom(p.m_p,tmp,n+1,-1,0.0,p.m_y); - //--- copy - for(i_=0;i_<=n;i_++) - tmp[i_]=xyp[i_][2]; - //--- function call - CSpline1D::Spline1DBuildCatmullRom(p.m_p,tmp,n+1,-1,0.0,p.m_z); - } -//--- check - if(st==2) - { - //--- copy - for(i_=0;i_<=n;i_++) - tmp[i_]=xyp[i_][0]; - //--- function call - CSpline1D::Spline1DBuildCubic(p.m_p,tmp,n+1,-1,0.0,-1,0.0,p.m_x); - //--- copy - for(i_=0;i_<=n;i_++) - tmp[i_]=xyp[i_][1]; - //--- function call - CSpline1D::Spline1DBuildCubic(p.m_p,tmp,n+1,-1,0.0,-1,0.0,p.m_y); - //--- copy - for(i_=0;i_<=n;i_++) - tmp[i_]=xyp[i_][2]; - //--- function call - CSpline1D::Spline1DBuildCubic(p.m_p,tmp,n+1,-1,0.0,-1,0.0,p.m_z); - } - } -//+------------------------------------------------------------------+ -//| This function returns vector of parameter values correspoding to | -//| points. | -//| I.e. for P created from (X[0],Y[0])...(X[N-1],Y[N-1]) and | -//| U=TValues(P) we have | -//| (X[0],Y[0]) = PSpline2Calc(P,U[0]), | -//| (X[1],Y[1]) = PSpline2Calc(P,U[1]), | -//| (X[2],Y[2]) = PSpline2Calc(P,U[2]), | -//| ... | -//| INPUT PARAMETERS: | -//| P - parametric spline interpolant | -//| OUTPUT PARAMETERS: | -//| N - array size | -//| T - array[0..N-1] | -//| NOTES: | -//| * for non-periodic splines U[0]=0, U[0]=2,__FUNCTION__+": internal error!")) - return; -//--- initialization - n=p.m_n; -//--- allocation - ArrayResizeAL(t,n); -//--- copy - for(i_=0;i_<=n-1;i_++) - t[i_]=p.m_p[i_]; - t[0]=0; -//--- check - if(!p.m_periodic) - t[n-1]=1; - } -//+------------------------------------------------------------------+ -//| This function returns vector of parameter values correspoding to | -//| points. | -//| Same as PSpline2ParameterValues(), but for 3D. | -//+------------------------------------------------------------------+ -static void CPSpline::PSpline3ParameterValues(CPSpline3Interpolant &p, - int &n,double &t[]) - { -//--- create a variable - int i_=0; -//--- initialization - n=0; -//--- check - if(!CAp::Assert(p.m_n>=2,__FUNCTION__+": internal error!")) - return; -//--- initialization - n=p.m_n; -//--- allocation - ArrayResizeAL(t,n); -//--- copy - for(i_=0;i_<=n-1;i_++) - t[i_]=p.m_p[i_]; - t[0]=0; -//--- check - if(!p.m_periodic) - t[n-1]=1; - } -//+------------------------------------------------------------------+ -//| This function calculates the value of the parametric spline for a| -//| given value of parameter T | -//| INPUT PARAMETERS: | -//| P - parametric spline interpolant | -//| T - point: | -//| * T in [0,1] corresponds to interval spanned by | -//| points | -//| * for non-periodic splines T<0 (or T>1) correspond to| -//| parts of the curve before the first (after the | -//| last) point | -//| * for periodic splines T<0 (or T>1) are projected | -//| into [0,1] by making T=T-floor(T). | -//| OUTPUT PARAMETERS: | -//| X - X-position | -//| Y - Y-position | -//+------------------------------------------------------------------+ -static void CPSpline::PSpline2Calc(CPSpline2Interpolant &p,double t, - double &x,double &y) - { -//--- initialization - x=0; - y=0; -//--- check - if(p.m_periodic) - t=t-(int)MathFloor(t); -//--- function call - x=CSpline1D::Spline1DCalc(p.m_x,t); -//--- function call - y=CSpline1D::Spline1DCalc(p.m_y,t); - } -//+------------------------------------------------------------------+ -//| This function calculates the value of the parametric spline for a| -//| given value of parameter T. | -//| INPUT PARAMETERS: | -//| P - parametric spline interpolant | -//| T - point: | -//| * T in [0,1] corresponds to interval spanned by | -//| points | -//| * for non-periodic splines T<0 (or T>1) correspond | -//| to parts of the curve before the first (after the | -//| last) point | -//| * for periodic splines T<0 (or T>1) are projected | -//| into [0,1] by making T=T-floor(T). | -//| OUTPUT PARAMETERS: | -//| X - X-position | -//| Y - Y-position | -//| Z - Z-position | -//+------------------------------------------------------------------+ -static void CPSpline::PSpline3Calc(CPSpline3Interpolant &p,double t, - double &x,double &y,double &z) - { -//--- initialization - x=0; - y=0; - z=0; -//--- check - if(p.m_periodic) - t=t-(int)MathFloor(t); -//--- function call - x=CSpline1D::Spline1DCalc(p.m_x,t); -//--- function call - y=CSpline1D::Spline1DCalc(p.m_y,t); -//--- function call - z=CSpline1D::Spline1DCalc(p.m_z,t); - } -//+------------------------------------------------------------------+ -//| This function calculates tangent vector for a given value of | -//| parameter T | -//| INPUT PARAMETERS: | -//| P - parametric spline interpolant | -//| T - point: | -//| * T in [0,1] corresponds to interval spanned by | -//| points | -//| * for non-periodic splines T<0 (or T>1) correspond to| -//| parts of the curve before the first (after the | -//| last) point | -//| * for periodic splines T<0 (or T>1) are projected | -//| into [0,1] by making T=T-floor(T). | -//| OUTPUT PARAMETERS: | -//| X - X-component of tangent vector (normalized) | -//| Y - Y-component of tangent vector (normalized) | -//| NOTE: | -//| X^2+Y^2 is either 1 (for non-zero tangent vector) or 0. | -//+------------------------------------------------------------------+ -static void CPSpline::PSpline2Tangent(CPSpline2Interpolant &p,double t, - double &x,double &y) - { -//--- create variables - double v=0; - double v0=0; - double v1=0; -//--- initialization - x=0; - y=0; -//--- check - if(p.m_periodic) - t=t-(int)MathFloor(t); -//--- function call - PSpline2Diff(p,t,v0,x,v1,y); -//--- check - if(x!=0.0 || y!=0.0) - { - //--- this code is a bit more complex than X^2+Y^2 to avoid - //--- overflow for large values of X and Y. - v=CApServ::SafePythag2(x,y); - x=x/v; - y=y/v; - } - } -//+------------------------------------------------------------------+ -//| This function calculates tangent vector for a given value of | -//| parameter T | -//| INPUT PARAMETERS: | -//| P - parametric spline interpolant | -//| T - point: | -//| * T in [0,1] corresponds to interval spanned by | -//| points | -//| * for non-periodic splines T<0 (or T>1) correspond to| -//| parts of the curve before the first (after the | -//| last) point | -//| * for periodic splines T<0 (or T>1) are projected | -//| into [0,1] by making T=T-floor(T). | -//| OUTPUT PARAMETERS: | -//| X - X-component of tangent vector (normalized) | -//| Y - Y-component of tangent vector (normalized) | -//| Z - Z-component of tangent vector (normalized) | -//| NOTE: | -//| X^2+Y^2+Z^2 is either 1 (for non-zero tangent vector) or 0. | -//+------------------------------------------------------------------+ -static void CPSpline::PSpline3Tangent(CPSpline3Interpolant &p,double t, - double &x,double &y,double &z) - { -//--- create variables - double v=0; - double v0=0; - double v1=0; - double v2=0; -//--- initialization - x=0; - y=0; - z=0; -//--- check - if(p.m_periodic) - t=t-(int)MathFloor(t); -//--- function call - PSpline3Diff(p,t,v0,x,v1,y,v2,z); -//--- check - if((x!=0.0 || y!=0.0) || z!=0.0) - { - //--- function call - v=CApServ::SafePythag3(x,y,z); - //--- change values - x=x/v; - y=y/v; - z=z/v; - } - } -//+------------------------------------------------------------------+ -//| This function calculates derivative, i.e. it returns | -//| (dX/dT,dY/dT). | -//| INPUT PARAMETERS: | -//| P - parametric spline interpolant | -//| T - point: | -//| * T in [0,1] corresponds to interval spanned by | -//| points | -//| * for non-periodic splines T<0 (or T>1) correspond to| -//| parts of the curve before the first (after the | -//| last) point | -//| * for periodic splines T<0 (or T>1) are projected | -//| into [0,1] by making T=T-floor(T). | -//| OUTPUT PARAMETERS: | -//| X - X-value | -//| DX - X-derivative | -//| Y - Y-value | -//| DY - Y-derivative | -//+------------------------------------------------------------------+ -static void CPSpline::PSpline2Diff(CPSpline2Interpolant &p,double t, - double &x,double &dx,double &y, - double &dy) - { -//--- create a variable - double d2s=0; -//--- change values - x=0; - dx=0; - y=0; - dy=0; -//--- check - if(p.m_periodic) - t=t-(int)MathFloor(t); -//--- function call - CSpline1D::Spline1DDiff(p.m_x,t,x,dx,d2s); -//--- function call - CSpline1D::Spline1DDiff(p.m_y,t,y,dy,d2s); - } -//+------------------------------------------------------------------+ -//| This function calculates derivative, i.e. it returns | -//| (dX/dT,dY/dT,dZ/dT). | -//| INPUT PARAMETERS: | -//| P - parametric spline interpolant | -//| T - point: | -//| * T in [0,1] corresponds to interval spanned by | -//| points | -//| * for non-periodic splines T<0 (or T>1) correspond to| -//| parts of the curve before the first (after the | -//| last) point | -//| * for periodic splines T<0 (or T>1) are projected | -//| into [0,1] by making T=T-floor(T). | -//| OUTPUT PARAMETERS: | -//| X - X-value | -//| DX - X-derivative | -//| Y - Y-value | -//| DY - Y-derivative | -//| Z - Z-value | -//| DZ - Z-derivative | -//+------------------------------------------------------------------+ -static void CPSpline::PSpline3Diff(CPSpline3Interpolant &p,double t, - double &x,double &dx,double &y, - double &dy,double &z,double &dz) - { -//--- create a variable - double d2s=0; -//--- initialization - x=0; - dx=0; - y=0; - dy=0; - z=0; - dz=0; -//--- check - if(p.m_periodic) - t=t-(int)MathFloor(t); -//--- function call - CSpline1D::Spline1DDiff(p.m_x,t,x,dx,d2s); -//--- function call - CSpline1D::Spline1DDiff(p.m_y,t,y,dy,d2s); -//--- function call - CSpline1D::Spline1DDiff(p.m_z,t,z,dz,d2s); - } -//+------------------------------------------------------------------+ -//| This function calculates first and second derivative with respect| -//| to T. | -//| INPUT PARAMETERS: | -//| P - parametric spline interpolant | -//| T - point: | -//| * T in [0,1] corresponds to interval spanned by | -//| points | -//| * for non-periodic splines T<0 (or T>1) correspond to| -//| parts of the curve before the first (after the | -//| last) point | -//| * for periodic splines T<0 (or T>1) are projected | -//| into [0,1] by making T=T-floor(T). | -//| OUTPUT PARAMETERS: | -//| X - X-value | -//| DX - derivative | -//| D2X - second derivative | -//| Y - Y-value | -//| DY - derivative | -//| D2Y - second derivative | -//+------------------------------------------------------------------+ -static void CPSpline::PSpline2Diff2(CPSpline2Interpolant &p,double t, - double &x,double &dx,double &d2x, - double &y,double &dy,double &d2y) - { -//--- initialization - x=0; - dx=0; - d2x=0; - y=0; - dy=0; - d2y=0; -//--- check - if(p.m_periodic) - t=t-(int)MathFloor(t); -//--- function call - CSpline1D::Spline1DDiff(p.m_x,t,x,dx,d2x); -//--- function call - CSpline1D::Spline1DDiff(p.m_y,t,y,dy,d2y); - } -//+------------------------------------------------------------------+ -//| This function calculates first and second derivative with respect| -//| to T. | -//| INPUT PARAMETERS: | -//| P - parametric spline interpolant | -//| T - point: | -//| * T in [0,1] corresponds to interval spanned by | -//| points | -//| * for non-periodic splines T<0 (or T>1) correspond to| -//| parts of the curve before the first (after the | -//| last) point | -//| * for periodic splines T<0 (or T>1) are projected | -//| into [0,1] by making T=T-floor(T). | -//| OUTPUT PARAMETERS: | -//| X - X-value | -//| DX - derivative | -//| D2X - second derivative | -//| Y - Y-value | -//| DY - derivative | -//| D2Y - second derivative | -//| Z - Z-value | -//| DZ - derivative | -//| D2Z - second derivative | -//+------------------------------------------------------------------+ -static void CPSpline::PSpline3Diff2(CPSpline3Interpolant &p,double t, - double &x,double &dx,double &d2x, - double &y,double &dy,double &d2y, - double &z,double &dz,double &d2z) - { -//--- initialization - x=0; - dx=0; - d2x=0; - y=0; - dy=0; - d2y=0; - z=0; - dz=0; - d2z=0; -//--- check - if(p.m_periodic) - t=t-(int)MathFloor(t); -//--- function call - CSpline1D::Spline1DDiff(p.m_x,t,x,dx,d2x); -//--- function call - CSpline1D::Spline1DDiff(p.m_y,t,y,dy,d2y); -//--- function call - CSpline1D::Spline1DDiff(p.m_z,t,z,dz,d2z); - } -//+------------------------------------------------------------------+ -//| This function calculates arc length, i.e. length of curve between| -//| t=a and t=b. | -//| INPUT PARAMETERS: | -//| P - parametric spline interpolant | -//| A,B - parameter values corresponding to arc ends: | -//| * B>A will result in positive length returned | -//| * B0,__FUNCTION__+": internal error!")) - return(EMPTY_VALUE); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| This function calculates arc length, i.e. length of curve between| -//| t=a and t=b. | -//| INPUT PARAMETERS: | -//| P - parametric spline interpolant | -//| A,B - parameter values corresponding to arc ends: | -//| * B>A will result in positive length returned | -//| * B0,__FUNCTION__+": internal error!")) - return(EMPTY_VALUE); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Builds non-periodic parameterization for 2-dimensional spline | -//+------------------------------------------------------------------+ -static void CPSpline::PSpline2Par(CMatrixDouble &xy,const int n,const int pt, - double &p[]) - { -//--- create variables - double v=0; - int i=0; - int i_=0; -//--- check - if(!CAp::Assert(pt>=0 && pt<=2,__FUNCTION__+": internal error!")) - return; -//--- Build parameterization: -//--- * fill by non-normalized values -//--- * normalize them so we have P[0]=0,P[N-1]=1. - ArrayResizeAL(p,n); -//--- check - if(pt==0) - { - for(i=0;i<=n-1;i++) - p[i]=i; - } -//--- check - if(pt==1) - { - p[0]=0; - //--- calculation - for(i=1;i<=n-1;i++) - p[i]=p[i-1]+CApServ::SafePythag2(xy[i][0]-xy[i-1][0],xy[i][1]-xy[i-1][1]); - } -//--- check - if(pt==2) - { - p[0]=0; - //--- calculation - for(i=1;i<=n-1;i++) - p[i]=p[i-1]+MathSqrt(CApServ::SafePythag2(xy[i][0]-xy[i-1][0],xy[i][1]-xy[i-1][1])); - } -//--- change value - v=1/p[n-1]; -//--- calculation - for(i_=0;i_<=n-1;i_++) - p[i_]=v*p[i_]; - } -//+------------------------------------------------------------------+ -//| Builds non-periodic parameterization for 3-dimensional spline | -//+------------------------------------------------------------------+ -static void CPSpline::PSpline3Par(CMatrixDouble &xy,const int n,const int pt, - double &p[]) - { -//--- create variables - double v=0; - int i=0; - int i_=0; -//--- check - if(!CAp::Assert(pt>=0 && pt<=2,__FUNCTION__+": internal error!")) - return; -//--- Build parameterization: -//--- * fill by non-normalized values -//--- * normalize them so we have P[0]=0,P[N-1]=1. - ArrayResizeAL(p,n); -//--- check - if(pt==0) - { - for(i=0;i<=n-1;i++) - p[i]=i; - } -//--- check - if(pt==1) - { - p[0]=0; - //--- calculation - for(i=1;i<=n-1;i++) - p[i]=p[i-1]+CApServ::SafePythag3(xy[i][0]-xy[i-1][0],xy[i][1]-xy[i-1][1],xy[i][2]-xy[i-1][2]); - } -//--- check - if(pt==2) - { - p[0]=0; - //--- calculation - for(i=1;i<=n-1;i++) - p[i]=p[i-1]+MathSqrt(CApServ::SafePythag3(xy[i][0]-xy[i-1][0],xy[i][1]-xy[i-1][1],xy[i][2]-xy[i-1][2])); - } -//--- change value - v=1/p[n-1]; -//--- calculation - for(i_=0;i_<=n-1;i_++) - p[i_]=v*p[i_]; - } -//+------------------------------------------------------------------+ -//| 2-dimensional spline inteprolant | -//+------------------------------------------------------------------+ -class CSpline2DInterpolant - { -public: - //--- variable - int m_k; - //--- array - double m_c[]; - //--- constructor, destructor - CSpline2DInterpolant(void); - ~CSpline2DInterpolant(void); - //--- copy - void Copy(CSpline2DInterpolant &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CSpline2DInterpolant::CSpline2DInterpolant(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSpline2DInterpolant::~CSpline2DInterpolant(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CSpline2DInterpolant::Copy(CSpline2DInterpolant &obj) - { -//--- copy variable - m_k=obj.m_k; -//--- copy array - ArrayCopy(m_c,obj.m_c); - } -//+------------------------------------------------------------------+ -//| 2-dimensional spline inteprolant | -//+------------------------------------------------------------------+ -class CSpline2DInterpolantShell - { -private: - CSpline2DInterpolant m_innerobj; -public: - //--- constructors, destructor - CSpline2DInterpolantShell(void); - CSpline2DInterpolantShell(CSpline2DInterpolant &obj); - ~CSpline2DInterpolantShell(void); - //--- method - CSpline2DInterpolant *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CSpline2DInterpolantShell::CSpline2DInterpolantShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CSpline2DInterpolantShell::CSpline2DInterpolantShell(CSpline2DInterpolant &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSpline2DInterpolantShell::~CSpline2DInterpolantShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CSpline2DInterpolant *CSpline2DInterpolantShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| 2-dimensional spline interpolation | -//+------------------------------------------------------------------+ -class CSpline2D - { -private: - //--- private method - static void BicubicCalcDerivatives(CMatrixDouble &a,double &x[],double &y[],const int m,const int n,CMatrixDouble &dx,CMatrixDouble &dy,CMatrixDouble &dxy); -public: - //--- constructor, destructor - CSpline2D(void); - ~CSpline2D(void); - //--- public methods - static void Spline2DBuildBilinear(double &cx[],double &cy[],CMatrixDouble &cf,const int m,const int n,CSpline2DInterpolant &c); - static void Spline2DBuildBicubic(double &cx[],double &cy[],CMatrixDouble &cf,const int m,const int n,CSpline2DInterpolant &c); - static double Spline2DCalc(CSpline2DInterpolant &c,const double x,const double y); - static void Spline2DDiff(CSpline2DInterpolant &c,const double x,const double y,double &f,double &fx,double &fy,double &fxy); - static void Spline2DUnpack(CSpline2DInterpolant &c,int &m,int &n,CMatrixDouble &tbl); - static void Spline2DLinTransXY(CSpline2DInterpolant &c,double ax,double bx,double ay,double by); - static void Spline2DLinTransF(CSpline2DInterpolant &c,const double a,const double b); - static void Spline2DCopy(CSpline2DInterpolant &c,CSpline2DInterpolant &cc); - static void Spline2DResampleBicubic(CMatrixDouble &a,const int oldheight,const int oldwidth,CMatrixDouble &b,const int newheight,const int newwidth); - static void Spline2DResampleBilinear(CMatrixDouble &a,const int oldheight,const int oldwidth,CMatrixDouble &b,const int newheight,const int newwidth); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CSpline2D::CSpline2D(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSpline2D::~CSpline2D(void) - { - - } -//+------------------------------------------------------------------+ -//| This subroutine builds bilinear spline coefficients table. | -//| Input parameters: | -//| X - spline abscissas, array[0..N-1] | -//| Y - spline ordinates, array[0..M-1] | -//| F - function values, array[0..M-1,0..N-1] | -//| M,N - grid size, M>=2, N>=2 | -//| Output parameters: | -//| C - spline interpolant | -//+------------------------------------------------------------------+ -static void CSpline2D::Spline2DBuildBilinear(double &cx[],double &cy[], - CMatrixDouble &cf,const int m, - const int n,CSpline2DInterpolant &c) - { -//--- create variables - int i=0; - int j=0; - int k=0; - int tblsize=0; - int shift=0; - double t=0; -//--- create arrays - double x[]; - double y[]; -//--- create matrix - CMatrixDouble dx; - CMatrixDouble dy; - CMatrixDouble dxy; - CMatrixDouble f; -//--- copy arrays - ArrayCopy(x,cx); - ArrayCopy(y,cy); -//--- copy matrix - f=cf; -//--- check - if(!CAp::Assert(n>=2 && m>=2,__FUNCTION__+": N<2 or M<2!")) - return; -//--- Sort points - for(j=0;j<=n-1;j++) - { - k=j; - for(i=j+1;i<=n-1;i++) - { - //--- check - if(x[i]=2, N>=2 | -//| Output parameters: | -//| C - spline interpolant | -//+------------------------------------------------------------------+ -static void CSpline2D::Spline2DBuildBicubic(double &cx[],double &cy[], - CMatrixDouble &cf,const int m, - const int n,CSpline2DInterpolant &c) - { -//--- create variables - int i=0; - int j=0; - int k=0; - int tblsize=0; - int shift=0; - double t=0; -//--- create arrays - double x[]; - double y[]; -//--- create matrix - CMatrixDouble dx; - CMatrixDouble dy; - CMatrixDouble dxy; - CMatrixDouble f; -//--- copy arrays - ArrayCopy(x,cx); - ArrayCopy(y,cy); -//--- copy matrix - f=cf; -//--- check - if(!CAp::Assert(n>=2 && m>=2,__FUNCTION__+": N<2 or M<2!")) - return; -//--- Sort points - for(j=0;j<=n-1;j++) - { - k=j; - for(i=j+1;i<=n-1;i++) - { - //--- check - if(x[i]=x) - r=h; - else - l=h; - } -//--- change values - t=(x-c.m_c[l])/(c.m_c[l+1]-c.m_c[l]); - dt=1.0/(c.m_c[l+1]-c.m_c[l]); - ix=l-4; -//--- Binary search in the [ y[0],...,y[m-2] ] (y[m-1] is not included) - l=4+n; - r=4+n+(m-2)+1; - while(l!=r-1) - { - h=(l+r)/2; - //--- check - if(c.m_c[h]>=y) - r=h; - else - l=h; - } -//--- change values - u=(y-c.m_c[l])/(c.m_c[l+1]-c.m_c[l]); - du=1.0/(c.m_c[l+1]-c.m_c[l]); - iy=l-(4+n); -//--- Prepare F,dF/dX,dF/dY,d2F/dXdY - f=0; - fx=0; - fy=0; - fxy=0; -//--- Bilinear interpolation - if((int)MathRound(c.m_c[1])==-1) - { - //--- calculation - shift1=4+n+m; - y1=c.m_c[shift1+n*iy+ix]; - y2=c.m_c[shift1+n*iy+(ix+1)]; - y3=c.m_c[shift1+n*(iy+1)+(ix+1)]; - y4=c.m_c[shift1+n*(iy+1)+ix]; - f=(1-t)*(1-u)*y1+t*(1-u)*y2+t*u*y3+(1-t)*u*y4; - fx=(-((1-u)*y1)+(1-u)*y2+u*y3-u*y4)*dt; - fy=(-((1-t)*y1)-t*y2+t*y3+(1-t)*y4)*du; - fxy=(y1-y2+y3-y4)*du*dt; - //--- exit the function - return; - } -//--- Bicubic interpolation - if((int)MathRound(c.m_c[1])==-3) - { - //--- Prepare info - t0=1; - t1=t; - t2=CMath::Sqr(t); - t3=t*t2; - u0=1; - u1=u; - u2=CMath::Sqr(u); - u3=u*u2; - sf=4+n+m; - sfx=4+n+m+n*m; - sfy=4+n+m+2*n*m; - sfxy=4+n+m+3*n*m; - s1=n*iy+ix; - s2=n*iy+(ix+1); - s3=n*(iy+1)+(ix+1); - s4=n*(iy+1)+ix; - //--- Calculate - v=1*c.m_c[sf+s1]; - f=f+v*t0*u0; - v=1*c.m_c[sfy+s1]/du; - f=f+v*t0*u1; - fy=fy+1*v*t0*u0*du; - v=-(3*c.m_c[sf+s1])+3*c.m_c[sf+s4]-2*c.m_c[sfy+s1]/du-1*c.m_c[sfy+s4]/du; - f=f+v*t0*u2; - fy=fy+2*v*t0*u1*du; - v=2*c.m_c[sf+s1]-2*c.m_c[sf+s4]+1*c.m_c[sfy+s1]/du+1*c.m_c[sfy+s4]/du; - f=f+v*t0*u3; - fy=fy+3*v*t0*u2*du; - v=1*c.m_c[sfx+s1]/dt; - f=f+v*t1*u0; - fx=fx+1*v*t0*u0*dt; - v=1*c.m_c[sfxy+s1]/(dt*du); - f=f+v*t1*u1; - fx=fx+1*v*t0*u1*dt; - fy=fy+1*v*t1*u0*du; - fxy=fxy+1*v*t0*u0*dt*du; - v=-(3*c.m_c[sfx+s1]/dt)+3*c.m_c[sfx+s4]/dt-2*c.m_c[sfxy+s1]/(dt*du)-1*c.m_c[sfxy+s4]/(dt*du); - f=f+v*t1*u2; - fx=fx+1*v*t0*u2*dt; - fy=fy+2*v*t1*u1*du; - fxy=fxy+2*v*t0*u1*dt*du; - v=2*c.m_c[sfx+s1]/dt-2*c.m_c[sfx+s4]/dt+1*c.m_c[sfxy+s1]/(dt*du)+1*c.m_c[sfxy+s4]/(dt*du); - f=f+v*t1*u3; - fx=fx+1*v*t0*u3*dt; - fy=fy+3*v*t1*u2*du; - fxy=fxy+3*v*t0*u2*dt*du; - v=-(3*c.m_c[sf+s1])+3*c.m_c[sf+s2]-2*c.m_c[sfx+s1]/dt-1*c.m_c[sfx+s2]/dt; - f=f+v*t2*u0; - fx=fx+2*v*t1*u0*dt; - v=-(3*c.m_c[sfy+s1]/du)+3*c.m_c[sfy+s2]/du-2*c.m_c[sfxy+s1]/(dt*du)-1*c.m_c[sfxy+s2]/(dt*du); - f=f+v*t2*u1; - fx=fx+2*v*t1*u1*dt; - fy=fy+1*v*t2*u0*du; - fxy=fxy+2*v*t1*u0*dt*du; - v=9*c.m_c[sf+s1]-9*c.m_c[sf+s2]+9*c.m_c[sf+s3]-9*c.m_c[sf+s4]+6*c.m_c[sfx+s1]/dt+3*c.m_c[sfx+s2]/dt-3*c.m_c[sfx+s3]/dt-6*c.m_c[sfx+s4]/dt+6*c.m_c[sfy+s1]/du-6*c.m_c[sfy+s2]/du-3*c.m_c[sfy+s3]/du+3*c.m_c[sfy+s4]/du+4*c.m_c[sfxy+s1]/(dt*du)+2*c.m_c[sfxy+s2]/(dt*du)+1*c.m_c[sfxy+s3]/(dt*du)+2*c.m_c[sfxy+s4]/(dt*du); - f=f+v*t2*u2; - fx=fx+2*v*t1*u2*dt; - fy=fy+2*v*t2*u1*du; - fxy=fxy+4*v*t1*u1*dt*du; - v=-(6*c.m_c[sf+s1])+6*c.m_c[sf+s2]-6*c.m_c[sf+s3]+6*c.m_c[sf+s4]-4*c.m_c[sfx+s1]/dt-2*c.m_c[sfx+s2]/dt+2*c.m_c[sfx+s3]/dt+4*c.m_c[sfx+s4]/dt-3*c.m_c[sfy+s1]/du+3*c.m_c[sfy+s2]/du+3*c.m_c[sfy+s3]/du-3*c.m_c[sfy+s4]/du-2*c.m_c[sfxy+s1]/(dt*du)-1*c.m_c[sfxy+s2]/(dt*du)-1*c.m_c[sfxy+s3]/(dt*du)-2*c.m_c[sfxy+s4]/(dt*du); - f=f+v*t2*u3; - fx=fx+2*v*t1*u3*dt; - fy=fy+3*v*t2*u2*du; - fxy=fxy+6*v*t1*u2*dt*du; - v=2*c.m_c[sf+s1]-2*c.m_c[sf+s2]+1*c.m_c[sfx+s1]/dt+1*c.m_c[sfx+s2]/dt; - f=f+v*t3*u0; - fx=fx+3*v*t2*u0*dt; - v=2*c.m_c[sfy+s1]/du-2*c.m_c[sfy+s2]/du+1*c.m_c[sfxy+s1]/(dt*du)+1*c.m_c[sfxy+s2]/(dt*du); - f=f+v*t3*u1; - fx=fx+3*v*t2*u1*dt; - fy=fy+1*v*t3*u0*du; - fxy=fxy+3*v*t2*u0*dt*du; - v=-(6*c.m_c[sf+s1])+6*c.m_c[sf+s2]-6*c.m_c[sf+s3]+6*c.m_c[sf+s4]-3*c.m_c[sfx+s1]/dt-3*c.m_c[sfx+s2]/dt+3*c.m_c[sfx+s3]/dt+3*c.m_c[sfx+s4]/dt-4*c.m_c[sfy+s1]/du+4*c.m_c[sfy+s2]/du+2*c.m_c[sfy+s3]/du-2*c.m_c[sfy+s4]/du-2*c.m_c[sfxy+s1]/(dt*du)-2*c.m_c[sfxy+s2]/(dt*du)-1*c.m_c[sfxy+s3]/(dt*du)-1*c.m_c[sfxy+s4]/(dt*du); - f=f+v*t3*u2; - fx=fx+3*v*t2*u2*dt; - fy=fy+2*v*t3*u1*du; - fxy=fxy+6*v*t2*u1*dt*du; - v=4*c.m_c[sf+s1]-4*c.m_c[sf+s2]+4*c.m_c[sf+s3]-4*c.m_c[sf+s4]+2*c.m_c[sfx+s1]/dt+2*c.m_c[sfx+s2]/dt-2*c.m_c[sfx+s3]/dt-2*c.m_c[sfx+s4]/dt+2*c.m_c[sfy+s1]/du-2*c.m_c[sfy+s2]/du-2*c.m_c[sfy+s3]/du+2*c.m_c[sfy+s4]/du+1*c.m_c[sfxy+s1]/(dt*du)+1*c.m_c[sfxy+s2]/(dt*du)+1*c.m_c[sfxy+s3]/(dt*du)+1*c.m_c[sfxy+s4]/(dt*du); - f=f+v*t3*u3; - fx=fx+3*v*t2*u3*dt; - fy=fy+3*v*t3*u2*du; - fxy=fxy+9*v*t2*u2*dt*du; - //--- exit the function - return; - } - } -//+------------------------------------------------------------------+ -//| This subroutine unpacks two-dimensional spline into the | -//| coefficients table | -//| Input parameters: | -//| C - spline interpolant. | -//| Result: | -//| M, N- grid size (x-axis and y-axis) | -//| Tbl - coefficients table, unpacked format, | -//| [0..(N-1)*(M-1)-1, 0..19]. | -//| For I = 0...M-2, J=0..N-2: | -//| K = I*(N-1)+J | -//| Tbl[K,0] = X[j] | -//| Tbl[K,1] = X[j+1] | -//| Tbl[K,2] = Y[i] | -//| Tbl[K,3] = Y[i+1] | -//| Tbl[K,4] = C00 | -//| Tbl[K,5] = C01 | -//| Tbl[K,6] = C02 | -//| Tbl[K,7] = C03 | -//| Tbl[K,8] = C10 | -//| Tbl[K,9] = C11 | -//| ... | -//| Tbl[K,19] = C33 | -//| On each grid square spline is equals to: | -//| S(x) = SUM(c[i,j]*(x^i)*(y^j), i=0..3, j=0..3) | -//| t = x-x[j] | -//| u = y-y[i] | -//+------------------------------------------------------------------+ -static void CSpline2D::Spline2DUnpack(CSpline2DInterpolant &c,int &m, - int &n,CMatrixDouble &tbl) - { -//--- create variables - int i=0; - int j=0; - int ci=0; - int cj=0; - int k=0; - int p=0; - int shift=0; - int s1=0; - int s2=0; - int s3=0; - int s4=0; - int sf=0; - int sfx=0; - int sfy=0; - int sfxy=0; - double y1=0; - double y2=0; - double y3=0; - double y4=0; - double dt=0; - double du=0; -//--- initialization - m=0; - n=0; -//--- check - if(!CAp::Assert((int)MathRound(c.m_c[1])==-3 || (int)MathRound(c.m_c[1])==-1,__FUNCTION__+": incorrect C!")) - return; -//--- initialization - n=(int)MathRound(c.m_c[2]); - m=(int)MathRound(c.m_c[3]); -//--- allocation - tbl.Resize((n-1)*(m-1),20); -//--- Fill - for(i=0;i<=m-2;i++) - { - for(j=0;j<=n-2;j++) - { - //--- calculation - p=i*(n-1)+j; - tbl[p].Set(0,c.m_c[4+j]); - tbl[p].Set(1,c.m_c[4+j+1]); - tbl[p].Set(2,c.m_c[4+n+i]); - tbl[p].Set(3,c.m_c[4+n+i+1]); - dt=1/(tbl[p][1]-tbl[p][0]); - du=1/(tbl[p][3]-tbl[p][2]); - //--- Bilinear interpolation - if((int)MathRound(c.m_c[1])==-1) - { - for(k=4;k<=19;k++) - tbl[p].Set(k,0); - //--- calculation - shift=4+n+m; - y1=c.m_c[shift+n*i+j]; - y2=c.m_c[shift+n*i+(j+1)]; - y3=c.m_c[shift+n*(i+1)+(j+1)]; - y4=c.m_c[shift+n*(i+1)+j]; - tbl[p].Set(4,y1); - tbl[p].Set(4+1*4+0,y2-y1); - tbl[p].Set(4+0*4+1,y4-y1); - tbl[p].Set(4+1*4+1,y3-y2-y4+y1); - } - //--- Bicubic interpolation - if((int)MathRound(c.m_c[1])==-3) - { - //--- change values - sf=4+n+m; - sfx=4+n+m+n*m; - sfy=4+n+m+2*n*m; - sfxy=4+n+m+3*n*m; - s1=n*i+j; - s2=n*i+(j+1); - s3=n*(i+1)+(j+1); - s4=n*(i+1)+j; - //--- change values - tbl[p].Set(4+0*4+0,1*c.m_c[sf+s1]); - tbl[p].Set(4+0*4+1,1*c.m_c[sfy+s1]/du); - tbl[p].Set(4+0*4+2,-(3*c.m_c[sf+s1])+3*c.m_c[sf+s4]-2*c.m_c[sfy+s1]/du-1*c.m_c[sfy+s4]/du); - tbl[p].Set(4+0*4+3,2*c.m_c[sf+s1]-2*c.m_c[sf+s4]+1*c.m_c[sfy+s1]/du+1*c.m_c[sfy+s4]/du); - tbl[p].Set(4+1*4+0,1*c.m_c[sfx+s1]/dt); - tbl[p].Set(4+1*4+1,1*c.m_c[sfxy+s1]/(dt*du)); - tbl[p].Set(4+1*4+2,-(3*c.m_c[sfx+s1]/dt)+3*c.m_c[sfx+s4]/dt-2*c.m_c[sfxy+s1]/(dt*du)-1*c.m_c[sfxy+s4]/(dt*du)); - tbl[p].Set(4+1*4+3,2*c.m_c[sfx+s1]/dt-2*c.m_c[sfx+s4]/dt+1*c.m_c[sfxy+s1]/(dt*du)+1*c.m_c[sfxy+s4]/(dt*du)); - tbl[p].Set(4+2*4+0,-(3*c.m_c[sf+s1])+3*c.m_c[sf+s2]-2*c.m_c[sfx+s1]/dt-1*c.m_c[sfx+s2]/dt); - tbl[p].Set(4+2*4+1,-(3*c.m_c[sfy+s1]/du)+3*c.m_c[sfy+s2]/du-2*c.m_c[sfxy+s1]/(dt*du)-1*c.m_c[sfxy+s2]/(dt*du)); - tbl[p].Set(4+2*4+2,9*c.m_c[sf+s1]-9*c.m_c[sf+s2]+9*c.m_c[sf+s3]-9*c.m_c[sf+s4]+6*c.m_c[sfx+s1]/dt+3*c.m_c[sfx+s2]/dt-3*c.m_c[sfx+s3]/dt-6*c.m_c[sfx+s4]/dt+6*c.m_c[sfy+s1]/du-6*c.m_c[sfy+s2]/du-3*c.m_c[sfy+s3]/du+3*c.m_c[sfy+s4]/du+4*c.m_c[sfxy+s1]/(dt*du)+2*c.m_c[sfxy+s2]/(dt*du)+1*c.m_c[sfxy+s3]/(dt*du)+2*c.m_c[sfxy+s4]/(dt*du)); - tbl[p].Set(4+2*4+3,-(6*c.m_c[sf+s1])+6*c.m_c[sf+s2]-6*c.m_c[sf+s3]+6*c.m_c[sf+s4]-4*c.m_c[sfx+s1]/dt-2*c.m_c[sfx+s2]/dt+2*c.m_c[sfx+s3]/dt+4*c.m_c[sfx+s4]/dt-3*c.m_c[sfy+s1]/du+3*c.m_c[sfy+s2]/du+3*c.m_c[sfy+s3]/du-3*c.m_c[sfy+s4]/du-2*c.m_c[sfxy+s1]/(dt*du)-1*c.m_c[sfxy+s2]/(dt*du)-1*c.m_c[sfxy+s3]/(dt*du)-2*c.m_c[sfxy+s4]/(dt*du)); - tbl[p].Set(4+3*4+0,2*c.m_c[sf+s1]-2*c.m_c[sf+s2]+1*c.m_c[sfx+s1]/dt+1*c.m_c[sfx+s2]/dt); - tbl[p].Set(4+3*4+1,2*c.m_c[sfy+s1]/du-2*c.m_c[sfy+s2]/du+1*c.m_c[sfxy+s1]/(dt*du)+1*c.m_c[sfxy+s2]/(dt*du)); - tbl[p].Set(4+3*4+2,-(6*c.m_c[sf+s1])+6*c.m_c[sf+s2]-6*c.m_c[sf+s3]+6*c.m_c[sf+s4]-3*c.m_c[sfx+s1]/dt-3*c.m_c[sfx+s2]/dt+3*c.m_c[sfx+s3]/dt+3*c.m_c[sfx+s4]/dt-4*c.m_c[sfy+s1]/du+4*c.m_c[sfy+s2]/du+2*c.m_c[sfy+s3]/du-2*c.m_c[sfy+s4]/du-2*c.m_c[sfxy+s1]/(dt*du)-2*c.m_c[sfxy+s2]/(dt*du)-1*c.m_c[sfxy+s3]/(dt*du)-1*c.m_c[sfxy+s4]/(dt*du)); - tbl[p].Set(4+3*4+3,4*c.m_c[sf+s1]-4*c.m_c[sf+s2]+4*c.m_c[sf+s3]-4*c.m_c[sf+s4]+2*c.m_c[sfx+s1]/dt+2*c.m_c[sfx+s2]/dt-2*c.m_c[sfx+s3]/dt-2*c.m_c[sfx+s4]/dt+2*c.m_c[sfy+s1]/du-2*c.m_c[sfy+s2]/du-2*c.m_c[sfy+s3]/du+2*c.m_c[sfy+s4]/du+1*c.m_c[sfxy+s1]/(dt*du)+1*c.m_c[sfxy+s2]/(dt*du)+1*c.m_c[sfxy+s3]/(dt*du)+1*c.m_c[sfxy+s4]/(dt*du)); - } - //--- Rescale Cij - for(ci=0;ci<=3;ci++) - { - for(cj=0;cj<=3;cj++) - tbl[p].Set(4+ci*4+cj,tbl[p][4+ci*4+cj]*MathPow(dt,ci)*MathPow(du,cj)); - } - } - } - } -//+------------------------------------------------------------------+ -//| This subroutine performs linear transformation of the spline | -//| argument. | -//| Input parameters: | -//| C - spline interpolant | -//| AX, BX - transformation coefficients: x = A*t + B | -//| AY, BY - transformation coefficients: y = A*u + B | -//| Result: | -//| C - transformed spline | -//+------------------------------------------------------------------+ -static void CSpline2D::Spline2DLinTransXY(CSpline2DInterpolant &c,double ax, - double bx,double ay,double by) - { -//--- create variables - int i=0; - int j=0; - int n=0; - int m=0; - double v=0; - int typec=0; -//--- create arrays - double x[]; - double y[]; -//--- create matrix - CMatrixDouble f; -//--- initialization - typec=(int)MathRound(c.m_c[1]); -//--- check - if(!CAp::Assert(typec==-3 || typec==-1,__FUNCTION__+": incorrect C!")) - return; -//--- initialization - n=(int)MathRound(c.m_c[2]); - m=(int)MathRound(c.m_c[3]); -//--- allocation - ArrayResizeAL(x,n); - ArrayResizeAL(y,m); - f.Resize(m,n); -//--- copy - for(j=0;j<=n-1;j++) - x[j]=c.m_c[4+j]; - for(i=0;i<=m-1;i++) - y[i]=c.m_c[4+n+i]; - for(i=0;i<=m-1;i++) - { - for(j=0;j<=n-1;j++) - f[i].Set(j,c.m_c[4+n+m+i*n+j]); - } -//--- Special case: AX=0 or AY=0 - if(ax==0.0) - { - //--- change values - for(i=0;i<=m-1;i++) - { - v=Spline2DCalc(c,bx,y[i]); - for(j=0;j<=n-1;j++) - f[i].Set(j,v); - } - //--- check - if(typec==-3) - Spline2DBuildBicubic(x,y,f,m,n,c); - //--- check - if(typec==-1) - Spline2DBuildBilinear(x,y,f,m,n,c); - //--- change values - ax=1; - bx=0; - } -//--- check - if(ay==0.0) - { - //--- change values - for(j=0;j<=n-1;j++) - { - v=Spline2DCalc(c,x[j],by); - for(i=0;i<=m-1;i++) - f[i].Set(j,v); - } - //--- check - if(typec==-3) - Spline2DBuildBicubic(x,y,f,m,n,c); - //--- check - if(typec==-1) - Spline2DBuildBilinear(x,y,f,m,n,c); - //--- change values - ay=1; - by=0; - } -//--- General case: AX<>0,AY<>0 -//--- Unpack,scale and pack again. - for(j=0;j<=n-1;j++) - x[j]=(x[j]-bx)/ax; - for(i=0;i<=m-1;i++) - y[i]=(y[i]-by)/ay; -//--- check - if(typec==-3) - Spline2DBuildBicubic(x,y,f,m,n,c); -//--- check - if(typec==-1) - Spline2DBuildBilinear(x,y,f,m,n,c); - } -//+------------------------------------------------------------------+ -//| This subroutine performs linear transformation of the spline. | -//| Input parameters: | -//| C - spline interpolant. | -//| A, B- transformation coefficients: S2(x,y) = A*S(x,y) + B | -//| Output parameters: | -//| C - transformed spline | -//+------------------------------------------------------------------+ -static void CSpline2D::Spline2DLinTransF(CSpline2DInterpolant &c,const double a, - const double b) - { -//--- create variables - int i=0; - int j=0; - int n=0; - int m=0; - int typec=0; -//--- create arrays - double x[]; - double y[]; -//--- create matrix - CMatrixDouble f; -//--- initialization - typec=(int)MathRound(c.m_c[1]); -//--- check - if(!CAp::Assert(typec==-3 || typec==-1,__FUNCTION__+": incorrect C!")) - return; -//--- initialization - n=(int)MathRound(c.m_c[2]); - m=(int)MathRound(c.m_c[3]); -//--- allocation - ArrayResizeAL(x,n); - ArrayResizeAL(y,m); - f.Resize(m,n); -//--- copy - for(j=0;j<=n-1;j++) - x[j]=c.m_c[4+j]; - for(i=0;i<=m-1;i++) - y[i]=c.m_c[4+n+i]; - for(i=0;i<=m-1;i++) - { - for(j=0;j<=n-1;j++) - f[i].Set(j,a*c.m_c[4+n+m+i*n+j]+b); - } -//--- check - if(typec==-3) - Spline2DBuildBicubic(x,y,f,m,n,c); -//--- check - if(typec==-1) - Spline2DBuildBilinear(x,y,f,m,n,c); - } -//+------------------------------------------------------------------+ -//| This subroutine makes the copy of the spline model. | -//| Input parameters: | -//| C - spline interpolant | -//| Output parameters: | -//| CC - spline copy | -//+------------------------------------------------------------------+ -static void CSpline2D::Spline2DCopy(CSpline2DInterpolant &c,CSpline2DInterpolant &cc) - { -//--- create variables - int n=0; - int i_=0; -//--- check - if(!CAp::Assert(c.m_k==1 || c.m_k==3,__FUNCTION__+": incorrect C!")) - return; -//--- change values - cc.m_k=c.m_k; - n=(int)MathRound(c.m_c[0]); -//--- allocation - ArrayResizeAL(cc.m_c,n); -//--- copy - for(i_=0;i_<=n-1;i_++) - cc.m_c[i_]=c.m_c[i_]; - } -//+------------------------------------------------------------------+ -//| Bicubic spline resampling | -//| Input parameters: | -//| A - function values at the old grid, | -//| array[0..OldHeight-1, 0..OldWidth-1] | -//| OldHeight - old grid height, OldHeight>1 | -//| OldWidth - old grid width, OldWidth>1 | -//| NewHeight - new grid height, NewHeight>1 | -//| NewWidth - new grid width, NewWidth>1 | -//| Output parameters: | -//| B - function values at the new grid, | -//| array[0..NewHeight-1, 0..NewWidth-1] | -//+------------------------------------------------------------------+ -static void CSpline2D::Spline2DResampleBicubic(CMatrixDouble &a,const int oldheight, - const int oldwidth,CMatrixDouble &b, - const int newheight,const int newwidth) - { -//--- create variables - int i=0; - int j=0; - int mw=0; - int mh=0; -//--- create arrays - double x[]; - double y[]; -//--- create matrix - CMatrixDouble buf; -//--- object of class - CSpline1DInterpolant c; -//--- check - if(!CAp::Assert(oldwidth>1 && oldheight>1,__FUNCTION__+": width/height less than 1")) - return; -//--- check - if(!CAp::Assert(newwidth>1 && newheight>1,__FUNCTION__+": width/height less than 1")) - return; -//--- Prepare - mw=MathMax(oldwidth,newwidth); - mh=MathMax(oldheight,newheight); -//--- allocation - b.Resize(newheight,newwidth); - buf.Resize(oldheight,newwidth); - ArrayResizeAL(x,MathMax(mw,mh)); - ArrayResizeAL(y,MathMax(mw,mh)); -//--- Horizontal interpolation - for(i=0;i<=oldheight-1;i++) - { - //--- Fill X,Y - for(j=0;j<=oldwidth-1;j++) - { - x[j]=(double)j/(double)(oldwidth-1); - y[j]=a[i][j]; - } - //--- Interpolate and place result into temporary matrix - CSpline1D::Spline1DBuildCubic(x,y,oldwidth,0,0.0,0,0.0,c); - for(j=0;j<=newwidth-1;j++) - buf[i].Set(j,CSpline1D::Spline1DCalc(c,(double)j/(double)(newwidth-1))); - } -//--- Vertical interpolation - for(j=0;j<=newwidth-1;j++) - { - //--- Fill X,Y - for(i=0;i<=oldheight-1;i++) - { - x[i]=(double)i/(double)(oldheight-1); - y[i]=buf[i][j]; - } - //--- Interpolate and place result into B - CSpline1D::Spline1DBuildCubic(x,y,oldheight,0,0.0,0,0.0,c); - for(i=0;i<=newheight-1;i++) - b[i].Set(j,CSpline1D::Spline1DCalc(c,(double)i/(double)(newheight-1))); - } - } -//+------------------------------------------------------------------+ -//| Bilinear spline resampling | -//| Input parameters: | -//| A - function values at the old grid, | -//| array[0..OldHeight-1, 0..OldWidth-1] | -//| OldHeight - old grid height, OldHeight>1 | -//| OldWidth - old grid width, OldWidth>1 | -//| NewHeight - new grid height, NewHeight>1 | -//| NewWidth - new grid width, NewWidth>1 | -//| Output parameters: | -//| B - function values at the new grid, | -//| array[0..NewHeight-1, 0..NewWidth-1] | -//+------------------------------------------------------------------+ -static void CSpline2D::Spline2DResampleBilinear(CMatrixDouble &a,const int oldheight, - const int oldwidth,CMatrixDouble &b, - const int newheight,const int newwidth) - { -//--- create variables - int i=0; - int j=0; - int l=0; - int c=0; - double t=0; - double u=0; -//--- allocation - b.Resize(newheight,newwidth); - for(i=0;i<=newheight-1;i++) - { - for(j=0;j<=newwidth-1;j++) - { - //--- calculation - l=i*(oldheight-1)/(newheight-1); - //--- check - if(l==oldheight-1) - l=oldheight-2; - //--- calculation - u=(double)i/(double)(newheight-1)*(oldheight-1)-l; - c=j*(oldwidth-1)/(newwidth-1); - //--- check - if(c==oldwidth-1) - c=oldwidth-2; - //--- calculation - t=(double)(j*(oldwidth-1))/(double)(newwidth-1)-c; - b[i].Set(j,(1-t)*(1-u)*a[l][c]+t*(1-u)*a[l][c+1]+t*u*a[l+1][c+1]+(1-t)*u*a[l+1][c]); - } - } - } -//+------------------------------------------------------------------+ -//| Internal subroutine. | -//| Calculation of the first derivatives and the cross-derivative. | -//+------------------------------------------------------------------+ -static void CSpline2D::BicubicCalcDerivatives(CMatrixDouble &a,double &x[], - double &y[],const int m, - const int n,CMatrixDouble &dx, - CMatrixDouble &dy,CMatrixDouble &dxy) - { -//--- create variables - int i=0; - int j=0; - double s=0; - double ds=0; - double d2s=0; -//--- create arrays - double xt[]; - double ft[]; -//--- object of class - CSpline1DInterpolant c; -//--- allocation - dx.Resize(m,n); - dy.Resize(m,n); - dxy.Resize(m,n); -//--- dF/dX - ArrayResizeAL(xt,n); - ArrayResizeAL(ft,n); - for(i=0;i<=m-1;i++) - { - for(j=0;j<=n-1;j++) - { - xt[j]=x[j]; - ft[j]=a[i][j]; - } - //--- function call - CSpline1D::Spline1DBuildCubic(xt,ft,n,0,0.0,0,0.0,c); - for(j=0;j<=n-1;j++) - { - //--- function call - CSpline1D::Spline1DDiff(c,x[j],s,ds,d2s); - dx[i].Set(j,ds); - } - } -//--- dF/dY - ArrayResizeAL(xt,m); - ArrayResizeAL(ft,m); - for(j=0;j<=n-1;j++) - { - for(i=0;i<=m-1;i++) - { - xt[i]=y[i]; - ft[i]=a[i][j]; - } - //--- function call - CSpline1D::Spline1DBuildCubic(xt,ft,m,0,0.0,0,0.0,c); - for(i=0;i<=m-1;i++) - { - //--- function call - CSpline1D::Spline1DDiff(c,y[i],s,ds,d2s); - dy[i].Set(j,ds); - } - } -//--- d2F/dXdY - ArrayResizeAL(xt,n); - ArrayResizeAL(ft,n); - for(i=0;i<=m-1;i++) - { - for(j=0;j<=n-1;j++) - { - xt[j]=x[j]; - ft[j]=dy[i][j]; - } - //--- function call - CSpline1D::Spline1DBuildCubic(xt,ft,n,0,0.0,0,0.0,c); - for(j=0;j<=n-1;j++) - { - //--- function call - CSpline1D::Spline1DDiff(c,x[j],s,ds,d2s); - dxy[i].Set(j,ds); - } - } - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Alglib/linalg.mqh b/Include/Math/Alglib/linalg.mqh deleted file mode 100644 index ee3617b..0000000 --- a/Include/Math/Alglib/linalg.mqh +++ /dev/null @@ -1,20339 +0,0 @@ -//+------------------------------------------------------------------+ -//| linalg.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 "alglibinternal.mqh" -#include "alglibmisc.mqh" -//+------------------------------------------------------------------+ -//| Work with matrix forms | -//+------------------------------------------------------------------+ -class CAblas - { -private: - //--- split lenght - static void AblasInternalSplitLength(const int n,const int nb,int &n1,int &n2); - //--- real numbers - static void RMatrixSyrk2(const int n,const int k,const double alpha,const 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 RMatrixGemmK(const int m,const int n,const int k,const double alpha,const CMatrixDouble &a,const int ia,const int ja,const int optypea,const CMatrixDouble &b,const int ib,const int jb,const int optypeb,const double beta,CMatrixDouble &c,const int ic,const int jc); - static void RMatrixRightTrsM2(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 RMatrixLeftTrsM2(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); - //--- complex numbers - static void CMatrixSyrk2(const int n,const int k,const double alpha,const 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 CMatrixGemmk(const int m,const int n,const int k,al_complex &alpha,const CMatrixComplex &a,const int ia,const int ja,const int optypea,const CMatrixComplex &b,const int ib,const int jb,const int optypeb,al_complex &beta,CMatrixComplex &c,const int ic,const int jc); - static void CMatrixRightTrsM2(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 CMatrixLeftTrsM2(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); -public: - CAblas(void); - ~CAblas(void); - //--- size - static int AblasBlockSize(void) { return(32);} - static int AblasMicroBlockSize(void) { return(8); } - static int AblasComplexBlockSize(void) { return(24);} - //--- split lenght - static void AblasSplitLength(const CMatrixDouble &a,const int n,int &n1,int &n2); - static void AblasComplexSplitLength(const CMatrixComplex &a,const int n,int &n1,int &n2); - //--- real numbers - static void RMatrixSyrk(const int n,const int k,const double alpha,const 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 RMatrixGemm(const int m,const int n,const int k,const double alpha,const CMatrixDouble &a,const int ia,const int ja,const int optypea,const CMatrixDouble &b,const int ib,const int jb,const int optypeb,const double beta,CMatrixDouble &c,const int ic,const int jc); - static void RMatrixTranspose(const int m,const int n,const CMatrixDouble &a,const int ia,const int ja,CMatrixDouble &b,const int ib,const int jb); - static void RMatrixCopy(const int m,const int n,const CMatrixDouble &a,const int ia,const int ja,CMatrixDouble &b,const int ib,const int jb); - static void RMatrixRank1(const int m,const int n,CMatrixDouble &a,const int ia,const int ja,const double &u[],const int iu,const double &v[],const int iv); - static void RMatrixMVect(const int m,const int n,const CMatrixDouble &a,const int ia,const int ja,const int opa,const double &x[],const int ix,double &y[],const int iy); - static void RMatrixRightTrsM(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 RMatrixLeftTrsM(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); - //--- complex numbers - static void CMatrixSyrk(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 CMatrixGemm(const int m,const int n,const int k,al_complex &alpha,CMatrixComplex &a,const int ia,const int ja,const int optypea,CMatrixComplex &b,const int ib,const int jb,const int optypeb,al_complex &beta,CMatrixComplex &c,const int ic,const int jc); - static void CMatrixTranspose(const int m,const int n,const CMatrixComplex &a,const int ia,const int ja,CMatrixComplex &b,const int ib,const int jb); - static void CMatrixCopy(const int m,const int n,const CMatrixComplex &a,const int ia,const int ja,CMatrixComplex &b,const int ib,const int jb); - static void CMatrixRank1(const int m,const int n,CMatrixComplex &a,const int ia,const int ja,const al_complex &u[],const int iu,const al_complex &v[],const int iv); - static void CMatrixMVect(const int m,const int n,const CMatrixComplex &a,const int ia,const int ja,const int opa,const al_complex &x[],const int ix,al_complex &y[],const int iy); - static void CMatrixRightTrsM(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 CMatrixLeftTrsM(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); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CAblas::CAblas(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CAblas::~CAblas(void) - { - - } -//+------------------------------------------------------------------+ -//| Same as CMatrixSYRK, but for real matrices | -//| OpType may be only 0 or 1. | -//+------------------------------------------------------------------+ -static void CAblas::RMatrixSyrk(const int n,const int k,const double alpha, - const 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 s1=0; - int s2=0; - int bs=0; -//--- calculation size - bs=AblasBlockSize(); -//--- check - if(n<=bs && k<=bs) - { - RMatrixSyrk2(n,k,alpha,a,ia,ja,optypea,beta,c,ic,jc,isUpper); - return; - } -//--- check - if(k>=n) - { - //--- Split K - AblasSplitLength(a,k,s1,s2); - //--- check - if(optypea==0) - { - RMatrixSyrk(n,s1,alpha,a,ia,ja,optypea,beta,c,ic,jc,isUpper); - RMatrixSyrk(n,s2,alpha,a,ia,ja+s1,optypea,1.0,c,ic,jc,isUpper); - } - else - { - RMatrixSyrk(n,s1,alpha,a,ia,ja,optypea,beta,c,ic,jc,isUpper); - RMatrixSyrk(n,s2,alpha,a,ia+s1,ja,optypea,1.0,c,ic,jc,isUpper); - } - } - else - { - //--- Split N - AblasSplitLength(a,n,s1,s2); - //--- check - if(optypea==0 && isUpper) - { - RMatrixSyrk(s1,k,alpha,a,ia,ja,optypea,beta,c,ic,jc,isUpper); - RMatrixGemm(s1,s2,k,alpha,a,ia,ja,0,a,ia+s1,ja,1,beta,c,ic,jc+s1); - RMatrixSyrk(s2,k,alpha,a,ia+s1,ja,optypea,beta,c,ic+s1,jc+s1,isUpper); - //--- exit the function - return; - } - //--- check - if(optypea==0 && !isUpper) - { - RMatrixSyrk(s1,k,alpha,a,ia,ja,optypea,beta,c,ic,jc,isUpper); - RMatrixGemm(s2,s1,k,alpha,a,ia+s1,ja,0,a,ia,ja,1,beta,c,ic+s1,jc); - RMatrixSyrk(s2,k,alpha,a,ia+s1,ja,optypea,beta,c,ic+s1,jc+s1,isUpper); - //--- exit the function - return; - } - //--- check - if(optypea!=0 && isUpper) - { - RMatrixSyrk(s1,k,alpha,a,ia,ja,optypea,beta,c,ic,jc,isUpper); - RMatrixGemm(s1,s2,k,alpha,a,ia,ja,1,a,ia,ja+s1,0,beta,c,ic,jc+s1); - RMatrixSyrk(s2,k,alpha,a,ia,ja+s1,optypea,beta,c,ic+s1,jc+s1,isUpper); - //--- exit the function - return; - } - //--- check - if(optypea!=0 && !isUpper) - { - RMatrixSyrk(s1,k,alpha,a,ia,ja,optypea,beta,c,ic,jc,isUpper); - RMatrixGemm(s2,s1,k,alpha,a,ia,ja+s1,1,a,ia,ja,0,beta,c,ic+s1,jc); - RMatrixSyrk(s2,k,alpha,a,ia,ja+s1,optypea,beta,c,ic+s1,jc+s1,isUpper); - //--- exit the function - return; - } - } -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Splits matrix length in two parts, left part should match ABLAS | -//| block size | -//| INPUT PARAMETERS | -//| A - real matrix, is passed to ensure that we didn't split| -//| complex matrix using real splitting subroutine. | -//| matrix itself is not changed. | -//| N - length, N>0 | -//| OUTPUT PARAMETERS | -//| N1 - length | -//| N2 - length | -//| N1+N2=N, N1>=N2, N2 may be zero | -//+------------------------------------------------------------------+ -static void CAblas::AblasSplitLength(const CMatrixDouble &a,const int n, - int &n1,int &n2) - { -//--- initialization - n1=0; - n2=0; -//--- check - if(n>AblasBlockSize()) - AblasInternalSplitLength(n,AblasBlockSize(),n1,n2); - else - AblasInternalSplitLength(n,AblasMicroBlockSize(),n1,n2); -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Complex ABLASSplitLength | -//+------------------------------------------------------------------+ -static void CAblas::AblasComplexSplitLength(const CMatrixComplex &a,const int n, - int &n1,int &n2) - { -//--- check - if(n>AblasComplexBlockSize()) - AblasInternalSplitLength(n,AblasComplexBlockSize(),n1,n2); - else - AblasInternalSplitLength(n,AblasMicroBlockSize(),n1,n2); - } -//+------------------------------------------------------------------+ -//| Same as CMatrixGEMM, but for real numbers. | -//| OpType may be only 0 or 1. | -//+------------------------------------------------------------------+ -static void CAblas::RMatrixGemm(const int m,const int n,const int k,const double alpha, - const CMatrixDouble &a,const int ia,const int ja, - const int optypea,const 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 s1=0; - int s2=0; - int bs; -//--- calculation size - bs=AblasBlockSize(); -//--- check - if(m<=bs && n<=bs && k<=bs) - { - RMatrixGemmK(m,n,k,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc); - return; - } -//--- check - if(m>=n && m>=k) - { - //--- A*B = (A1 A2)^T*B - AblasSplitLength(a,m,s1,s2); - //--- check - if(optypea==0) - { - RMatrixGemm(s1,n,k,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc); - RMatrixGemm(s2,n,k,alpha,a,ia+s1,ja,optypea,b,ib,jb,optypeb,beta,c,ic+s1,jc); - } - else - { - RMatrixGemm(s1,n,k,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc); - RMatrixGemm(s2,n,k,alpha,a,ia,ja+s1,optypea,b,ib,jb,optypeb,beta,c,ic+s1,jc); - } - return; - } -//--- check - if(n>=m && n>=k) - { - //--- A*B = A*(B1 B2) - AblasSplitLength(a,n,s1,s2); - //--- check - if(optypeb==0) - { - RMatrixGemm(m,s1,k,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc); - RMatrixGemm(m,s2,k,alpha,a,ia,ja,optypea,b,ib,jb+s1,optypeb,beta,c,ic,jc+s1); - } - else - { - RMatrixGemm(m,s1,k,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc); - RMatrixGemm(m,s2,k,alpha,a,ia,ja,optypea,b,ib+s1,jb,optypeb,beta,c,ic,jc+s1); - } - return; - } -//--- check - if(k>=m && k>=n) - { - //--- A*B = (A1 A2)*(B1 B2)^T - AblasSplitLength(a,k,s1,s2); - //--- check - if(optypea==0 && optypeb==0) - { - RMatrixGemm(m,n,s1,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc); - RMatrixGemm(m,n,s2,alpha,a,ia,ja+s1,optypea,b,ib+s1,jb,optypeb,1.0,c,ic,jc); - } - //--- check - if(optypea==0 && optypeb!=0) - { - RMatrixGemm(m,n,s1,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc); - RMatrixGemm(m,n,s2,alpha,a,ia,ja+s1,optypea,b,ib,jb+s1,optypeb,1.0,c,ic,jc); - } - //--- check - if(optypea!=0 && optypeb==0) - { - RMatrixGemm(m,n,s1,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc); - RMatrixGemm(m,n,s2,alpha,a,ia+s1,ja,optypea,b,ib+s1,jb,optypeb,1.0,c,ic,jc); - } - //--- check - if(optypea!=0 && optypeb!=0) - { - RMatrixGemm(m,n,s1,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc); - RMatrixGemm(m,n,s2,alpha,a,ia+s1,ja,optypea,b,ib,jb+s1,optypeb,1.0,c,ic,jc); - } - } -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Level 2 subrotuine | -//+------------------------------------------------------------------+ -static void CAblas::RMatrixSyrk2(const int n,const int k,const double alpha, - const 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) - { -//--- check - if((alpha==0.0 || k==0.0) && beta==1.0) - return; -//--- create variables - int i=0; - int j=0; - int j1=0; - int j2=0; - double v=0; - int i_=0; - int i1_=0; -//--- check - if(optypea==0) - { - //--- C=alpha*A*A^H+beta*C - for(i=0;i0) - { - v=0.0; - for(i_=ja;i_n) - { - //--- split - AblasComplexSplitLength(a,m,s1,s2); - //--- function call - CMatrixTranspose(s1,n,a,ia,ja,b,ib,jb); - CMatrixTranspose(s2,n,a,ia+s1,ja,b,ib,jb+s1); - } - else - { - //--- split - AblasComplexSplitLength(a,n,s1,s2); - //--- function call - CMatrixTranspose(m,s1,a,ia,ja,b,ib,jb); - CMatrixTranspose(m,s2,a,ia,ja+s1,b,ib+s1,jb); - } - } - } -//+------------------------------------------------------------------+ -//| Cache-oblivous real "copy-and-transpose" | -//| Input parameters: | -//| M - number of rows | -//| N - number of columns | -//| A - source matrix, MxN submatrix is copied and transposed| -//| IA - submatrix offset (row index) | -//| JA - submatrix offset (column index) | -//| A - destination matrix | -//| IB - submatrix offset (row index) | -//| JB - submatrix offset (column index) | -//+------------------------------------------------------------------+ -static void CAblas::RMatrixTranspose(const int m,const int n,const CMatrixDouble &a, - const int ia,const int ja,CMatrixDouble &b, - const int ib,const int jb) - { -//--- create variables - int i=0; - int s1=0; - int s2=0; - int i_=0; - int i1_=0; -//--- check - if(m<=2*AblasBlockSize() && n<=2*AblasBlockSize()) - { - //--- base case - for(i=0;in) - { - //--- split - AblasSplitLength(a,m,s1,s2); - //--- function call - RMatrixTranspose(s1,n,a,ia,ja,b,ib,jb); - RMatrixTranspose(s2,n,a,ia+s1,ja,b,ib,jb+s1); - } - else - { - //--- split - AblasSplitLength(a,n,s1,s2); - //--- function call - RMatrixTranspose(m,s1,a,ia,ja,b,ib,jb); - RMatrixTranspose(m,s2,a,ia,ja+s1,b,ib+s1,jb); - } - } - } -//+------------------------------------------------------------------+ -//| Copy | -//| Input parameters: | -//| M - number of rows | -//| N - number of columns | -//| A - source matrix, MxN submatrix is copied and transposed| -//| IA - submatrix offset (row index) | -//| JA - submatrix offset (column index) | -//| B - destination matrix | -//| IB - submatrix offset (row index) | -//| JB - submatrix offset (column index) | -//+------------------------------------------------------------------+ -static void CAblas::CMatrixCopy(const int m,const int n,const CMatrixComplex &a, - const int ia,const int ja,CMatrixComplex &b, - const int ib,const int jb) - { -//--- create variables - int i=0; - int i_=0; - int i1_=0; -//--- copy - for(i=0;i=0 | -//| N - number of columns of op(A) | -//| N>=0 | -//| A - target matrix | -//| IA - submatrix offset (row index) | -//| JA - submatrix offset (column index) | -//| OpA - operation type: | -//| * OpA=0 => op(A) = A | -//| * OpA=1 => op(A) = A^T | -//| * OpA=2 => op(A) = A^H | -//| X - input vector | -//| IX - subvector offset | -//| IY - subvector offset | -//| OUTPUT PARAMETERS: | -//| Y - vector which stores result | -//| if M=0, then subroutine does nothing. | -//| if N=0, Y is filled by zeros. | -//+------------------------------------------------------------------+ -static void CAblas::CMatrixMVect(const int m,const int n,const CMatrixComplex &a, - const int ia,const int ja,const int opa, - const al_complex &x[],const int ix,al_complex &y[], - const int iy) - { -//--- create variables - int i=0; - al_complex v=0; - int i_=0; - int i1_=0; -//--- check - if(m==0) - return; -//--- check - if(n==0) - { - for(i=0;i op(A) = A | -//| * OpA=1 => op(A) = A^T | -//| X - input vector | -//| IX - subvector offset | -//| IY - subvector offset | -//| OUTPUT PARAMETERS: | -//| Y - vector which stores result | -//| if M=0, then subroutine does nothing. | -//| if N=0, Y is filled by zeros. | -//+------------------------------------------------------------------+ -static void CAblas::RMatrixMVect(const int m,const int n,const CMatrixDouble &a, - const int ia,const int ja,const int opa, - const double &x[],const int ix,double &y[], - const int iy) - { -//--- create variables - int i=0; - double v=0; - int i_=0; - int i1_=0; -//--- check - if(m==0) - return; -//--- check - if(n==0) - { - for(i=0;i=0 | -//| M - matrix size, N>=0 | -//| A - matrix, actial matrix is stored in | -//| A[I1:I1+N-1,J1:J1+N-1] | -//| I1 - submatrix offset | -//| J1 - submatrix offset | -//| IsUpper - whether matrix is upper triangular | -//| IsUnit - whether matrix is unitriangular | -//| OpType - transformation type: | -//| * 0 - no transformation | -//| * 1 - transposition | -//| * 2 - conjugate transposition | -//| C - matrix, actial matrix is stored in | -//| C[I2:I2+M-1,J2:J2+N-1] | -//| I2 - submatrix offset | -//| J2 - submatrix offset | -//+------------------------------------------------------------------+ -static void CAblas::CMatrixRightTrsM(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 - al_complex Alpha(-1,0); - al_complex Beta(1,0); - int s1=0; - int s2=0; - int bs=AblasComplexBlockSize(); -//--- check - if(m<=bs && n<=bs) - { - //--- basic algorithm - CMatrixRightTrsM2(m,n,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - //--- exit the function - return; - } -//--- check - if(m>=n) - { - //--- Split X: X*A = (X1 X2)^T*A - AblasComplexSplitLength(a,m,s1,s2); - CMatrixRightTrsM(s1,n,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - CMatrixRightTrsM(s2,n,a,i1,j1,isUpper,isUnit,optype,x,i2+s1,j2); - } - else - { - //--- Split A: - //--- (A1 A12) - //--- X*op(A) = X*op( ) - //--- ( A2) - //--- - //--- Different variants depending on - //--- IsUpper/OpType combinations - AblasComplexSplitLength(a,n,s1,s2); - //--- check - if(isUpper && optype==0) - { - //--- (A1 A12)-1 - //--- X*A^-1 = (X1 X2)*( ) - //--- ( A2) - CMatrixRightTrsM(m,s1,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - CMatrixGemm(m,s2,s1,Alpha,x,i2,j2,0,a,i1,j1+s1,0,Beta,x,i2,j2+s1); - CMatrixRightTrsM(m,s2,a,i1+s1,j1+s1,isUpper,isUnit,optype,x,i2,j2+s1); - //--- exit the function - return; - } - //--- check - if(isUpper && optype!=0) - { - //--- (A1' )-1 - //--- X*A^-1 = (X1 X2)*( ) - //--- (A12' A2') - CMatrixRightTrsM(m,s2,a,i1+s1,j1+s1,isUpper,isUnit,optype,x,i2,j2+s1); - CMatrixGemm(m,s1,s2,Alpha,x,i2,j2+s1,0,a,i1,j1+s1,optype,Beta,x,i2,j2); - CMatrixRightTrsM(m,s1,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - //--- exit the function - return; - } - //--- check - if(!isUpper && optype==0) - { - //--- (A1 )-1 - //--- X*A^-1 = (X1 X2)*( ) - //--- (A21 A2) - CMatrixRightTrsM(m,s2,a,i1+s1,j1+s1,isUpper,isUnit,optype,x,i2,j2+s1); - CMatrixGemm(m,s1,s2,Alpha,x,i2,j2+s1,0,a,i1+s1,j1,0,Beta,x,i2,j2); - CMatrixRightTrsM(m,s1,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - //--- exit the function - return; - } - //--- check - if(!isUpper && optype!=0) - { - //--- (A1' A21')-1 - //--- X*A^-1 = (X1 X2)*( ) - //--- ( A2') - CMatrixRightTrsM(m,s1,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - CMatrixGemm(m,s2,s1,Alpha,x,i2,j2,0,a,i1+s1,j1,optype,Beta,x,i2,j2+s1); - CMatrixRightTrsM(m,s2,a,i1+s1,j1+s1,isUpper,isUnit,optype,x,i2,j2+s1); - } - } -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This subroutine calculates op(A^-1)*X where: | -//| * X is MxN general matrix | -//| * A is MxM upper/lower triangular/unitriangular matrix | -//| * "op" may be identity transformation, transposition, conjugate | -//| transposition | -//| Multiplication result replaces X. | -//| Cache-oblivious algorithm is used. | -//| INPUT PARAMETERS | -//| N - matrix size, N>=0 | -//| M - matrix size, N>=0 | -//| A - matrix, actial matrix is stored in | -//| A[I1:I1+M-1,J1:J1+M-1] | -//| I1 - submatrix offset | -//| J1 - submatrix offset | -//| IsUpper - whether matrix is upper triangular | -//| IsUnit - whether matrix is unitriangular | -//| OpType - transformation type: | -//| * 0 - no transformation | -//| * 1 - transposition | -//| * 2 - conjugate transposition | -//| C - matrix, actial matrix is stored in | -//| C[I2:I2+M-1,J2:J2+N-1] | -//| I2 - submatrix offset | -//| J2 - submatrix offset | -//+------------------------------------------------------------------+ -static void CAblas::CMatrixLeftTrsM(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 - al_complex Alpha(-1,0); - al_complex Beta(1,0); - int s1=0; - int s2=0; - int bs=AblasComplexBlockSize(); -//--- check - if(m<=bs && n<=bs) - { - //--- basic algorithm - CMatrixLeftTrsM2(m,n,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - //--- exit the function - return; - } -//--- check - if(n>=m) - { - //--- Split X: op(A)^-1*X = op(A)^-1*(X1 X2) - AblasComplexSplitLength(x,n,s1,s2); - CMatrixLeftTrsM(m,s1,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - CMatrixLeftTrsM(m,s2,a,i1,j1,isUpper,isUnit,optype,x,i2,j2+s1); - } - else - { - //--- Split A - AblasComplexSplitLength(a,m,s1,s2); - //--- check - if(isUpper && optype==0) - { - //--- (A1 A12)-1 ( X1 ) - //--- A^-1*X* = ( ) *( ) - //--- ( A2) ( X2 ) - CMatrixLeftTrsM(s2,n,a,i1+s1,j1+s1,isUpper,isUnit,optype,x,i2+s1,j2); - CMatrixGemm(s1,n,s2,Alpha,a,i1,j1+s1,0,x,i2+s1,j2,0,Beta,x,i2,j2); - CMatrixLeftTrsM(s1,n,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - //--- exit the function - return; - } - //--- check - if(isUpper && optype!=0) - { - //--- (A1' )-1 ( X1 ) - //--- A^-1*X = ( ) *( ) - //--- (A12' A2') ( X2 ) - CMatrixLeftTrsM(s1,n,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - CMatrixGemm(s2,n,s1,Alpha,a,i1,j1+s1,optype,x,i2,j2,0,Beta,x,i2+s1,j2); - CMatrixLeftTrsM(s2,n,a,i1+s1,j1+s1,isUpper,isUnit,optype,x,i2+s1,j2); - //--- exit the function - return; - } - //--- check - if(!isUpper && optype==0) - { - //--- (A1 )-1 ( X1 ) - //--- A^-1*X = ( ) *( ) - //--- (A21 A2) ( X2 ) - CMatrixLeftTrsM(s1,n,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - CMatrixGemm(s2,n,s1,Alpha,a,i1+s1,j1,0,x,i2,j2,0,Beta,x,i2+s1,j2); - CMatrixLeftTrsM(s2,n,a,i1+s1,j1+s1,isUpper,isUnit,optype,x,i2+s1,j2); - //--- exit the function - return; - } - //--- check - if(!isUpper && optype!=0) - { - //--- (A1' A21')-1 ( X1 ) - //--- A^-1*X = ( ) *( ) - //--- ( A2') ( X2 ) - CMatrixLeftTrsM(s2,n,a,i1+s1,j1+s1,isUpper,isUnit,optype,x,i2+s1,j2); - CMatrixGemm(s1,n,s2,Alpha,a,i1+s1,j1,optype,x,i2+s1,j2,0,Beta,x,i2,j2); - CMatrixLeftTrsM(s1,n,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - } - } -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Same as CMatrixRightTRSM, but for real matrices | -//| OpType may be only 0 or 1. | -//+------------------------------------------------------------------+ -static void CAblas::RMatrixRightTrsM(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 s1=0; - int s2=0; - int bs=AblasBlockSize(); -//--- check - if(m<=bs && n<=bs) - { - //--- basic algorithm - RMatrixRightTrsM2(m,n,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - //--- exit the function - return; - } -//--- check - if(m>=n) - { - //--- Split X: X*A = (X1 X2)^T*A - AblasSplitLength(a,m,s1,s2); - RMatrixRightTrsM(s1,n,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - RMatrixRightTrsM(s2,n,a,i1,j1,isUpper,isUnit,optype,x,i2+s1,j2); - } - else - { - //--- Split A: - //--- (A1 A12) - //--- X*op(A) = X*op( ) - //--- ( A2) - //--- Different variants depending on - //--- IsUpper/OpType combinations - AblasSplitLength(a,n,s1,s2); - //--- check - if(isUpper && optype==0) - { - //--- (A1 A12)-1 - //--- X*A^-1 = (X1 X2)*( ) - //--- ( A2) - RMatrixRightTrsM(m,s1,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - RMatrixGemm(m,s2,s1,-1.0,x,i2,j2,0,a,i1,j1+s1,0,1.0,x,i2,j2+s1); - RMatrixRightTrsM(m,s2,a,i1+s1,j1+s1,isUpper,isUnit,optype,x,i2,j2+s1); - //--- exit the function - return; - } - //--- check - if(isUpper && optype!=0) - { - //--- (A1' )-1 - //--- X*A^-1 = (X1 X2)*( ) - //--- (A12' A2') - RMatrixRightTrsM(m,s2,a,i1+s1,j1+s1,isUpper,isUnit,optype,x,i2,j2+s1); - RMatrixGemm(m,s1,s2,-1.0,x,i2,j2+s1,0,a,i1,j1+s1,optype,1.0,x,i2,j2); - RMatrixRightTrsM(m,s1,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - //--- exit the function - return; - } - //--- check - if(!isUpper && optype==0) - { - //--- (A1 )-1 - //--- X*A^-1 = (X1 X2)*( ) - //--- (A21 A2) - RMatrixRightTrsM(m,s2,a,i1+s1,j1+s1,isUpper,isUnit,optype,x,i2,j2+s1); - RMatrixGemm(m,s1,s2,-1.0,x,i2,j2+s1,0,a,i1+s1,j1,0,1.0,x,i2,j2); - RMatrixRightTrsM(m,s1,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - //--- exit the function - return; - } - //--- check - if(!isUpper && optype!=0) - { - //--- (A1' A21')-1 - //--- X*A^-1 = (X1 X2)*( ) - //--- ( A2') - RMatrixRightTrsM(m,s1,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - RMatrixGemm(m,s2,s1,-1.0,x,i2,j2,0,a,i1+s1,j1,optype,1.0,x,i2,j2+s1); - RMatrixRightTrsM(m,s2,a,i1+s1,j1+s1,isUpper,isUnit,optype,x,i2,j2+s1); - } - } -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Same as CMatrixLeftTRSM, but for real matrices | -//| OpType may be only 0 or 1. | -//+------------------------------------------------------------------+ -static void CAblas::RMatrixLeftTrsM(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 s1=0; - int s2=0; - int bs=AblasBlockSize(); -//--- check - if(m<=bs && n<=bs) - { - //--- basic algorithm - RMatrixLeftTrsM2(m,n,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - //--- exit the function - return; - } -//--- check - if(n>=m) - { - //--- Split X: op(A)^-1*X = op(A)^-1*(X1 X2) - AblasSplitLength(x,n,s1,s2); - RMatrixLeftTrsM(m,s1,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - RMatrixLeftTrsM(m,s2,a,i1,j1,isUpper,isUnit,optype,x,i2,j2+s1); - } - else - { - //--- Split A - AblasSplitLength(a,m,s1,s2); - //--- check - if(isUpper && optype==0) - { - //--- (A1 A12)-1 ( X1 ) - //--- A^-1*X* = ( ) *( ) - //--- ( A2) ( X2 ) - RMatrixLeftTrsM(s2,n,a,i1+s1,j1+s1,isUpper,isUnit,optype,x,i2+s1,j2); - RMatrixGemm(s1,n,s2,-1.0,a,i1,j1+s1,0,x,i2+s1,j2,0,1.0,x,i2,j2); - RMatrixLeftTrsM(s1,n,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - //--- exit the function - return; - } - //--- check - if(isUpper && optype!=0) - { - //--- (A1' )-1 ( X1 ) - //--- A^-1*X = ( ) *( ) - //--- (A12' A2') ( X2 ) - RMatrixLeftTrsM(s1,n,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - RMatrixGemm(s2,n,s1,-1.0,a,i1,j1+s1,optype,x,i2,j2,0,1.0,x,i2+s1,j2); - RMatrixLeftTrsM(s2,n,a,i1+s1,j1+s1,isUpper,isUnit,optype,x,i2+s1,j2); - //--- exit the function - return; - } - //--- check - if(!isUpper && optype==0) - { - //--- (A1 )-1 ( X1 ) - //--- A^-1*X = ( ) *( ) - //--- (A21 A2) ( X2 ) - RMatrixLeftTrsM(s1,n,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - RMatrixGemm(s2,n,s1,-1.0,a,i1+s1,j1,0,x,i2,j2,0,1.0,x,i2+s1,j2); - RMatrixLeftTrsM(s2,n,a,i1+s1,j1+s1,isUpper,isUnit,optype,x,i2+s1,j2); - //--- exit the function - return; - } - //--- check - if(!isUpper && optype!=0) - { - //--- (A1' A21')-1 ( X1 ) - //--- A^-1*X = ( ) *( ) - //--- ( A2') ( X2 ) - RMatrixLeftTrsM(s2,n,a,i1+s1,j1+s1,isUpper,isUnit,optype,x,i2+s1,j2); - RMatrixGemm(s1,n,s2,-1.0,a,i1+s1,j1,optype,x,i2+s1,j2,0,1.0,x,i2,j2); - RMatrixLeftTrsM(s1,n,a,i1,j1,isUpper,isUnit,optype,x,i2,j2); - } - } -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This subroutine calculates C=alpha*A*A^H+beta*C or | -//| C=alpha*A^H*A+beta*C where: | -//| * C is NxN Hermitian matrix given by its upper/lower triangle | -//| * A is NxK matrix when A*A^H is calculated, KxN matrix otherwise | -//| Additional info: | -//| * cache-oblivious algorithm is used. | -//| * multiplication result replaces C. If Beta=0, C elements are not| -//| used in calculations (not multiplied by zero - just not | -//| referenced) | -//| * if Alpha=0, A is not used (not multiplied by zero - just not | -//| referenced) | -//| * if both Beta and Alpha are zero, C is filled by zeros. | -//| INPUT PARAMETERS | -//| N - matrix size, N>=0 | -//| K - matrix size, K>=0 | -//| Alpha - coefficient | -//| A - matrix | -//| IA - submatrix offset | -//| JA - submatrix offset | -//| OpTypeA - multiplication type: | -//| * 0 - A*A^H is calculated | -//| * 2 - A^H*A is calculated | -//| Beta - coefficient | -//| C - matrix | -//| IC - submatrix offset | -//| JC - submatrix offset | -//| IsUpper - whether C is upper triangular or lower triangular| -//+------------------------------------------------------------------+ -static void CAblas::CMatrixSyrk(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 - al_complex Alpha(alpha,0); - al_complex Beta(beta,0); - int s1=0; - int s2=0; - int bs=AblasComplexBlockSize(); -//--- check - if(n<=bs && k<=bs) - { - //--- basic algorithm - CMatrixSyrk2(n,k,alpha,a,ia,ja,optypea,beta,c,ic,jc,isUpper); - //--- exit the function - return; - } -//--- check - if(k>=n) - { - //--- Split K - AblasComplexSplitLength(a,k,s1,s2); - //--- check - if(optypea==0) - { - CMatrixSyrk(n,s1,alpha,a,ia,ja,optypea,beta,c,ic,jc,isUpper); - CMatrixSyrk(n,s2,alpha,a,ia,ja+s1,optypea,1.0,c,ic,jc,isUpper); - } - else - { - CMatrixSyrk(n,s1,alpha,a,ia,ja,optypea,beta,c,ic,jc,isUpper); - CMatrixSyrk(n,s2,alpha,a,ia+s1,ja,optypea,1.0,c,ic,jc,isUpper); - } - } - else - { - //--- Split N - AblasComplexSplitLength(a,n,s1,s2); - //--- check - if(optypea==0 && isUpper) - { - CMatrixSyrk(s1,k,alpha,a,ia,ja,optypea,beta,c,ic,jc,isUpper); - CMatrixGemm(s1,s2,k,Alpha,a,ia,ja,0,a,ia+s1,ja,2,Beta,c,ic,jc+s1); - CMatrixSyrk(s2,k,alpha,a,ia+s1,ja,optypea,beta,c,ic+s1,jc+s1,isUpper); - //--- exit the function - return; - } - //--- check - if(optypea==0 && !isUpper) - { - CMatrixSyrk(s1,k,alpha,a,ia,ja,optypea,beta,c,ic,jc,isUpper); - CMatrixGemm(s2,s1,k,Alpha,a,ia+s1,ja,0,a,ia,ja,2,Beta,c,ic+s1,jc); - CMatrixSyrk(s2,k,alpha,a,ia+s1,ja,optypea,beta,c,ic+s1,jc+s1,isUpper); - //--- exit the function - return; - } - //--- check - if(optypea!=0 && isUpper) - { - CMatrixSyrk(s1,k,alpha,a,ia,ja,optypea,beta,c,ic,jc,isUpper); - CMatrixGemm(s1,s2,k,Alpha,a,ia,ja,2,a,ia,ja+s1,0,Beta,c,ic,jc+s1); - CMatrixSyrk(s2,k,alpha,a,ia,ja+s1,optypea,beta,c,ic+s1,jc+s1,isUpper); - //--- exit the function - return; - } - //--- check - if(optypea!=0 && !isUpper) - { - CMatrixSyrk(s1,k,alpha,a,ia,ja,optypea,beta,c,ic,jc,isUpper); - CMatrixGemm(s2,s1,k,Alpha,a,ia,ja+s1,2,a,ia,ja,0,Beta,c,ic+s1,jc); - CMatrixSyrk(s2,k,alpha,a,ia,ja+s1,optypea,beta,c,ic+s1,jc+s1,isUpper); - } - } -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where:| -//| * C is MxN general matrix | -//| * op1(A) is MxK matrix | -//| * op2(B) is KxN matrix | -//| * "op" may be identity transformation, transposition, conjugate | -//| transposition | -//| Additional info: | -//| * cache-oblivious algorithm is used. | -//| * multiplication result replaces C. If Beta=0, C elements are not| -//| used in calculations (not multiplied by zero - just not | -//| referenced) | -//| * if Alpha=0, A is not used (not multiplied by zero - just not | -//| referenced) | -//| * if both Beta and Alpha are zero, C is filled by zeros. | -//| INPUT PARAMETERS | -//| N - matrix size, N>0 | -//| M - matrix size, N>0 | -//| K - matrix size, K>0 | -//| Alpha - coefficient | -//| A - matrix | -//| IA - submatrix offset | -//| JA - submatrix offset | -//| OpTypeA - transformation type: | -//| * 0 - no transformation | -//| * 1 - transposition | -//| * 2 - conjugate transposition | -//| B - matrix | -//| IB - submatrix offset | -//| JB - submatrix offset | -//| OpTypeB - transformation type: | -//| * 0 - no transformation | -//| * 1 - transposition | -//| * 2 - conjugate transposition | -//| Beta - coefficient | -//| C - matrix | -//| IC - submatrix offset | -//| JC - submatrix offset | -//+------------------------------------------------------------------+ -static void CAblas::CMatrixGemm(const int m,const int n,const int k,al_complex &alpha, - CMatrixComplex &a,const int ia,const int ja, - const int optypea,CMatrixComplex &b,const int ib, - const int jb,const int optypeb,al_complex &beta, - CMatrixComplex &c,const int ic,const int jc) - { -//--- create variables - al_complex Beta(1,0); - int s1=0; - int s2=0; - int bs=AblasComplexBlockSize(); -//--- check - if(m<=bs && n<=bs && k<=bs) - { - //--- basic algorithm - CMatrixGemmk(m,n,k,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc); - //--- exit the function - return; - } -//--- check - if(m>=n && m>=k) - { - //--- A*B = (A1 A2)^T*B - AblasComplexSplitLength(a,m,s1,s2); - CMatrixGemm(s1,n,k,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc); - //--- check - if(optypea==0) - CMatrixGemm(s2,n,k,alpha,a,ia+s1,ja,optypea,b,ib,jb,optypeb,beta,c,ic+s1,jc); - else - CMatrixGemm(s2,n,k,alpha,a,ia,ja+s1,optypea,b,ib,jb,optypeb,beta,c,ic+s1,jc); - //--- exit the function - return; - } -//--- check - if(n>=m && n>=k) - { - //---A*B = A*(B1 B2) - AblasComplexSplitLength(a,n,s1,s2); - //--- check - if(optypeb==0) - { - CMatrixGemm(m,s1,k,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc); - CMatrixGemm(m,s2,k,alpha,a,ia,ja,optypea,b,ib,jb+s1,optypeb,beta,c,ic,jc+s1); - } - else - { - CMatrixGemm(m,s1,k,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc); - CMatrixGemm(m,s2,k,alpha,a,ia,ja,optypea,b,ib+s1,jb,optypeb,beta,c,ic,jc+s1); - } - //--- exit the function - return; - } -//--- check - if(k>=m && k>=n) - { - //--- A*B = (A1 A2)*(B1 B2)^T - AblasComplexSplitLength(a,k,s1,s2); - //--- check - if(optypea==0 && optypeb==0) - { - CMatrixGemm(m,n,s1,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc); - CMatrixGemm(m,n,s2,alpha,a,ia,ja+s1,optypea,b,ib+s1,jb,optypeb,Beta,c,ic,jc); - } - //--- check - if(optypea==0 && optypeb!=0) - { - CMatrixGemm(m,n,s1,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc); - CMatrixGemm(m,n,s2,alpha,a,ia,ja+s1,optypea,b,ib,jb+s1,optypeb,Beta,c,ic,jc); - } - //--- check - if(optypea!=0 && optypeb==0) - { - CMatrixGemm(m,n,s1,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc); - CMatrixGemm(m,n,s2,alpha,a,ia+s1,ja,optypea,b,ib+s1,jb,optypeb,Beta,c,ic,jc); - } - //--- check - if(optypea!=0 && optypeb!=0) - { - CMatrixGemm(m,n,s1,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc); - CMatrixGemm(m,n,s2,alpha,a,ia+s1,ja,optypea,b,ib,jb+s1,optypeb,Beta,c,ic,jc); - } - } -//--- exit the function - return; - } -//+------------------------------------------------------------------+ -//| Level 2 variant of CMatrixRightTRSM | -//+------------------------------------------------------------------+ -static void CAblas::CMatrixRightTrsM2(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) - { -//--- check - if(n*m==0) - return; -//--- create variables - int i=0; - int j=0; - al_complex vc=0; - al_complex vd=0; - int i_=0; - int i1_=0; -//--- General case - if(isUpper) - { - //--- Upper triangular matrix - if(optype==0) - { - //--- X*A^(-1) - for(i=0;i=0;j--) - { - vc=0; - vd=1; - //--- check - if(j=0;j--) - { - vc=0; - vd=1; - //--- check - if(j=0;j--) - { - //--- check - if(isUnit) - vd=1; - else - vd=a[i1+j][j1+j]; - //--- change x - x[i2+i].Set(j2+j,x[i2+i][j2+j]/vd); - //--- check - if(j>0) - { - vc=x[i2+i][j2+j]; - i1_=j1-j2; - for(i_=j2;i_0) - { - i1_=j1-j2; - vc=0.0; - for(i_=j2;i_0) - { - i1_=j1-j2; - vc=0.0; - for(i_=j2;i_=0;i--) - { - for(j=i+1;j<=m-1;j++) - { - vc=a[i1+i][j1+j]; - //--- change x - for(i_=j2;i_=0;i--) - { - //--- check - if(isUnit) - vd=1; - else - vd=Beta/a[i1+i][j1+i]; - //--- change x - for(i_=j2;i_=0;j--) - { - vc=a[i1+i][j1+j]; - for(i_=j2;i_=0;i--) - { - //--- check - if(isUnit) - vd=1; - else - vd=Beta/CMath::Conj(a[i1+i][j1+i]); - //--- change x - for(i_=j2;i_=0;j--) - { - vc=CMath::Conj(a[i1+i][j1+j]); - for(i_=j2;i_=0;j--) - { - vr=0; - vd=1; - //--- check - if(j=0;j--) - { - //--- check - if(isUnit) - vd=1; - else - vd=a[i1+j][j1+j]; - //--- change x - x[i2+i].Set(j2+j,x[i2+i][j2+j]/vd); - //--- check - if(j>0) - { - vr=x[i2+i][j2+j]; - i1_=j1-j2; - //--- change x - for(i_=j2;i_0) - { - i1_=j1-j2; - vr=0.0; - for(i_=j2;i_=0;i--) - { - for(j=i+1;j<=m-1;j++) - { - vr=a[i1+i][j1+j]; - for(i_=j2;i_=0;i--) - { - //--- check - if(isUnit) - vd=1; - else - vd=1/a[i1+i][j1+i]; - //--- change x - for(i_=j2;i_=0;j--) - { - vr=a[i1+i][j1+j]; - for(i_=j2;i_0) - { - v=0.0; - for(i_=ja;i_<=ja+k-1;i_++) - v+=a[ia+i][i_]*CMath::Conj(a[ia+j][i_]); - } - else - v=0; - //--- check - if(beta==0) - c[ic+i].Set(jc+j,Alpha*v); - else - c[ic+i].Set(jc+j,Beta*c[ic+i][jc+j]+Alpha*v); - } - } - //--- exit the function - return; - } - else - { - //--- C = alpha*A^H*A+beta*C - for(i=0;iCAblas::AblasBlockSize()) - blocksize=CAblas::AblasBlockSize(); - //--- change - rowscount=m-blockstart; - //--- QR decomposition of submatrix. - //--- Matrix is copied to temporary storage to solve - //--- some TLB issues arising from non-contiguous memory - //--- access pattern. - CAblas::RMatrixCopy(rowscount,blocksize,a,blockstart,blockstart,tmpa,0,0); - RMatrixQRBaseCase(tmpa,rowscount,blocksize,work,t,taubuf); - CAblas::RMatrixCopy(rowscount,blocksize,tmpa,0,0,a,blockstart,blockstart); - i1_=-blockstart; - for(i_=blockstart;i_<=blockstart+blocksize-1;i_++) - tau[i_]=taubuf[i_+i1_]; - //--- check - if(blockstart+blocksize<=n-1) - { - //--- Update the rest, choose between: - //--- a) Level 2 algorithm (when the rest of the matrix is small enough) - //--- b) blocked algorithm, see algorithm 5 from 'A storage efficient WY - //--- representation for products of Householder transformations', - //--- by R. Schreiber and C. Van Loan. - if(n-blockstart-blocksize>=2*CAblas::AblasBlockSize() || rowscount>=4*CAblas::AblasBlockSize()) - { - //--- Prepare block reflector - RMatrixBlockReflector(tmpa,taubuf,true,rowscount,blocksize,tmpt,work); - //--- Multiply the rest of A by Q'. - //--- Q = E + Y*T*Y' = E + TmpA*TmpT*TmpA' - //--- Q' = E + Y*T'*Y' = E + TmpA*TmpT'*TmpA' - CAblas::RMatrixGemm(blocksize,n-blockstart-blocksize,rowscount,1.0,tmpa,0,0,1,a,blockstart,blockstart+blocksize,0,0.0,tmpr,0,0); - CAblas::RMatrixGemm(blocksize,n-blockstart-blocksize,blocksize,1.0,tmpt,0,0,1,tmpr,0,0,0,0.0,tmpr,blocksize,0); - CAblas::RMatrixGemm(rowscount,n-blockstart-blocksize,blocksize,1.0,tmpa,0,0,0,tmpr,blocksize,0,0,1.0,a,blockstart,blockstart+blocksize); - } - else - { - //--- Level 2 algorithm - for(i=0;iCAblas::AblasBlockSize()) - blocksize=CAblas::AblasBlockSize(); - //--- change - columnscount=n-blockstart; - //--- LQ decomposition of submatrix. - //--- Matrix is copied to temporary storage to solve - //--- some TLB issues arising from non-contiguous memory - //--- access pattern. - CAblas::RMatrixCopy(blocksize,columnscount,a,blockstart,blockstart,tmpa,0,0); - RMatrixLQBaseCase(tmpa,blocksize,columnscount,work,t,taubuf); - CAblas::RMatrixCopy(blocksize,columnscount,tmpa,0,0,a,blockstart,blockstart); - i1_=-blockstart; - for(i_=blockstart;i_<=blockstart+blocksize-1;i_++) - { - tau[i_]=taubuf[i_+i1_]; - } - //--- Update the rest, choose between: - //--- a) Level 2 algorithm (when the rest of the matrix is small enough) - //--- b) blocked algorithm, see algorithm 5 from 'A storage efficient WY - //--- representation for products of Householder transformations', - //--- by R. Schreiber and C. Van Loan. - if(blockstart+blocksize<=m-1) - { - //--- check - if(m-blockstart-blocksize>=2*CAblas::AblasBlockSize()) - { - //--- prepare - RMatrixBlockReflector(tmpa,taubuf,false,columnscount,blocksize,tmpt,work); - //--- Multiply the rest of A by Q. - //--- Q = E + Y*T*Y' = E + TmpA'*TmpT*TmpA - CAblas::RMatrixGemm(m-blockstart-blocksize,blocksize,columnscount,1.0,a,blockstart+blocksize,blockstart,0,tmpa,0,0,1,0.0,tmpr,0,0); - CAblas::RMatrixGemm(m-blockstart-blocksize,blocksize,blocksize,1.0,tmpr,0,0,0,tmpt,0,0,0,0.0,tmpr,0,blocksize); - CAblas::RMatrixGemm(m-blockstart-blocksize,columnscount,blocksize,1.0,tmpr,0,blocksize,0,tmpa,0,0,0,1.0,a,blockstart+blocksize,blockstart); - } - else - { - //--- Level 2 algorithm - for(i=0;iCAblas::AblasComplexBlockSize()) - blocksize=CAblas::AblasComplexBlockSize(); - rowscount=m-blockstart; - //--- QR decomposition of submatrix. - //--- Matrix is copied to temporary storage to solve - //--- some TLB issues arising from non-contiguous memory - //--- access pattern. - CAblas::CMatrixCopy(rowscount,blocksize,a,blockstart,blockstart,tmpa,0,0); - CMatrixQRBaseCase(tmpa,rowscount,blocksize,work,t,taubuf); - CAblas::CMatrixCopy(rowscount,blocksize,tmpa,0,0,a,blockstart,blockstart); - i1_=-blockstart; - for(i_=blockstart;i_<=blockstart+blocksize-1;i_++) - tau[i_]=taubuf[i_+i1_]; - //--- Update the rest, choose between: - //--- a) Level 2 algorithm (when the rest of the matrix is small enough) - //--- b) blocked algorithm, see algorithm 5 from 'A storage efficient WY - //--- representation for products of Householder transformations', - //--- by R. Schreiber and C. Van Loan. - if(blockstart+blocksize<=n-1) - { - //--- check - if(n-blockstart-blocksize>=2*CAblas::AblasComplexBlockSize()) - { - //--- Prepare block reflector - CMatrixBlockReflector(tmpa,taubuf,true,rowscount,blocksize,tmpt,work); - //--- Multiply the rest of A by Q'. - //--- Q = E + Y*T*Y' = E + TmpA*TmpT*TmpA' - //--- Q' = E + Y*T'*Y' = E + TmpA*TmpT'*TmpA' - CAblas::CMatrixGemm(blocksize,n-blockstart-blocksize,rowscount,Alpha,tmpa,0,0,2,a,blockstart,blockstart+blocksize,0,Beta,tmpr,0,0); - CAblas::CMatrixGemm(blocksize,n-blockstart-blocksize,blocksize,Alpha,tmpt,0,0,2,tmpr,0,0,0,Beta,tmpr,blocksize,0); - CAblas::CMatrixGemm(rowscount,n-blockstart-blocksize,blocksize,Alpha,tmpa,0,0,0,tmpr,blocksize,0,0,Alpha,a,blockstart,blockstart+blocksize); - } - else - { - //--- Level 2 algorithm - for(i=0;iCAblas::AblasComplexBlockSize()) - blocksize=CAblas::AblasComplexBlockSize(); - columnscount=n-blockstart; - //--- LQ decomposition of submatrix. - //--- Matrix is copied to temporary storage to solve - //--- some TLB issues arising from non-contiguous memory - //--- access pattern. - CAblas::CMatrixCopy(blocksize,columnscount,a,blockstart,blockstart,tmpa,0,0); - CMatrixLQBaseCase(tmpa,blocksize,columnscount,work,t,taubuf); - CAblas::CMatrixCopy(blocksize,columnscount,tmpa,0,0,a,blockstart,blockstart); - i1_=-blockstart; - for(i_=blockstart;i_<=blockstart+blocksize-1;i_++) - tau[i_]=taubuf[i_+i1_]; - //--- Update the rest, choose between: - //--- a) Level 2 algorithm (when the rest of the matrix is small enough) - //--- b) blocked algorithm, see algorithm 5 from 'A storage efficient WY - //--- representation for products of Householder transformations', - //--- by R. Schreiber and C. Van Loan. - if(blockstart+blocksize<=m-1) - { - //--- check - if(m-blockstart-blocksize>=2*CAblas::AblasComplexBlockSize()) - { - //--- Prepare block reflector - CMatrixBlockReflector(tmpa,taubuf,false,columnscount,blocksize,tmpt,work); - //--- Multiply the rest of A by Q. - //--- Q = E + Y*T*Y' = E + TmpA'*TmpT*TmpA - CAblas::CMatrixGemm(m-blockstart-blocksize,blocksize,columnscount,Alpha,a,blockstart+blocksize,blockstart,0,tmpa,0,0,2,Beta,tmpr,0,0); - CAblas::CMatrixGemm(m-blockstart-blocksize,blocksize,blocksize,Alpha,tmpr,0,0,0,tmpt,0,0,0,Beta,tmpr,0,blocksize); - CAblas::CMatrixGemm(m-blockstart-blocksize,columnscount,blocksize,Alpha,tmpr,0,blocksize,0,tmpa,0,0,0,Alpha,a,blockstart+blocksize,blockstart); - } - else - { - //--- Level 2 algorithm - for(i=0;i=0. | -//| N - number of columns in given matrix A. N>=0. | -//| Tau - scalar factors which are used to form Q. | -//| Output of the RMatrixQR subroutine. | -//| QColumns - required number of columns of matrix Q. | -//| M>=QColumns>=0. | -//| Output parameters: | -//| Q - first QColumns columns of matrix Q. | -//| Array whose indexes range within | -//| [0..M-1, 0..QColumns-1]. | -//| If QColumns=0, the array remains unchanged. | -//+------------------------------------------------------------------+ -static void COrtFac::RMatrixQRUnpackQ(CMatrixDouble &a,const int m,const int n, - double &tau[],const int qcolumns,CMatrixDouble &q) - { -//--- check - if(!CAp::Assert(qcolumns<=m,__FUNCTION__+": QColumns>M!")) - return; -//--- check - if(m<=0 || n<=0 || qcolumns<=0) - return; -//--- create arrays - double work[]; - double t[]; - double taubuf[]; -//--- create matrix - CMatrixDouble tmpa; - CMatrixDouble tmpt; - CMatrixDouble tmpr; -//--- create variables - int minmn=MathMin(m,n); - int refcnt=MathMin(minmn,qcolumns); - int blockstart=CAblas::AblasBlockSize()*(refcnt/CAblas::AblasBlockSize()); - int blocksize=refcnt-blockstart; - int rowscount=0; - int i=0; - int j=0; - int i_=0; - int i1_=0; -//--- allocation - q.Resize(m,qcolumns); -//--- identity matrix - for(i=0;i=0) - { - rowscount=m-blockstart; - //--- Copy current block - CAblas::RMatrixCopy(rowscount,blocksize,a,blockstart,blockstart,tmpa,0,0); - i1_=blockstart; - for(i_=0;i_=2*CAblas::AblasBlockSize()) - { - //--- Prepare block reflector - RMatrixBlockReflector(tmpa,taubuf,true,rowscount,blocksize,tmpt,work); - //--- Multiply matrix by Q. - //--- Q = E + Y*T*Y' = E + TmpA*TmpT*TmpA' - CAblas::RMatrixGemm(blocksize,qcolumns,rowscount,1.0,tmpa,0,0,1,q,blockstart,0,0,0.0,tmpr,0,0); - CAblas::RMatrixGemm(blocksize,qcolumns,blocksize,1.0,tmpt,0,0,0,tmpr,0,0,0,0.0,tmpr,blocksize,0); - CAblas::RMatrixGemm(rowscount,qcolumns,blocksize,1.0,tmpa,0,0,0,tmpr,blocksize,0,0,1.0,q,blockstart,0); - } - else - { - //--- Level 2 algorithm - for(i=blocksize-1;i>=0;i--) - { - i1_=i-1; - for(i_=1;i_<=rowscount-i;i_++) - { - t[i_]=tmpa[i_+i1_][i]; - } - t[1]=1; - //--- function call - CReflections::ApplyReflectionFromTheLeft(q,taubuf[i],t,blockstart+i,m-1,0,qcolumns-1,work); - } - } - //--- change value - blockstart=blockstart-CAblas::AblasBlockSize(); - blocksize=CAblas::AblasBlockSize(); - } - } -//+------------------------------------------------------------------+ -//| Unpacking of matrix R from the QR decomposition of a matrix A | -//| Input parameters: | -//| A - matrices Q and R in compact form. | -//| Output of RMatrixQR subroutine. | -//| M - number of rows in given matrix A. M>=0. | -//| N - number of columns in given matrix A. N>=0. | -//| Output parameters: | -//| R - matrix R, array[0..M-1, 0..N-1]. | -//+------------------------------------------------------------------+ -static void COrtFac::RMatrixQRUnpackR(CMatrixDouble &a,const int m,const int n,CMatrixDouble &r) - { -//--- check - if(m<=0 || n<=0) - return; -//--- create variables - int i=0; - int k=MathMin(m,n); - int i_=0; -//--- allocation - r.Resize(m,n); -//--- Prepare matrix - for(i=0;i=0. | -//| N - number of columns in given matrix A. N>=0. | -//| Tau - scalar factors which are used to form Q. | -//| Output of the RMatrixLQ subroutine. | -//| QRows - required number of rows in matrix Q. N>=QRows>=0.| -//| Output parameters: | -//| Q - first QRows rows of matrix Q. Array whose indexes| -//| range within [0..QRows-1, 0..N-1]. If QRows=0, | -//| the array remains unchanged. | -//+------------------------------------------------------------------+ -static void COrtFac::RMatrixLQUnpackQ(CMatrixDouble &a,const int m,const int n, - double &tau[],const int qrows,CMatrixDouble &q) - { -//--- check - if(!CAp::Assert(qrows<=n,__FUNCTION__+": QRows>N!")) - return; -//--- check - if(m<=0 || n<=0 || qrows<=0) - return; -//--- create arrays - double work[]; - double t[]; - double taubuf[]; -//--- create matrix - CMatrixDouble tmpa; - CMatrixDouble tmpt; - CMatrixDouble tmpr; -//--- create variables - int minmn=MathMin(m,n); - int refcnt=MathMin(minmn,qrows); - int blockstart=CAblas::AblasBlockSize()*(refcnt/CAblas::AblasBlockSize()); - int blocksize=refcnt-blockstart; - int columnscount=0; - int i=0; - int j=0; - int i_=0; - int i1_=0; -//--- allocation - ArrayResizeAL(work,MathMax(m,n)+1); - ArrayResizeAL(t,MathMax(m,n)+1); - ArrayResizeAL(taubuf,minmn); -//--- allocation - tmpa.Resize(CAblas::AblasBlockSize(),n); - tmpt.Resize(CAblas::AblasBlockSize(),2*CAblas::AblasBlockSize()); - tmpr.Resize(qrows,2*CAblas::AblasBlockSize()); - q.Resize(qrows,n); -//--- identity matrix - for(i=0;i<=qrows-1;i++) - { - for(j=0;j=0) - { - columnscount=n-blockstart; - //--- Copy submatrix - CAblas::RMatrixCopy(blocksize,columnscount,a,blockstart,blockstart,tmpa,0,0); - i1_=blockstart; - for(i_=0;i_=2*CAblas::AblasBlockSize()) - { - //--- Prepare block reflector - RMatrixBlockReflector(tmpa,taubuf,false,columnscount,blocksize,tmpt,work); - //--- Multiply the rest of A by Q'. - //--- Q' = E + Y*T'*Y' = E + TmpA'*TmpT'*TmpA - CAblas::RMatrixGemm(qrows,blocksize,columnscount,1.0,q,0,blockstart,0,tmpa,0,0,1,0.0,tmpr,0,0); - CAblas::RMatrixGemm(qrows,blocksize,blocksize,1.0,tmpr,0,0,0,tmpt,0,0,1,0.0,tmpr,0,blocksize); - CAblas::RMatrixGemm(qrows,columnscount,blocksize,1.0,tmpr,0,blocksize,0,tmpa,0,0,0,1.0,q,0,blockstart); - } - else - { - //--- Level 2 algorithm - for(i=blocksize-1;i>=0;i--) - { - i1_=i-1; - for(i_=1;i_<=columnscount-i;i_++) - t[i_]=tmpa[i][i_+i1_]; - t[1]=1; - //--- function call - CReflections::ApplyReflectionFromTheRight(q,taubuf[i],t,0,qrows-1,blockstart+i,n-1,work); - } - } - //--- change value - blockstart=blockstart-CAblas::AblasBlockSize(); - blocksize=CAblas::AblasBlockSize(); - } - } -//+------------------------------------------------------------------+ -//| Unpacking of matrix L from the LQ decomposition of a matrix A | -//| Input parameters: | -//| A -matrices Q and L in compact form. | -//| Output of RMatrixLQ subroutine. | -//| M -number of rows in given matrix A. M>=0. | -//| N -number of columns in given matrix A. N>=0. | -//| Output parameters: | -//| L -matrix L, array[0..M-1,0..N-1]. | -//+------------------------------------------------------------------+ -static void COrtFac::RMatrixLQUnpackL(CMatrixDouble &a,const int m,const int n,CMatrixDouble &l) - { -//--- check - if(m<=0 || n<=0) - return; -//--- create variables - int i=0; - int k=0; - int i_=0; -//--- allocation - l.Resize(m,n); -//--- Prepare matrix - for(i=0;i=0. | -//| N - number of columns in matrix A. N>=0. | -//| Tau - scalar factors which are used to form Q. | -//| Output of CMatrixQR subroutine . | -//| QColumns - required number of columns in matrix Q. | -//| M>=QColumns>=0. | -//| Output parameters: | -//| Q - first QColumns columns of matrix Q. | -//| Array whose index ranges within [0..M-1, | -//| 0..QColumns-1]. | -//| If QColumns=0, array isn't changed. | -//+------------------------------------------------------------------+ -static void COrtFac::CMatrixQRUnpackQ(CMatrixComplex &a,const int m,const int n, - al_complex &tau[],const int qcolumns,CMatrixComplex &q) - { -//--- check - if(!CAp::Assert(qcolumns<=m,__FUNCTION__+": QColumns>M!")) - return; -//--- check - if(m<=0 || n<=0) - return; -//--- create arrays - al_complex work[]; - al_complex t[]; - al_complex taubuf[]; -//--- create matrix - CMatrixComplex tmpa; - CMatrixComplex tmpt; - CMatrixComplex tmpr; -//--- create variables - int minmn=MathMin(m,n); - int refcnt=MathMin(minmn,qcolumns); - int blockstart=CAblas::AblasComplexBlockSize()*(refcnt/CAblas::AblasComplexBlockSize()); - int blocksize=refcnt-blockstart; - int rowscount=0; - int i=0; - int j=0; - int i_=0; - int i1_=0; - al_complex One(1,0); - al_complex Zero(0,0); -//--- allocation - ArrayResizeAL(work,MathMax(m,n)+1); - ArrayResizeAL(t,MathMax(m,n)+1); - ArrayResizeAL(taubuf,minmn); -//--- allocation - tmpa.Resize(m,CAblas::AblasComplexBlockSize()); - tmpt.Resize(CAblas::AblasComplexBlockSize(),CAblas::AblasComplexBlockSize()); - tmpr.Resize(2*CAblas::AblasComplexBlockSize(),qcolumns); - q.Resize(m,qcolumns); - for(i=0;i=0) - { - rowscount=m-blockstart; - //--- QR decomposition of submatrix. - //--- Matrix is copied to temporary storage to solve - //--- some TLB issues arising from non-contiguous memory - //--- access pattern. - CAblas::CMatrixCopy(rowscount,blocksize,a,blockstart,blockstart,tmpa,0,0); - i1_=blockstart; - for(i_=0;i_=2*CAblas::AblasComplexBlockSize()) - { - //--- Prepare block reflector - CMatrixBlockReflector(tmpa,taubuf,true,rowscount,blocksize,tmpt,work); - //--- Multiply the rest of A by Q. - //--- Q = E + Y*T*Y' = E + TmpA*TmpT*TmpA' - CAblas::CMatrixGemm(blocksize,qcolumns,rowscount,One,tmpa,0,0,2,q,blockstart,0,0,Zero,tmpr,0,0); - CAblas::CMatrixGemm(blocksize,qcolumns,blocksize,One,tmpt,0,0,0,tmpr,0,0,0,Zero,tmpr,blocksize,0); - CAblas::CMatrixGemm(rowscount,qcolumns,blocksize,One,tmpa,0,0,0,tmpr,blocksize,0,0,One,q,blockstart,0); - } - else - { - //--- Level 2 algorithm - for(i=blocksize-1;i>=0;i--) - { - i1_=i-1; - for(i_=1;i_<=rowscount-i;i_++) - t[i_]=tmpa[i_+i1_][i]; - t[1]=1; - //--- function call - CComplexReflections::ComplexApplyReflectionFromTheLeft(q,taubuf[i],t,blockstart+i,m-1,0,qcolumns-1,work); - } - } - //--- change value - blockstart=blockstart-CAblas::AblasComplexBlockSize(); - blocksize=CAblas::AblasComplexBlockSize(); - } - } -//+------------------------------------------------------------------+ -//| Unpacking of matrix R from the QR decomposition of a matrix A | -//| Input parameters: | -//| A - matrices Q and R in compact form. | -//| Output of CMatrixQR subroutine. | -//| M - number of rows in given matrix A. M>=0. | -//| N - number of columns in given matrix A. N>=0. | -//| Output parameters: | -//| R - matrix R, array[0..M-1, 0..N-1]. | -//+------------------------------------------------------------------+ -static void COrtFac::CMatrixQRUnpackR(CMatrixComplex &a,const int m,const int n,CMatrixComplex &r) - { -//--- check - if(m<=0 || n<=0) - return; -//--- create variables - al_complex Zero(0,0); - int i=0; - int k=MathMin(m,n); - int i_=0; -//--- allocation - r.Resize(m,n); -//--- Prepare matrix - for(i=0;i=0. | -//| N - number of columns in matrix A. N>=0. | -//| Tau - scalar factors which are used to form Q. | -//| Output of CMatrixLQ subroutine . | -//| QRows - required number of rows in matrix Q. | -//| N>=QColumns>=0. | -//| Output parameters: | -//| Q - first QRows rows of matrix Q. | -//| Array whose index ranges within [0..QRows-1, | -//| 0..N-1]. | -//| If QRows=0, array isn't changed. | -//+------------------------------------------------------------------+ -static void COrtFac::CMatrixLQUnpackQ(CMatrixComplex &a,const int m,const int n, - al_complex &tau[],const int qrows,CMatrixComplex &q) - { -//--- check - if(m<=0 || n<=0) - return; -//--- create arrays - al_complex work[]; - al_complex t[]; - al_complex taubuf[]; -//--- create matrix - CMatrixComplex tmpa; - CMatrixComplex tmpt; - CMatrixComplex tmpr; -//--- create variables - int minmn=MathMin(m,n); - int refcnt=MathMin(minmn,qrows); - int blockstart=CAblas::AblasComplexBlockSize()*(refcnt/CAblas::AblasComplexBlockSize()); - int blocksize=refcnt-blockstart; - int columnscount=0; - int i=0; - int j=0; - int i_=0; - int i1_=0; - al_complex One(1,0); - al_complex Zero(0,0); -//--- allocation - ArrayResizeAL(work,MathMax(m,n)+1); - ArrayResizeAL(t,MathMax(m,n)+1); - ArrayResizeAL(taubuf,minmn); -//--- allocation - tmpa.Resize(CAblas::AblasComplexBlockSize(),n); - tmpt.Resize(CAblas::AblasComplexBlockSize(),CAblas::AblasComplexBlockSize()); - tmpr.Resize(qrows,2*CAblas::AblasComplexBlockSize()); - q.Resize(qrows,n); - for(i=0;i<=qrows-1;i++) - { - for(j=0;j=0) - { - columnscount=n-blockstart; - //--- LQ decomposition of submatrix. - //--- Matrix is copied to temporary storage to solve - //--- some TLB issues arising from non-contiguous memory - //--- access pattern. - CAblas::CMatrixCopy(blocksize,columnscount,a,blockstart,blockstart,tmpa,0,0); - i1_=blockstart; - for(i_=0;i_=2*CAblas::AblasComplexBlockSize()) - { - //--- Prepare block reflector - CMatrixBlockReflector(tmpa,taubuf,false,columnscount,blocksize,tmpt,work); - //--- Multiply the rest of A by Q'. - //--- Q' = E + Y*T'*Y' = E + TmpA'*TmpT'*TmpA - CAblas::CMatrixGemm(qrows,blocksize,columnscount,One,q,0,blockstart,0,tmpa,0,0,2,Zero,tmpr,0,0); - CAblas::CMatrixGemm(qrows,blocksize,blocksize,One,tmpr,0,0,0,tmpt,0,0,2,Zero,tmpr,0,blocksize); - CAblas::CMatrixGemm(qrows,columnscount,blocksize,One,tmpr,0,blocksize,0,tmpa,0,0,0,One,q,0,blockstart); - } - else - { - //--- Level 2 algorithm - for(i=blocksize-1;i>=0;i--) - { - i1_=i-1; - for(i_=1;i_<=columnscount-i;i_++) - t[i_]=CMath::Conj(tmpa[i][i_+i1_]); - t[1]=1; - //--- function call - CComplexReflections::ComplexApplyReflectionFromTheRight(q,CMath::Conj(taubuf[i]),t,0,qrows-1,blockstart+i,n-1,work); - } - } - //--- change value - blockstart=blockstart-CAblas::AblasComplexBlockSize(); - blocksize=CAblas::AblasComplexBlockSize(); - } - } -//+------------------------------------------------------------------+ -//| Unpacking of matrix L from the LQ decomposition of a matrix A | -//| Input parameters: | -//| A - matrices Q and L in compact form. | -//| Output of CMatrixLQ subroutine. | -//| M - number of rows in given matrix A. M>=0. | -//| N - number of columns in given matrix A. N>=0. | -//| Output parameters: | -//| L - matrix L, array[0..M-1, 0..N-1]. | -//+------------------------------------------------------------------+ -static void COrtFac::CMatrixLQUnpackL(CMatrixComplex &a,const int m,const int n,CMatrixComplex &l) - { -//--- check - if(m<=0 || n<=0) - return; -//--- create variables - al_complex Zero(0,0); - int i=0; - int k=0; - int i_=0; -//--- allocation - l.Resize(m,n); -//--- Prepare matrix - for(i=0;i=N, B is the upper bidiagonal MxN matrix and is stored in | -//| the corresponding elements of matrix A. Matrix Q is represented | -//| as a product of elementary reflections Q = H(0)*H(1)*...*H(n-1), | -//| where H(i) = 1-tau*v*v'. Here tau is a scalar which is stored in | -//| TauQ[i], and vector v has the following structure: v(0:i-1)=0, | -//| v(i)=1, v(i+1:m-1) is stored in elements A(i+1:m-1,i).Matrix P is| -//| as follows: P = G(0)*G(1)*...*G(n-2), where G(i) = 1 - tau*u*u'. | -//| Tau is stored in TauP[i], u(0:i)=0, u(i+1)=1, u(i+2:n-1) is | -//| stored in elements A(i,i+2:n-1). | -//| If M n): m=5, n=6 (m < n): | -//| ( d e u1 u1 u1 ) ( d u1 u1 u1 u1 u1 ) | -//| ( v1 d e u2 u2 ) ( e d u2 u2 u2 u2 ) | -//| ( v1 v2 d e u3 ) ( v1 e d u3 u3 u3 ) | -//| ( v1 v2 v3 d e ) ( v1 v2 e d u4 u4 ) | -//| ( v1 v2 v3 v4 d ) ( v1 v2 v3 e d u5 ) | -//| ( v1 v2 v3 v4 v5 ) | -//| Here vi and ui are vectors which form H(i) and G(i), and d and | -//| e - are the diagonal and off-diagonal elements of matrix B. | -//+------------------------------------------------------------------+ -static void COrtFac::RMatrixBD(CMatrixDouble &a,const int m,const int n,double &tauq[],double &taup[]) - { -//--- check - if(n<=0 || m<=0) - return; -//--- create arrays - double work[]; - double t[]; -//--- create variables - int minmn=0; - int maxmn=MathMax(m,n); - int i=0; - double ltau=0; - int i_=0; - int i1_=0; -//--- allocation - ArrayResizeAL(work,maxmn+1); - ArrayResizeAL(t,maxmn+1); -//--- check - if(m>=n) - { - ArrayResizeAL(tauq,n); - ArrayResizeAL(taup,n); - } - else - { - ArrayResizeAL(tauq,m); - ArrayResizeAL(taup,m); - } -//--- check - if(m>=n) - { - //--- Reduce to upper bidiagonal form - for(i=0;i=QColumns>=0. | -//| Output parameters: | -//| Q - first QColumns columns of matrix Q. | -//| Array[0..M-1, 0..QColumns-1] | -//| If QColumns=0, the array is not modified. | -//+------------------------------------------------------------------+ -static void COrtFac::RMatrixBDUnpackQ(CMatrixDouble &qp,const int m,const int n, - double &tauq[],const int qcolumns,CMatrixDouble &q) - { -//--- check - if(!CAp::Assert(qcolumns<=m,__FUNCTION__+": QColumns>M!")) - return; -//--- check - if(!CAp::Assert(qcolumns>=0,__FUNCTION__+": QColumns<0!")) - return; -//--- check - if(m==0 || n==0 || qcolumns==0) - return; -//--- create variables - int i=0; - int j=0; -//--- allocation - q.Resize(m,qcolumns); -//--- identity matrix - for(i=0;i=n) - { - //--- setup - if(fromtheright) - { - i1=0; - i2=n-1; - istep=1; - } - else - { - i1=n-1; - i2=0; - istep=-1; - } - //--- check - if(dotranspose) - { - i=i1; - i1=i2; - i2=i; - istep=-istep; - } - //--- Process - i=i1; - do - { - i1_=i-1; - for(i_=1;i_<=m-i;i_++) - v[i_]=qp[i_+i1_][i]; - v[1]=1; - //--- check - if(fromtheright) - CReflections::ApplyReflectionFromTheRight(z,tauq[i],v,0,zrows-1,i,m-1,work); - else - CReflections::ApplyReflectionFromTheLeft(z,tauq[i],v,i,m-1,0,zcolumns-1,work); - i=i+istep; - } - while(i!=i2+istep); - } - else - { - //--- setup - if(fromtheright) - { - i1=0; - i2=m-2; - istep=1; - } - else - { - i1=m-2; - i2=0; - istep=-1; - } - //--- check - if(dotranspose) - { - i=i1; - i1=i2; - i2=i; - istep=-istep; - } - //--- Process - if(m-1>0) - { - i=i1; - do - { - i1_=i; - for(i_=1;i_<=m-i-1;i_++) - v[i_]=qp[i_+i1_][i]; - v[1]=1; - //--- check - if(fromtheright) - CReflections::ApplyReflectionFromTheRight(z,tauq[i],v,0,zrows-1,i+1,m-1,work); - else - CReflections::ApplyReflectionFromTheLeft(z,tauq[i],v,i+1,m-1,0,zcolumns-1,work); - i=i+istep; - } - while(i!=i2+istep); - } - } - } -//+------------------------------------------------------------------+ -//| Unpacking matrix P which reduces matrix A to bidiagonal form. | -//| The subroutine returns transposed matrix P. | -//| Input parameters: | -//| QP - matrices Q and P in compact form. | -//| Output of ToBidiagonal subroutine. | -//| M - number of rows in matrix A. | -//| N - number of columns in matrix A. | -//| TAUP - scalar factors which are used to form P. | -//| Output of ToBidiagonal subroutine. | -//| PTRows - required number of rows of matrix P^T. | -//| N >= PTRows >= 0. | -//| Output parameters: | -//| PT - first PTRows columns of matrix P^T | -//| Array[0..PTRows-1, 0..N-1] | -//| If PTRows=0, the array is not modified. | -//+------------------------------------------------------------------+ -static void COrtFac::RMatrixBDUnpackPT(CMatrixDouble &qp,const int m,const int n, - double &taup[],const int ptrows,CMatrixDouble &pt) - { -//--- check - if(!CAp::Assert(ptrows<=n,__FUNCTION__+": PTRows>N!")) - return; -//--- check - if(!CAp::Assert(ptrows>=0,__FUNCTION__+": PTRows<0!")) - return; -//--- check - if(m==0 || n==0 || ptrows==0) - return; -//--- create variables - int i=0; - int j=0; -//--- allocation - pt.Resize(ptrows,n); -//--- prepare - for(i=0;i<=ptrows-1;i++) - { - for(j=0;j=n) - { - //--- setup - if(fromtheright) - { - i1=n-2; - i2=0; - istep=-1; - } - else - { - i1=0; - i2=n-2; - istep=1; - } - //--- check - if(!dotranspose) - { - i=i1; - i1=i2; - i2=i; - istep=-istep; - } - //--- Process - if(n-1>0) - { - i=i1; - do - { - i1_=i; - for(i_=1;i_=n) - isupper=true; - else - isupper=false; -//--- check - if(isupper) - { - //--- allocation - ArrayResizeAL(d,n); - ArrayResizeAL(e,n); - //--- get result - for(i=0;i=0,__FUNCTION__+": incorrect N!")) - return; -//--- create arrays - double t[]; - double work[]; -//--- create variables - int i=0; - double v=0; - int i_=0; - int i1_=0; -//--- allocation - ArrayResizeAL(tau,n-1); - ArrayResizeAL(t,n+1); - ArrayResizeAL(work,n); - for(i=0;i1) - ArrayResizeAL(tau,n-1); - ArrayResizeAL(d,n); -//--- check - if(n>1) - ArrayResizeAL(e,n-1); -//--- check - if(isupper) - { - //--- Reduce the upper triangle of A - for(i=n-2;i>=0;i--) - { - //--- Generate elementary reflector H() = E - tau * v * v' - if(i>=1) - { - i1_=-2; - for(i_=2;i_<=i+1;i_++) - t[i_]=a[i_+i1_][i+1]; - } - t[1]=a[i][i+1]; - CReflections::GenerateReflection(t,i+1,taui); - //--- check - if(i>=1) - { - i1_=2; - for(i_=0;i_=0;i--) - { - //--- Apply H(i) - i1_=i; - for(i_=1;i_1) - { - ArrayResizeAL(tau,n-1); - ArrayResizeAL(e,n-1); - } - ArrayResizeAL(d,n); - ArrayResizeAL(t,n); - ArrayResizeAL(t2,n); - ArrayResizeAL(t3,n); -//--- check - if(isupper) - { - //--- Reduce the upper triangle of A - a[n-1].Set(n-1,a[n-1][n-1].re); - for(i=n-2;i>=0;i--) - { - //--- Generate elementary reflector H = I+1 - tau * v * v' - alpha=a[i][i+1]; - t[1]=alpha; - //--- check - if(i>=1) - { - i1_=-2; - for(i_=2;i_<=i+1;i_++) - t[i_]=a[i_+i1_][i+1]; - } - //--- function call - CComplexReflections::ComplexGenerateReflection(t,i+1,taui); - //--- check - if(i>=1) - { - i1_=2; - for(i_=0;i_=0;i--) - { - //--- Apply H(i) - i1_=i; - for(i_=1;i_=0). | -//| W - array of the eigenvalues found. | -//| Array whose index ranges within [0..M-1]. | -//| Z - if ZNeeded is equal to: | -//| * 0, Z hasn?t changed; | -//| * 1, Z contains eigenvectors. | -//| Array whose indexes range within | -//| [0..N-1, 0..M-1]. | -//| The eigenvectors are stored in the matrix | -//| columns. | -//| Result: | -//| True, if successful. M contains the number of eigenvalues in | -//| the given half-interval (could be equal to 0), W contains the| -//| eigenvalues, Z contains the eigenvectors (if needed). | -//| False, if the bisection method subroutine wasn't able to find| -//| the eigenvalues in the given interval or if the inverse | -//| iteration subroutine wasn't able to find all the | -//| corresponding eigenvectors. In that case, the eigenvalues | -//| and eigenvectors are not returned, M is equal to 0. | -//+------------------------------------------------------------------+ -static bool CEigenVDetect::SMatrixEVDR(CMatrixDouble &ca,const int n,const int zneeded, - const bool isupper,const double b1,const double b2, - int &m,double &w[],CMatrixDouble &z) - { -//--- create arrays - double tau[]; - double e[]; -//--- create copy - CMatrixDouble a; - a=ca; -//--- initialization - m=0; -//--- check - if(!CAp::Assert(zneeded==0 || zneeded==1,__FUNCTION__+": incorrect ZNeeded")) - return(false); -//--- function call - COrtFac::SMatrixTD(a,n,isupper,tau,w,e); -//--- check - if(zneeded==1) - { - //--- function call - COrtFac::SMatrixTDUnpackQ(a,n,isupper,tau,z); - } -//--- return result - return(SMatrixTdEVDR(w,e,n,zneeded,b1,b2,m,z)); - } -//+------------------------------------------------------------------+ -//| Subroutine for finding the eigenvalues and eigenvectors of a | -//| symmetric matrix with given indexes by using bisection and | -//| inverse iteration methods. | -//| Input parameters: | -//| A - symmetric matrix which is given by its upper or | -//| lower triangular part. Array whose indexes range | -//| within [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| ZNeeded - flag controlling whether the eigenvectors are | -//| needed or not. | -//| If ZNeeded is equal to: | -//| * 0, the eigenvectors are not returned; | -//| * 1, the eigenvectors are returned. | -//| IsUpperA - storage format of matrix A. | -//| I1, I2 - index interval for searching (from I1 to I2). | -//| 0 <= I1 <= I2 <= N-1. | -//| Output parameters: | -//| W - array of the eigenvalues found. | -//| Array whose index ranges within [0..I2-I1]. | -//| Z - if ZNeeded is equal to: | -//| * 0, Z hasn?t changed; | -//| * 1, Z contains eigenvectors. | -//| Array whose indexes range within | -//| [0..N-1, 0..I2-I1]. | -//| In that case, the eigenvectors are stored in the | -//| matrix columns. | -//| Result: | -//| True, if successful. W contains the eigenvalues, Z contains | -//| the eigenvectors (if needed). | -//| False, if the bisection method subroutine wasn't able to find| -//| the eigenvalues in the given interval or if the inverse | -//| iteration subroutine wasn't able to find all the | -//| corresponding eigenvectors. In that case, the eigenvalues | -//| and eigenvectors are not returned. | -//+------------------------------------------------------------------+ -static bool CEigenVDetect::SMatrixEVDI(CMatrixDouble &ca,const int n,const int zneeded, - const bool isupper,const int i1,const int i2, - double &w[],CMatrixDouble &z) - { -//--- create arrays - double tau[]; - double e[]; -//--- create copy - CMatrixDouble a; - a=ca; -//--- check - if(!CAp::Assert(zneeded==0 || zneeded==1,__FUNCTION__+": incorrect ZNeeded")) - return(false); -//--- function call - COrtFac::SMatrixTD(a,n,isupper,tau,w,e); -//--- check - if(zneeded==1) - { - //--- function call - COrtFac::SMatrixTDUnpackQ(a,n,isupper,tau,z); - } -//--- return result - return(SMatrixTdEVDI(w,e,n,zneeded,i1,i2,z)); - } -//+------------------------------------------------------------------+ -//| Finding the eigenvalues and eigenvectors of a Hermitian matrix | -//| The algorithm finds eigen pairs of a Hermitian matrix by reducing| -//| it to real tridiagonal form and using the QL/QR algorithm. | -//| Input parameters: | -//| A - Hermitian matrix which is given by its upper or | -//| lower triangular part. | -//| Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| IsUpper - storage format. | -//| ZNeeded - flag controlling whether the eigenvectors are | -//| needed or not. If ZNeeded is equal to: | -//| * 0, the eigenvectors are not returned; | -//| * 1, the eigenvectors are returned. | -//| Output parameters: | -//| D - eigenvalues in ascending order. | -//| Array whose index ranges within [0..N-1]. | -//| Z - if ZNeeded is equal to: | -//| * 0, Z hasn?t changed; | -//| * 1, Z contains the eigenvectors. | -//| Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| The eigenvectors are stored in the matrix | -//| columns. | -//| Result: | -//| True, if the algorithm has converged. | -//| False, if the algorithm hasn't converged (rare case). | -//| Note: | -//| eigenvectors of Hermitian matrix are defined up to | -//| multiplication by a complex number L, such that |L|=1. | -//+------------------------------------------------------------------+ -static bool CEigenVDetect::HMatrixEVD(CMatrixComplex &ca,const int n,int zneeded, - const bool isupper,double &d[],CMatrixComplex &z) - { -//--- create variables - int i=0; - int k=0; - double v=0; - int i_=0; - bool result; -//--- create arrays - al_complex tau[]; - double e[]; - double work[]; -//--- create matrix - CMatrixDouble t; - CMatrixComplex q; -//--- create copy - CMatrixComplex a; - a=ca; -//--- check - if(!CAp::Assert(zneeded==0 || zneeded==1,__FUNCTION__+": incorrect ZNeeded")) - return(false); -//--- Reduce to tridiagonal form - COrtFac::HMatrixTD(a,n,isupper,tau,d,e); -//--- check - if(zneeded==1) - { - //--- function call - COrtFac::HMatrixTDUnpackQ(a,n,isupper,tau,q); - zneeded=2; - } -//--- get result - result=SMatrixTdEVD(d,e,n,zneeded,t); -//--- Eigenvectors are needed -//--- Calculate Z = Q*T = Re(Q)*T + i*Im(Q)*T - if(result && zneeded!=0) - { - ArrayResizeAL(work,n); - z.Resize(n,n); - for(i=0;i=0 | -//| W - array of the eigenvalues found. | -//| Array whose index ranges within [0..M-1]. | -//| Z - if ZNeeded is equal to: | -//| * 0, Z hasn?t changed; | -//| * 1, Z contains eigenvectors. | -//| Array whose indexes range within | -//| [0..N-1, 0..M-1]. | -//| The eigenvectors are stored in the matrix | -//| columns. | -//| Result: | -//| True, if successful. M contains the number of eigenvalues | -//| in the given half-interval (could be equal to 0), W contains | -//| the eigenvalues, Z contains the eigenvectors (if needed). | -//| False, if the bisection method subroutine wasn't able to find| -//| the eigenvalues in the given interval or if the inverse | -//| iteration subroutine wasn't able to find all the | -//| corresponding eigenvectors. In that case, the eigenvalues and| -//| eigenvectors are not returned, M is equal to 0. | -//| Note: | -//| eigen vectors of Hermitian matrix are defined up to | -//| multiplication by a complex number L, such as |L|=1. | -//+------------------------------------------------------------------+ -static bool CEigenVDetect::HMatrixEVDR(CMatrixComplex &ca,const int n,int zneeded, - bool isupper,const double b1,const double b2, - int &m,double &w[],CMatrixComplex &z) - { -//--- create variables - int i=0; - int k=0; - double v=0; - int i_=0; - bool result; -//--- create arrays - al_complex tau[]; - double e[]; - double work[]; -//--- create matrix - CMatrixComplex q; - CMatrixDouble t; -//--- create copy - CMatrixComplex a; - a=ca; -//--- initialization - m=0; -//--- check - if(!CAp::Assert(zneeded==0 || zneeded==1,__FUNCTION__+": incorrect ZNeeded")) - return(false); -//--- Reduce to tridiagonal form - COrtFac::HMatrixTD(a,n,isupper,tau,w,e); -//--- check - if(zneeded==1) - { - //--- function call - COrtFac::HMatrixTDUnpackQ(a,n,isupper,tau,q); - zneeded=2; - } -//--- Bisection and inverse iteration - result=SMatrixTdEVDR(w,e,n,zneeded,b1,b2,m,t); -//--- Eigenvectors are needed -//--- Calculate Z = Q*T = Re(Q)*T + i*Im(Q)*T - if((result && zneeded!=0) && m!=0) - { - ArrayResizeAL(work,m); - z.Resize(n,m); - for(i=0;i1) - { - i1_=-1; - for(i_=1;i_=0. | -//| ZNeeded - flag controlling whether the eigenvectors are | -//| needed or not. If ZNeeded is equal to: | -//| * 0, the eigenvectors are not needed; | -//| * 1, the eigenvectors of a tridiagonal matrix | -//| are multiplied by the square matrix Z. It is | -//| used if the tridiagonal matrix is obtained by | -//| the similarity transformation of a symmetric | -//| matrix. | -//| * 2, the eigenvectors of a tridiagonal matrix | -//| replace matrix Z. | -//| A, B - half-interval (A, B] to search eigenvalues in. | -//| Z - if ZNeeded is equal to: | -//| * 0, Z isn't used and remains unchanged; | -//| * 1, Z contains the square matrix (array whose | -//| indexes range within [0..N-1, 0..N-1]) which | -//| reduces the given symmetric matrix to | -//| tridiagonal form; | -//| * 2, Z isn't used (but changed on the exit). | -//| Output parameters: | -//| D - array of the eigenvalues found. | -//| Array whose index ranges within [0..M-1]. | -//| M - number of eigenvalues found in the given | -//| half-interval (M>=0). | -//| Z - if ZNeeded is equal to: | -//| * 0, doesn't contain any information; | -//| * 1, contains the product of a given NxN matrix | -//| Z (from the left) and NxM matrix of the | -//| eigenvectors found (from the right). Array | -//| whose indexes range within [0..N-1, 0..M-1]. | -//| * 2, contains the matrix of the eigenvectors | -//| found. Array whose indexes range within | -//| [0..N-1, 0..M-1]. | -//| Result: | -//| True, if successful. In that case, M contains the number of | -//| eigenvalues in the given half-interval (could be equal to 0),| -//| D contains the eigenvalues, Z contains the eigenvectors (if | -//| needed). It should be noted that the subroutine changes the | -//| size of arrays D and Z. | -//| False, if the bisection method subroutine wasn't able to find| -//| the eigenvalues in the given interval or if the inverse | -//| iteration subroutine wasn't able to find all the | -//| corresponding eigenvectors. In that case, the eigenvalues and| -//| eigenvectors are not returned, M is equal to 0. | -//+------------------------------------------------------------------+ -static bool CEigenVDetect::SMatrixTdEVDR(double &d[],double &e[],const int n, - const int zneeded,const double a, - const double b,int &m,CMatrixDouble &z) - { -//--- create variables - bool result; - int errorcode=0; - int nsplit=0; - int i=0; - int j=0; - int k=0; - int cr=0; - double v=0; - int i_=0; - int i1_=0; -//--- create arrays - int iblock[]; - int isplit[]; - int ifail[]; - double d1[]; - double e1[]; - double w[]; -//--- create matrix - CMatrixDouble z2; - CMatrixDouble z3; -//--- initialization - m=0; -//--- check - if(!CAp::Assert(zneeded>=0 && zneeded<=2,__FUNCTION__+": incorrect ZNeeded!")) - return(false); -//--- check - if(b<=a) - { - m=0; - //--- return result - return(true); - } -//--- check - if(n<=0) - { - m=0; - //--- return result - return(true); - } -//--- Copy D,E to D1, E1 - ArrayResizeAL(d1,n+1); - i1_=-1; - for(i_=1;i_<=n;i_++) - d1[i_]=d[i_+i1_]; -//--- check - if(n>1) - { - ArrayResizeAL(e1,n); - i1_=-1; - for(i_=1;i_=0. | -//| ZNeeded - flag controlling whether the eigenvectors are | -//| needed or not. If ZNeeded is equal to: | -//| * 0, the eigenvectors are not needed; | -//| * 1, the eigenvectors of a tridiagonal matrix | -//| are multiplied by the square matrix Z. It is | -//| used if the tridiagonal matrix is obtained by | -//| the similarity transformation of a symmetric | -//| matrix. | -//| * 2, the eigenvectors of a tridiagonal matrix | -//| replace matrix Z. | -//| I1, I2 - index interval for searching (from I1 to I2). | -//| 0 <= I1 <= I2 <= N-1. | -//| Z - if ZNeeded is equal to: | -//| * 0, Z isn't used and remains unchanged; | -//| * 1, Z contains the square matrix (array whose | -//| indexes range within [0..N-1, 0..N-1]) which | -//| reduces the given symmetric matrix to | -//| tridiagonal form; | -//| * 2, Z isn't used (but changed on the exit). | -//| Output parameters: | -//| D - array of the eigenvalues found. | -//| Array whose index ranges within [0..I2-I1]. | -//| Z - if ZNeeded is equal to: | -//| * 0, doesn't contain any information; | -//| * 1, contains the product of a given NxN matrix | -//| Z (from the left) and Nx(I2-I1) matrix of the | -//| eigenvectors found (from the right). Array | -//| whose indexes range within [0..N-1, 0..I2-I1].| -//| * 2, contains the matrix of the eigenvalues | -//| found. Array whose indexes range within | -//| [0..N-1, 0..I2-I1]. | -//| Result: | -//| True, if successful. In that case, D contains the | -//| eigenvalues, Z contains the eigenvectors (if needed). | -//| It should be noted that the subroutine changes the size of | -//| arrays D and Z. | -//| False, if the bisection method subroutine wasn't able to find| -//| the eigenvalues in the given interval or if the inverse | -//| iteration subroutine wasn't able to find all the | -//| corresponding eigenvectors. In that case, the eigenvalues and| -//| eigenvectors are not returned. | -//+------------------------------------------------------------------+ -static bool CEigenVDetect::SMatrixTdEVDI(double &d[],double &e[],const int n, - const int zneeded,const int i1, - const int i2,CMatrixDouble &z) - { -//--- create variables - bool result; - int errorcode=0; - int nsplit=0; - int i=0; - int j=0; - int k=0; - int m=0; - int cr=0; - double v=0; - int i_=0; - int i1_=0; -//--- create arrays - int iblock[]; - int isplit[]; - int ifail[]; - double w[]; - double d1[]; - double e1[]; -//--- create matrix - CMatrixDouble z2; - CMatrixDouble z3; -//--- check - if(!CAp::Assert((0<=i1 && i1<=i2) && i21) - { - ArrayResizeAL(e1,n); - i1_=-1; - for(i_=1;i_0, we have a pair of complex conjugate | -//| numbers with positive and negative imaginary | -//| parts: the first eigenvalue WR[i] + | -//| + sqrt(-1)*WI[i]; the second eigenvalue | -//| WR[i+1] + sqrt(-1)*WI[i+1]; | -//| WI[i]>0 | -//| WI[i+1] = -WI[i] < 0 | -//| In that case, the eigenvector corresponding to | -//| the first eigenvalue is located in i and i+1 | -//| columns of matrices VL/VR (the column number i | -//| contains the real part, and the column number | -//| i+1 contains the imaginary part), and the vector | -//| corresponding to the second eigenvalue is a | -//| complex conjugate to the first vector. | -//| Arrays whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| Result: | -//| True, if the algorithm has converged. | -//| False, if the algorithm has not converged. | -//| Note 1: | -//| Some users may ask the following question: what if WI[N-1]>0?| -//| WI[N] must contain an eigenvalue which is complex conjugate | -//| to the N-th eigenvalue, but the array has only size N? | -//| The answer is as follows: such a situation cannot occur | -//| because the algorithm finds a pairs of eigenvalues, | -//| therefore, if WI[i]>0, I is strictly less than N-1. | -//| Note 2: | -//| The algorithm performance depends on the value of the | -//| internal parameter NS of the InternalSchurDecomposition | -//| subroutine which defines the number of shifts in the QR | -//| algorithm (similarly to the block width in block-matrix | -//| algorithms of linear algebra). If you require maximum | -//| performance on your machine, it is recommended to adjust | -//| this parameter manually. | -//| See also the InternalTREVC subroutine. | -//| The algorithm is based on the LAPACK 3.0 library. | -//+------------------------------------------------------------------+ -static bool CEigenVDetect::RMatrixEVD(CMatrixDouble &ca,const int n,const int vneeded, - double &wr[],double &wi[], - CMatrixDouble &vl,CMatrixDouble &vr) - { -//--- create variables - int i=0; - int i_=0; - int i1_=0; - bool result; -//--- create arrays - double wr1[]; - double wi1[]; -//--- create matrix - CMatrixDouble a1; - CMatrixDouble vl1; - CMatrixDouble vr1; -//--- create copy - CMatrixDouble a; - a=ca; -//--- check - if(!CAp::Assert(vneeded>=0 && vneeded<=3,__FUNCTION__+": incorrect VNeeded!")) - return(false); - a1.Resize(n+1,n+1); - for(i=1;i<=n;i++) - { - i1_=-1; - for(i_=1;i_<=n;i_++) - a1[i].Set(i_,a[i-1][i_+i1_]); - } -//--- get result - result=NonSymmetricEVD(a1,n,vneeded,wr1,wi1,vl1,vr1); -//--- check - if(result) - { - //--- allocation - ArrayResizeAL(wr,n); - ArrayResizeAL(wi,n); - i1_=1; - for(i_=0;i_=0 && zneeded<=3,__FUNCTION__+": Incorrent ZNeeded")) - return(false); -//--- check - if(zneeded<0 || zneeded>3) - return(false); -//--- initialization - result=true; -//--- check - if(n==0) - return(result); -//--- check - if(n==1) - { - //--- check - if(zneeded==2 || zneeded==3) - { - z.Resize(2,2); - z[1].Set(1,1); - } - //--- return result - return(result); - } -//--- initialization - maxit=30; -//--- allocation - ArrayResizeAL(wtemp,n+1); - ArrayResizeAL(work1,n); - ArrayResizeAL(work2,n); - ArrayResizeAL(workc,n+1); - ArrayResizeAL(works,n+1); -//--- Determine the unit roundoff and over/underflow thresholds. - eps=CMath::m_machineepsilon; - eps2=CMath::Sqr(eps); - safmin=CMath::m_minrealnumber; - safmax=CMath::m_maxrealnumber; - ssfmax=MathSqrt(safmax)/3; - ssfmin=MathSqrt(safmin)/eps2; -//--- Here we are using transposition to get rid of column operations - wastranspose=false; - zrows=0; -//--- check - if(zneeded==1) - zrows=n; -//--- check - if(zneeded==2) - zrows=n; -//--- check - if(zneeded==3) - zrows=1; -//--- check - if(zneeded==1) - { - wastranspose=true; - //--- function call - CBlas::InplaceTranspose(z,1,n,1,n,wtemp); - } -//--- check - if(zneeded==2) - { - wastranspose=true; - z.Resize(n+1,n+1); - for(i=1;i<=n;i++) - { - for(j=1;j<=n;j++) - { - //--- check - if(i==j) - z[i].Set(j,1); - else - z[i].Set(j,0); - } - } - } -//--- check - if(zneeded==3) - { - wastranspose=false; - z.Resize(2,n+1); - for(j=1;j<=n;j++) - { - //--- check - if(j==1) - z[1].Set(j,1); - else - z[1].Set(j,0); - } - } -//--- initialization - nmaxit=n*maxit; - jtot=0; -//--- Determine where the matrix splits and choose QL or QR iteration -//--- for each block, according to whether top or bottom diagonal -//--- element is smaller. - l1=1; - nm1=n-1; - while(true) - { - //--- check - if(l1>n) - break; - //--- check - if(l1>1) - e[l1-1]=0; - gotoflag=false; - m=l1; - //--- check - if(l1<=nm1) - { - for(m=l1;m<=nm1;m++) - { - tst=MathAbs(e[m]); - //--- check - if(tst==0.0) - { - gotoflag=true; - //--- break the cycle - break; - } - //--- check - if(tst<=MathSqrt(MathAbs(d[m]))*MathSqrt(MathAbs(d[m+1]))*eps) - { - e[m]=0; - gotoflag=true; - //--- break the cycle - break; - } - } - } - //--- check - if(!gotoflag) - m=n; - //--- change values - l=l1; - lsv=l; - lend=m; - lendsv=lend; - l1=m+1; - //--- check - if(lend==l) - continue; - //--- Scale submatrix in rows and columns L to LEND - if(l==lend) - anorm=MathAbs(d[l]); - else - { - anorm=MathMax(MathAbs(d[l])+MathAbs(e[l]),MathAbs(e[lend-1])+MathAbs(d[lend])); - for(i=l+1;i<=lend-1;i++) - anorm=MathMax(anorm,MathAbs(d[i])+MathAbs(e[i])+MathAbs(e[i-1])); - } - iscale=0; - //--- check - if(anorm==0.0) - continue; - //--- check - if(anorm>(double)(ssfmax)) - { - iscale=1; - tmp=ssfmax/anorm; - tmpint=lend-1; - for(i_=l;i_<=lend;i_++) - d[i_]=tmp*d[i_]; - for(i_=l;i_<=tmpint;i_++) - e[i_]=tmp*e[i_]; - } - //--- check - if(anorml) - { - //--- QL Iteration - //--- Look for small subdiagonal element. - while(true) - { - gotoflag=false; - //--- check - if(l!=lend) - { - lendm1=lend-1; - for(m=l;m<=lendm1;m++) - { - tst=CMath::Sqr(MathAbs(e[m])); - //--- check - if(tst<=eps2*MathAbs(d[m])*MathAbs(d[m+1])+safmin) - { - gotoflag=true; - //--- break the cycle - break; - } - } - } - //--- check - if(!gotoflag) - m=lend; - //--- check - if(m0) - { - //--- function call - TdEVDEv2(d[l],e[l],d[l+1],rt1,rt2,c,s); - //--- change values - work1[l]=c; - work2[l]=s; - workc[1]=work1[l]; - works[1]=work2[l]; - //--- check - if(!wastranspose) - CRotations::ApplyRotationsFromTheRight(false,1,zrows,l,l+1,workc,works,z,wtemp); - else - CRotations::ApplyRotationsFromTheLeft(false,l,l+1,1,zrows,workc,works,z,wtemp); - } - else - //--- function call - TdEVDE2(d[l],e[l],d[l+1],rt1,rt2); - //--- change values - d[l]=rt1; - d[l+1]=rt2; - e[l]=0; - l=l+2; - //--- check - if(l<=lend) - continue; - //--- break the cycle - break; - } - //--- check - if(jtot==nmaxit) - break; - jtot=jtot+1; - //--- Form shift. - g=(d[l+1]-p)/(2*e[l]); - //--- function call - r=TdEVDPythag(g,1); - g=d[m]-p+e[l]/(g+TdEVDExtSign(r,g)); - s=1; - c=1; - p=0; - //--- Inner loop - mm1=m-1; - for(i=mm1;i>=l;i--) - { - f=s*e[i]; - b=c*e[i]; - //--- function call - CRotations::GenerateRotation(g,f,c,s,r); - //--- check - if(i!=m-1) - e[i+1]=r; - g=d[i+1]-p; - r=(d[i]-g)*s+2*c*b; - p=s*r; - d[i+1]=g+p; - g=c*r-b; - //--- If eigenvectors are desired, then save rotations. - if(zneeded>0) - { - work1[i]=c; - work2[i]=-s; - } - } - //--- If eigenvectors are desired, then apply saved rotations. - if(zneeded>0) - { - for(i=l;i=lendp1;m--) - { - tst=CMath::Sqr(MathAbs(e[m-1])); - //--- check - if(tst<=(double)(eps2*MathAbs(d[m])*MathAbs(d[m-1])+safmin)) - { - gotoflag=true; - //--- break the cycle - break; - } - } - } - //--- check - if(!gotoflag) - m=lend; - //--- check - if(m>lend) - e[m-1]=0; - p=d[l]; - //--- check - if(m!=l) - { - //--- If remaining matrix is 2-by-2, use DLAE2 or SLAEV2 - //--- to compute its eigensystem. - if(m==l-1) - { - //--- check - if(zneeded>0) - { - //--- function call - TdEVDEv2(d[l-1],e[l-1],d[l],rt1,rt2,c,s); - work1[m]=c; - work2[m]=s; - workc[1]=c; - works[1]=s; - //--- check - if(!wastranspose) - { - //--- function call - CRotations::ApplyRotationsFromTheRight(true,1,zrows,l-1,l,workc,works,z,wtemp); - } - else - { - //--- function call - CRotations::ApplyRotationsFromTheLeft(true,l-1,l,1,zrows,workc,works,z,wtemp); - } - } - else - { - //--- function call - TdEVDE2(d[l-1],e[l-1],d[l],rt1,rt2); - } - d[l-1]=rt1; - d[l]=rt2; - e[l-1]=0; - l=l-2; - //--- check - if(l>=lend) - continue; - //--- break the cycle - break; - } - //--- check - if(jtot==nmaxit) - break; - jtot=jtot+1; - //--- Form shift. - g=(d[l-1]-p)/(2*e[l-1]); - //--- function call - r=TdEVDPythag(g,1); - g=d[m]-p+e[l-1]/(g+TdEVDExtSign(r,g)); - s=1; - c=1; - p=0; - //--- Inner loop - lm1=l-1; - for(i=m;i<=lm1;i++) - { - f=s*e[i]; - b=c*e[i]; - //--- function call - CRotations::GenerateRotation(g,f,c,s,r); - //--- check - if(i!=m) - e[i-1]=r; - //--- change values - g=d[i]-p; - r=(d[i+1]-g)*s+2*c*b; - p=s*r; - d[i]=g+p; - g=c*r-b; - //--- If eigenvectors are desired, then save rotations. - if(zneeded>0) - { - work1[i]=c; - work2[i]=s; - } - } - //--- If eigenvectors are desired, then apply saved rotations. - if(zneeded>0) - { - mm=l-m+1; - for(i=m;i<=l-1;i++) - { - workc[i-m+1]=work1[i]; - works[i-m+1]=work2[i]; - } - //--- check - if(!wastranspose) - { - //--- function call - CRotations::ApplyRotationsFromTheRight(true,1,zrows,m,l,workc,works,z,wtemp); - } - else - { - //--- function call - CRotations::ApplyRotationsFromTheLeft(true,m,l,1,zrows,workc,works,z,wtemp); - } - } - d[l]=d[l]-p; - e[lm1]=g; - continue; - } - //--- Eigenvalue found. - d[l]=p; - l=l-1; - //--- check - if(l>=lend) - continue; - //--- break the cycle - break; - } - } - //--- Undo scaling if necessary - if(iscale==1) - { - tmp=anorm/ssfmax; - tmpint=lendsv-1; - for(i_=lsv;i_<=lendsv;i_++) - d[i_]=tmp*d[i_]; - for(i_=lsv;i_<=tmpint;i_++) - e[i_]=tmp*e[i_]; - } - //--- check - if(iscale==2) - { - tmp=anorm/ssfmin; - tmpint=lendsv-1; - for(i_=lsv;i_<=lendsv;i_++) - d[i_]=tmp*d[i_]; - for(i_=lsv;i_<=tmpint;i_++) - e[i_]=tmp*e[i_]; - } - //--- Check for no convergence to an eigenvalue after a total - //--- of N*MAXIT iterations. - if(jtot>=nmaxit) - { - result=false; - //--- check - if(wastranspose) - { - //--- function call - CBlas::InplaceTranspose(z,1,n,1,n,wtemp); - } - //--- return result - return(result); - } - } -//--- Order eigenvalues and eigenvectors. - if(zneeded==0) - { - //--- Sort - if(n==1) - return(result); - //--- check - if(n==2) - { - //--- check - if(d[1]>d[2]) - { - tmp=d[1]; - d[1]=d[2]; - d[2]=tmp; - } - //--- return result - return(result); - } - i=2; - do - { - t=i; - while(t!=1) - { - k=t/2; - //--- check - if(d[k]>=d[t]) - t=1; - else - { - //--- change values - tmp=d[k]; - d[k]=d[t]; - d[t]=tmp; - t=k; - } - } - i=i+1; - } - //--- cycle - while(i<=n); - i=n-1; - do - { - tmp=d[i+1]; - d[i+1]=d[1]; - d[1]=tmp; - t=1; - while(t!=0) - { - k=2*t; - //--- check - if(k>i) - t=0; - else - { - //--- check - if(kd[k]) - k=k+1; - } - //--- check - if(d[t]>=d[k]) - t=0; - else - { - //--- change values - tmp=d[k]; - d[k]=d[t]; - d[t]=tmp; - t=k; - } - } - } - i=i-1; - } - while(i>=1); - } - else - { - //--- Use Selection Sort to minimize swaps of eigenvectors - for(ii=2;ii<=n;ii++) - { - i=ii-1; - k=i; - p=d[i]; - for(j=ii;j<=n;j++) - { - //--- check - if(d[j]MathAbs(c)) - { - acmx=a; - acmn=c; - } - else - { - acmx=c; - acmn=a; - } -//--- check - if(adf>ab) - { - rt=adf*MathSqrt(1+CMath::Sqr(ab/adf)); - } - else - { - //--- check - if(adf0.0) - { - rt1=0.5*(sm+rt); - //--- Order of execution important. - //--- To get fully accurate smaller eigenvalue, - //--- next line needs to be executed in higher precision. - rt2=acmx/rt1*acmn-b/rt1*b; - } - else - { - //--- Includes case RT1 = RT2 = 0 - rt1=0.5*rt; - rt2=-(0.5*rt); - } - } - } -//+------------------------------------------------------------------+ -//| DLAEV2 computes the eigendecomposition of a 2-by-2 symmetric | -//| matrix | -//| [ A B ] | -//| [ B C ]. | -//| On return, RT1 is the eigenvalue of larger absolute value, RT2 is| -//| the eigenvalue of smaller absolute value, and (CS1,SN1) is the | -//| unit right eigenvector for RT1, giving the decomposition | -//| [ CS1 SN1 ] [ A B ] [ CS1 -SN1 ] = [ RT1 0 ] | -//| [-SN1 CS1 ] [ B C ] [ SN1 CS1 ] [ 0 RT2 ]. | -//| -- LAPACK auxiliary routine (version 3.0) -- | -//| Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., | -//| Courant Institute, Argonne National Lab, and Rice University| -//| October 31, 1992 | -//+------------------------------------------------------------------+ -static void CEigenVDetect::TdEVDEv2(const double a,const double b,const double c, - double &rt1,double &rt2,double &cs1,double &sn1) - { -//--- create variables - int sgn1=0; - int sgn2=0; - double ab=0; - double acmn=0; - double acmx=0; - double acs=0; - double adf=0; - double cs=0; - double ct=0; - double df=0; - double rt=0; - double sm=0; - double tb=0; - double tn=0; -//--- initialization - rt1=0; - rt2=0; - cs1=0; - sn1=0; -//--- Compute the eigenvalues - sm=a+c; - df=a-c; - adf=MathAbs(df); - tb=b+b; - ab=MathAbs(tb); -//--- check - if(MathAbs(a)>MathAbs(c)) - { - acmx=a; - acmn=c; - } - else - { - acmx=c; - acmn=a; - } -//--- check - if(adf>ab) - rt=adf*MathSqrt(1+CMath::Sqr(ab/adf)); - else - { - //--- check - if(adf0.0) - { - rt1=0.5*(sm+rt); - sgn1=1; - //--- Order of execution important. - //--- To get fully accurate smaller eigenvalue, - //--- next line needs to be executed in higher precision. - rt2=acmx/rt1*acmn-b/rt1*b; - } - else - { - //--- Includes case RT1 = RT2 = 0 - rt1=0.5*rt; - rt2=-(0.5*rt); - sgn1=1; - } - } -//--- Compute the eigenvector - if(df>=0.0) - { - cs=df+rt; - sgn2=1; - } - else - { - cs=df-rt; - sgn2=-1; - } - acs=MathAbs(cs); -//--- check - if(acs>ab) - { - ct=-(tb/cs); - sn1=1/MathSqrt(1+ct*ct); - cs1=ct*sn1; - } - else - { - //--- check - if(ab==0.0) - { - cs1=1; - sn1=0; - } - else - { - tn=-(cs/tb); - cs1=1/MathSqrt(1+tn*tn); - sn1=tn*cs1; - } - } -//--- check - if(sgn1==sgn2) - { - tn=cs1; - cs1=-sn1; - sn1=tn; - } - } -//+------------------------------------------------------------------+ -//| Internal routine | -//+------------------------------------------------------------------+ -static double CEigenVDetect::TdEVDPythag(const double a,const double b) - { -//--- create variables - double result=0; -//--- check - if(MathAbs(a)=0.0) - result=MathAbs(a); - else - result=-MathAbs(a); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static bool CEigenVDetect::InternalBisectionEigenValues(double &cd[],double &ce[], - const int n,int irange, - const int iorder,const double vl, - const double vu,const int il, - const int iu,const double abstol, - double &w[],int &m, - int &nsplit,int &iblock[], - int &isplit[],int &errorcode) - { -//--- create variables - bool result; - double fudge=0; - double relfac=0; - bool ncnvrg; - bool toofew; - int ib=0; - int ibegin=0; - int idiscl=0; - int idiscu=0; - int ie=0; - int iend=0; - int iinfo=0; - int im=0; - int iin=0; - int ioff=0; - int iout=0; - int itmax=0; - int iw=0; - int iwoff=0; - int j=0; - int itmp1=0; - int jb=0; - int jdisc=0; - int je=0; - int nwl=0; - int nwu=0; - int tmpi=0; - double atoli=0; - double bnorm=0; - double gl=0; - double gu=0; - double pivmin=0; - double rtoli=0; - double safemn=0; - double tmp1=0; - double tmp2=0; - double tnorm=0; - double ulp=0; - double wkill=0; - double wl=0; - double wlu=0; - double wu=0; - double wul=0; - double scalefactor=0; - double t=0; -//--- create arrays - int idumma[]; - double work[]; - int iwork[]; - int ia1s2[]; - double ra1s2[]; - double ra1siin[]; - double ra2siin[]; - double ra3siin[]; - double ra4siin[]; - int iworkspace[]; - double rworkspace[]; -//--- create matrix - CMatrixDouble ra1s2x2; - CMatrixInt ia1s2x2; - CMatrixDouble ra1siinx2; - CMatrixInt ia1siinx2; -//--- create copy - double d[]; - ArrayResizeAL(d,ArraySize(cd)); - ArrayCopy(d,cd); -//--- create copy - double e[]; - ArrayResizeAL(e,ArraySize(ce)); - ArrayCopy(e,ce); -//--- initialization - m=0; - nsplit=0; - errorcode=0; -//--- check - if(n==0) - return(true); -//--- Get machine constants -//--- NB is the minimum vector length for vector bisection, or 0 -//--- if only scalar is to be done. - fudge=2; - relfac=2; - safemn=CMath::m_minrealnumber; - ulp=2*CMath::m_machineepsilon; - rtoli=ulp*relfac; -//--- allocation - ArrayResizeAL(idumma,2); - ArrayResizeAL(work,4*n+1); - ArrayResizeAL(iwork,3*n+1); - ArrayResizeAL(w,n+1); - ArrayResizeAL(iblock,n+1); - ArrayResizeAL(isplit,n+1); - ArrayResizeAL(ia1s2,3); - ArrayResizeAL(ra1s2,3); - ArrayResizeAL(ra1siin,n+1); - ArrayResizeAL(ra2siin,n+1); - ArrayResizeAL(ra3siin,n+1); - ArrayResizeAL(ra4siin,n+1); - ArrayResizeAL(iworkspace,n+1); - ArrayResizeAL(rworkspace,n+1); - ra1siinx2.Resize(n+1,3); - ia1siinx2.Resize(n+1,3); - ra1s2x2.Resize(3,3); - ia1s2x2.Resize(3,3); -//--- initialization - wlu=0; - wul=0; -//--- Check for Errors - result=false; - errorcode=0; -//--- check - if(irange<=0 || irange>=4) - errorcode=-4; -//--- check - if(iorder<=0 || iorder>=3) - errorcode=-5; -//--- check - if(n<0) - errorcode=-3; -//--- check - if(irange==2 && vl>=vu) - errorcode=-6; -//--- check - if(irange==3 && (il<1 || il>MathMax(1,n))) - errorcode=-8; -//--- check - if(irange==3 && (iun)) - errorcode=-9; -//--- check - if(errorcode!=0) - return(result); -//--- Initialize error flags - ncnvrg=false; - toofew=false; -//--- Simplifications: - if(irange==3 && il==1 && iu==n) - irange=1; -//--- Special Case when N=1 - if(n==1) - { - nsplit=1; - isplit[1]=1; - //--- check - if((irange==2 && vl>=d[1]) || vuMathSqrt(MathSqrt(CMath::m_minrealnumber))*MathSqrt(CMath::m_maxrealnumber)) - scalefactor=t; - //--- check - if(ttmp1) - { - isplit[nsplit]=j-1; - nsplit=nsplit+1; - work[j-1]=0; - } - else - { - work[j-1]=tmp1; - pivmin=MathMax(pivmin,tmp1); - } - } - isplit[nsplit]=n; - pivmin=pivmin*safemn; -//--- Compute Interval and ATOLI - if(irange==3) - { - //--- RANGE='I': Compute the interval containing eigenvalues - //--- IL through IU. - //--- Compute Gershgorin interval for entire (split) matrix - //--- and use it as the initial interval - gu=d[1]; - gl=d[1]; - tmp1=0; - for(j=1;j=n || nwu<1 || nwu>n) - { - errorcode=4; - return(false); - } - } - else - { - //--- RANGE='A' or 'V' -- Set ATOLI - tnorm=MathMax(MathAbs(d[1])+MathAbs(e[1]),MathAbs(d[n])+MathAbs(e[n-1])); - for(j=2;j=d[ibegin]-pivmin) - nwl=nwl+1; - //--- check - if(irange==1 || wu>=d[ibegin]-pivmin) - nwu=nwu+1; - //--- check - if((irange==1 || wl=d[ibegin]-pivmin) - { - m=m+1; - w[m]=d[ibegin]; - iblock[m]=jb; - } - } - else - { - //--- General Case -- IIN > 1 - //--- Compute Gershgorin Interval - //--- and use it as the initial interval - gu=d[ibegin]; - gl=d[ibegin]; - tmp1=0; - for(j=ibegin;j<=iend-1;j++) - { - //--- change values - tmp2=MathAbs(e[j]); - gu=MathMax(gu,d[j]+tmp1+tmp2); - gl=MathMin(gl,d[j]-tmp1-tmp2); - tmp1=tmp2; - } - //--- change values - gu=MathMax(gu,d[iend]+tmp1); - gl=MathMin(gl,d[iend]-tmp1); - bnorm=MathMax(MathAbs(gl),MathAbs(gu)); - gl=gl-fudge*bnorm*ulp*iin-fudge*pivmin; - gu=gu+fudge*bnorm*ulp*iin+fudge*pivmin; - //--- Compute ATOLI for the current submatrix - if(abstol<=0.0) - atoli=ulp*MathMax(MathAbs(gl),MathAbs(gu)); - else - atoli=abstol; - //--- check - if(irange>1) - { - //--- check - if(gu=gu) - continue; - } - //--- Set Up Initial Interval - work[n+1]=gl; - work[n+iin+1]=gu; - //--- Calling DLAEBZ - //--- CALL DLAEBZ( 1, 0, IN, IN, 1, NB, ATOLI, RTOLI, PIVMIN, - //--- D( IBEGIN ), E( IBEGIN ), WORK( IBEGIN ), - //--- IDUMMA, WORK( N+1 ), WORK( N+2*IN+1 ), IM, - //--- IWORK, W( M+1 ), IBLOCK( M+1 ), IINFO ) - for(tmpi=1;tmpi<=iin;tmpi++) - { - ra1siin[tmpi]=d[ibegin-1+tmpi]; - //--- check - if(ibegin-1+tmpiiout-iinfo) - { - ncnvrg=true; - ib=-jb; - } - else - ib=jb; - for(je=iwork[j]+1+iwoff;je<=iwork[j+iin]+iwoff;je++) - { - w[je]=tmp1; - iblock[je]=ib; - } - } - m=m+im; - } - } -//--- If RANGE='I', then (WL,WU) contains eigenvalues NWL+1,...,NWU -//--- If NWL+1 < IL or NWU > IU, discard extra eigenvalues. - if(irange==3) - { - im=0; - idiscl=il-1-nwl; - idiscu=nwu-iu; - //--- check - if(idiscl>0 || idiscu>0) - { - for(je=1;je<=m;je++) - { - //--- check - if(w[je]<=wlu && idiscl>0) - { - idiscl=idiscl-1; - } - else - { - //--- check - if(w[je]>=wul && idiscu>0) - idiscu=idiscu-1; - else - { - im=im+1; - w[im]=w[je]; - iblock[im]=iblock[je]; - } - } - } - m=im; - } - //--- check - if(idiscl>0 || idiscu>0) - { - //--- Code to deal with effects of bad arithmetic: - //--- Some low eigenvalues to be discarded are not in (WL,WLU], - //--- or high eigenvalues to be discarded are not in (WUL,WU] - //--- so just kill off the smallest IDISCL/largest IDISCU - //--- eigenvalues, by simply finding the smallest/largest - //--- eigenvalue(s). - //--- (If N(w) is monotone non-decreasing, this should never - //--- happen.) - if(idiscl>0) - { - wkill=wu; - for(jdisc=1;jdisc<=idiscl;jdisc++) - { - iw=0; - for(je=1;je<=m;je++) - { - //--- check - if(iblock[je]!=0 && (w[je]<(double)(wkill) || iw==0)) - { - iw=je; - wkill=w[je]; - } - } - iblock[iw]=0; - } - } - //--- check - if(idiscu>0) - { - wkill=wl; - for(jdisc=1;jdisc<=idiscu;jdisc++) - { - iw=0; - for(je=1;je<=m;je++) - { - //--- check - if(iblock[je]!=0 && (w[je]>(double)(wkill) || iw==0)) - { - iw=je; - wkill=w[je]; - } - } - iblock[iw]=0; - } - } - im=0; - for(je=1;je<=m;je++) - { - //--- check - if(iblock[je]!=0) - { - im=im+1; - w[im]=w[je]; - iblock[im]=iblock[je]; - } - } - m=im; - } - //--- check - if(idiscl<0 || idiscu<0) - toofew=true; - } -//--- If ORDER='B', do nothing -- the eigenvalues are already sorted -//--- by block. -//--- If ORDER='E', sort the eigenvalues from smallest to largest - if(iorder==1 && nsplit>1) - { - for(je=1;je<=m-1;je++) - { - ie=0; - tmp1=w[je]; - for(j=je+1;j<=m;j++) - { - //--- check - if(w[j]n) - { - info=-4; - return; - } - for(j=2;j<=m;j++) - { - //--- check - if(iblock[j]1) - { - eps1=MathAbs(eps*xj); - pertol=10*eps1; - sep=xj-xjm; - //--- check - if(sepmaxits) - { - //--- If stopping criterion was not satisfied, update info and - //--- store eigenvector number in array ifail. - info=info+1; - ifail[info]=j; - break; - } - //--- Normalize and scale the righthand side vector Pb. - v=0; - for(ti=1;ti<=blksiz;ti++) - v=v+MathAbs(work1[ti]); - scl=blksiz*onenrm*MathMax(eps,MathAbs(work4[blksiz]))/v; - for(i_=1;i_<=blksiz;i_++) - work1[i_]=scl*work1[i_]; - //--- Solve the system LU = Pb. - TdIninternalDLAGTS(blksiz,work4,work2,work3,work5,iwork,work1,tol,iinfo); - //--- Reorthogonalize by modified Gram-Schmidt if eigenvalues are - //--- close enough. - if(jblk!=1) - { - //--- check - if(MathAbs(xj-xjm)>ortol) - gpind=j; - //--- check - if(gpind!=j) - { - for(i=gpind;i1) - tol=MathMax(tol,MathMax(MathAbs(a[2]),MathAbs(b[1]))); - for(k=3;k<=n;k++) - tol=MathMax(tol,MathMax(MathAbs(a[k]),MathMax(MathAbs(b[k-1]),MathAbs(d[k-2])))); - tol=tol*eps; - //--- check - if(tol==0.0) - tol=eps; - } - for(k=2;k<=n;k++) - { - //--- check - if(iin[k-1]==0) - y[k]=y[k]-c[k-1]*y[k-1]; - else - { - temp=y[k-1]; - y[k-1]=y[k]; - y[k]=temp-c[k-1]*y[k]; - } - } - for(k=n;k>=1;k--) - { - //--- check - if(k<=n-2) - temp=y[k]-b[k]*y[k+1]-d[k]*y[k+2]; - else - { - //--- check - if(k==n-1) - temp=y[k]-b[k]*y[k+1]; - else - temp=y[k]; - } - ak=a[k]; - pert=MathAbs(tol); - //--- check - if(ak<0.0) - pert=-pert; - while(true) - { - absak=MathAbs(ak); - //--- check - if(absak<1.0) - { - //--- check - if(absakabsak) - { - ak=ak+pert; - pert=2*pert; - continue; - } - else - { - temp=temp*bignum; - ak=ak*bignum; - } - } - else - { - //--- check - if(MathAbs(temp)>absak*bignum) - { - ak=ak+pert; - pert=2*pert; - continue; - } - } - } - //--- break the cycle - break; - } - y[k]=temp/ak; - } - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static void CEigenVDetect::InternalDLAEBZ(const int ijob,const int nitmax, - const int n,const int mmax,const int minp, - const double abstol,const double reltol, - const double pivmin,double &d[], - double &e[],double &e2[],int &nval[], - CMatrixDouble &ab,double &c[],int &mout, - CMatrixInt &nab,double &work[], - int &iwork[],int &info) - { -//--- create variables - int itmp1=0; - int itmp2=0; - int j=0; - int ji=0; - int jit=0; - int jp=0; - int kf=0; - int kfnew=0; - int kl=0; - int klnew=0; - double tmp1=0; - double tmp2=0; -//--- initialization - mout=0; - info=0; -//--- check - if(ijob<1 || ijob>3) - { - info=-1; - //--- exit the function - return; - } -//--- Initialize NAB - if(ijob==1) - { - //--- Compute the number of eigenvalues in the initial intervals. - mout=0; - //--- DIR$ NOVECTOR - for(ji=1;ji<=minp;ji++) - { - for(jp=1;jp<=2;jp++) - { - tmp1=d[1]-ab[ji][jp]; - //--- check - if(MathAbs(tmp1)=nval[ji]) - { - ab[ji].Set(2,tmp1); - nab[ji].Set(2,itmp1); - } - } - } - kl=klnew; - //--- Check for convergence - kfnew=kf; - for(ji=kf;ji<=kl;ji++) - { - tmp1=MathAbs(ab[ji][2]-ab[ji][1]); - tmp2=MathMax(MathAbs(ab[ji][2]),MathAbs(ab[ji][1])); - //--- check - if(tmp1<(double)(MathMax(abstol,MathMax(pivmin,reltol*tmp2))) || nab[ji][1]>=nab[ji][2]) - { - //--- Converged -- Swap with position KFNEW, - //--- then increment KFNEW - if(ji>kfnew) - { - tmp1=ab[ji][1]; - tmp2=ab[ji][2]; - itmp1=nab[ji][1]; - itmp2=nab[ji][2]; - //--- change values - ab[ji].Set(1,ab[kfnew][1]); - ab[ji].Set(2,ab[kfnew][2]); - nab[ji].Set(1,nab[kfnew][1]); - nab[ji].Set(2,nab[kfnew][2]); - ab[kfnew].Set(1,tmp1); - ab[kfnew].Set(2,tmp2); - nab[kfnew].Set(1,itmp1); - nab[kfnew].Set(2,itmp2); - //--- check - if(ijob==3) - { - itmp1=nval[ji]; - nval[ji]=nval[kfnew]; - nval[kfnew]=itmp1; - } - } - kfnew=kfnew+1; - } - } - kf=kfnew; - //--- Choose Midpoints - for(ji=kf;ji<=kl;ji++) - c[ji]=0.5*(ab[ji][1]+ab[ji][2]); - //--- If no more intervals to refine, quit. - if(kf>kl) - break; - } -//--- Converged - info=(int)MathMax(kl+1-kf,0); - mout=kl; - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//| -- LAPACK routine (version 3.0) -- | -//| Univ. of Tennessee,Univ. of California Berkeley,NAG Ltd., | -//| Courant Institute,Argonne National Lab, and Rice University | -//| June 30,1999 | -//+------------------------------------------------------------------+ -static void CEigenVDetect::InternalTREVC(CMatrixDouble &t,const int n,const int side, - const int howmny,bool &cvselect[],CMatrixDouble &vl, - CMatrixDouble &vr,int &m,int &info) - { -//--- create variables - bool allv; - bool bothv; - bool leftv; - bool over; - bool pair; - bool rightv; - bool somev; - int i=0; - int ierr=0; - int ii=0; - int ip=0; - int iis=0; - int j=0; - int j1=0; - int j2=0; - int jnxt=0; - int k=0; - int ki=0; - int n2=0; - double beta=0; - double bignum=0; - double emax=0; - double ovfl=0; - double rec=0; - double remax=0; - double scl=0; - double smin=0; - double smlnum=0; - double ulp=0; - double unfl=0; - double vcrit=0; - double vmax=0; - double wi=0; - double wr=0; - double xnorm=0; - bool skipflag; - int k1=0; - int k2=0; - int k3=0; - int k4=0; - double vt=0; - int i_=0; - int i1_=0; -//--- create arrays - double work[]; - double temp[]; - bool rswap4[]; - bool zswap4[]; - double civ4[]; - double crv4[]; -//--- create matrix - CMatrixDouble x; - CMatrixDouble temp11; - CMatrixDouble temp22; - CMatrixDouble temp11b; - CMatrixDouble temp21b; - CMatrixDouble temp12b; - CMatrixDouble temp22b; - CMatrixInt ipivot44; -//--- create copy - bool vselect[]; - ArrayResizeAL(vselect,ArraySize(cvselect)); - ArrayCopy(vselect,cvselect); -//--- initialization - m=0; - info=0; -//--- allocation - x.Resize(3,3); - temp11.Resize(2,2); - temp11b.Resize(2,2); - temp21b.Resize(3,2); - temp12b.Resize(2,3); - temp22b.Resize(3,3); - temp22.Resize(3,3); - ArrayResizeAL(work,3*n+1); - ArrayResizeAL(temp,n+1); - ArrayResizeAL(rswap4,5); - ArrayResizeAL(zswap4,5); - ArrayResizeAL(civ4,5); - ArrayResizeAL(crv4,5); - ipivot44.Resize(5,5); -//--- check - if(howmny!=1) - { - //--- check - if(side==1 || side==3) - vr.Resize(n+1,n+1); - //--- check - if(side==2 || side==3) - vl.Resize(n+1,n+1); - } -//--- Decode and test the input parameters - bothv=side==3; - rightv=side==1 || bothv; - leftv=side==2 || bothv; - allv=howmny==2; - over=howmny==1; - somev=howmny==3; - info=0; -//--- check - if(n<0) - { - info=-2; - return; - } -//--- check - if(!rightv && !leftv) - { - info=-3; - return; - } -//--- check - if((!allv && !over) && !somev) - { - info=-4; - return; - } -//--- Set M to the number of columns required to store the selected -//--- eigenvectors, standardize the array SELECT if necessary, and -//--- test MM. - if(somev) - { - m=0; - pair=false; - for(j=1;j<=n;j++) - { - //--- check - if(pair) - { - pair=false; - vselect[j]=false; - } - else - { - //--- check - if(j=1;ki--) - { - skipflag=false; - //--- check - if(ip==1) - skipflag=true; - else - { - //--- check - if(ki!=1) - { - //--- check - if(t[ki][ki-1]!=0.0) - ip=-1; - } - //--- check - if(somev) - { - //--- check - if(ip==0) - { - //--- check - if(!vselect[ki]) - skipflag=true; - } - else - { - //--- check - if(!vselect[ki-1]) - skipflag=true; - } - } - } - //--- check - if(!skipflag) - { - //--- Compute the KI-th eigenvalue (WR,WI). - wr=t[ki][ki]; - wi=0; - //--- check - if(ip!=0) - wi=MathSqrt(MathAbs(t[ki][ki-1]))*MathSqrt(MathAbs(t[ki-1][ki])); - smin=MathMax(ulp*(MathAbs(wr)+MathAbs(wi)),smlnum); - //--- check - if(ip==0) - { - //--- Real right eigenvector - work[ki+n]=1; - //--- Form right-hand side - for(k=1;k<=ki-1;k++) - work[k+n]=-t[k][ki]; - //--- Solve the upper quasi-triangular system: - //--- (T(1:KI-1,1:KI-1) - WR)*X = SCALE*WORK. - jnxt=ki-1; - for(j=ki-1;j>=1;j--) - { - //--- check - if(j>jnxt) - continue; - j1=j; - j2=j; - jnxt=j-1; - //--- check - if(j>1) - { - //--- check - if(t[j][j-1]!=0.0) - { - j1=j-1; - jnxt=j-2; - } - } - //--- check - if(j1==j2) - { - //--- 1-by-1 diagonal block - temp11[1].Set(1,t[j][j]); - temp11b[1].Set(1,work[j+n]); - //--- function call - InternalHsEVDLALN2(false,1,1,smin,1,temp11,1.0,1.0,temp11b,wr,0.0,rswap4,zswap4,ipivot44,civ4,crv4,x,scl,xnorm,ierr); - //--- Scale X(1,1) to avoid overflow when updating - //--- the right-hand side. - if(xnorm>1.0) - { - //--- check - if(work[j]>bignum/xnorm) - { - x[1].Set(1,x[1][1]/xnorm); - scl=scl/xnorm; - } - } - //--- Scale if necessary - if(scl!=1.0) - { - k1=n+1; - k2=n+ki; - for(i_=k1;i_<=k2;i_++) - work[i_]=scl*work[i_]; - } - work[j+n]=x[1][1]; - //--- Update right-hand side - k1=1+n; - k2=j-1+n; - k3=j-1; - vt=-x[1][1]; - i1_=1-k1; - for(i_=k1;i_<=k2;i_++) - { - work[i_]=work[i_]+vt*t[i_+i1_][j]; - } - } - else - { - //--- 2-by-2 diagonal block - temp22[1].Set(1,t[j-1][j-1]); - temp22[1].Set(2,t[j-1][j]); - temp22[2].Set(1,t[j][j-1]); - temp22[2].Set(2,t[j][j]); - temp21b[1].Set(1,work[j-1+n]); - temp21b[2].Set(1,work[j+n]); - //--- function call - InternalHsEVDLALN2(false,2,1,smin,1.0,temp22,1.0,1.0,temp21b,wr,0,rswap4,zswap4,ipivot44,civ4,crv4,x,scl,xnorm,ierr); - //--- Scale X(1,1) and X(2,1) to avoid overflow when - //--- updating the right-hand side. - if(xnorm>1.0) - { - beta=MathMax(work[j-1],work[j]); - //--- check - if(beta>bignum/xnorm) - { - x[1].Set(1,x[1][1]/xnorm); - x[2].Set(1,x[2][1]/xnorm); - scl=scl/xnorm; - } - } - //--- Scale if necessary - if(scl!=1.0) - { - k1=1+n; - k2=ki+n; - for(i_=k1;i_<=k2;i_++) - work[i_]=scl*work[i_]; - } - work[j-1+n]=x[1][1]; - work[j+n]=x[2][1]; - //--- Update right-hand side - k1=1+n; - k2=j-2+n; - k3=j-2; - k4=j-1; - vt=-x[1][1]; - i1_=1-k1; - for(i_=k1;i_<=k2;i_++) - work[i_]=work[i_]+vt*t[i_+i1_][k4]; - vt=-x[2][1]; - i1_=1-k1; - for(i_=k1;i_<=k2;i_++) - work[i_]=work[i_]+vt*t[i_+i1_][j]; - } - } - //--- Copy the vector x or Q*x to VR and normalize. - if(!over) - { - k1=1+n; - k2=ki+n; - i1_=k1-1; - for(i_=1;i_<=ki;i_++) - vr[i_].Set(iis,work[i_+i1_]); - //--- function call - ii=CBlas::ColumnIdxAbsMax(vr,1,ki,iis); - remax=1/MathAbs(vr[ii][iis]); - for(i_=1;i_<=ki;i_++) - vr[i_].Set(iis,remax*vr[i_][iis]); - for(k=ki+1;k<=n;k++) - vr[k].Set(iis,0); - } - else - { - //--- check - if(ki>1) - { - for(i_=1;i_<=n;i_++) - temp[i_]=vr[i_][ki]; - //--- function call - CBlas::MatrixVectorMultiply(vr,1,n,1,ki-1,false,work,1+n,ki-1+n,1.0,temp,1,n,work[ki+n]); - for(i_=1;i_<=n;i_++) - vr[i_].Set(ki,temp[i_]); - } - //--- function call - ii=CBlas::ColumnIdxAbsMax(vr,1,n,ki); - remax=1/MathAbs(vr[ii][ki]); - for(i_=1;i_<=n;i_++) - vr[i_].Set(ki,remax*vr[i_][ki]); - } - } - else - { - //--- Complex right eigenvector. - //--- Initial solve - //--- [ (T(KI-1,KI-1) T(KI-1,KI) ) - (WR + I* WI)]*X = 0. - //--- [ (T(KI,KI-1) T(KI,KI) ) ] - if(MathAbs(t[ki-1][ki])>=MathAbs(t[ki][ki-1])) - { - work[ki-1+n]=1; - work[ki+n2]=wi/t[ki-1][ki]; - } - else - { - work[ki-1+n]=-(wi/t[ki][ki-1]); - work[ki+n2]=1; - } - work[ki+n]=0; - work[ki-1+n2]=0; - //--- Form right-hand side - for(k=1;k<=ki-2;k++) - { - work[k+n]=-(work[ki-1+n]*t[k][ki-1]); - work[k+n2]=-(work[ki+n2]*t[k][ki]); - } - //--- Solve upper quasi-triangular system: - //--- (T(1:KI-2,1:KI-2) - (WR+i*WI))*X = SCALE*(WORK+i*WORK2) - jnxt=ki-2; - for(j=ki-2;j>=1;j--) - { - //--- check - if(j>jnxt) - continue; - j1=j; - j2=j; - jnxt=j-1; - //--- check - if(j>1) - { - //--- check - if(t[j][j-1]!=0.0) - { - j1=j-1; - jnxt=j-2; - } - } - //--- check - if(j1==j2) - { - //--- 1-by-1 diagonal block - temp11[1].Set(1,t[j][j]); - temp12b[1].Set(1,work[j+n]); - temp12b[1].Set(2,work[j+n+n]); - //--- function call - InternalHsEVDLALN2(false,1,2,smin,1.0,temp11,1.0,1.0,temp12b,wr,wi,rswap4,zswap4,ipivot44,civ4,crv4,x,scl,xnorm,ierr); - //--- Scale X(1,1) and X(1,2) to avoid overflow when - //--- updating the right-hand side. - if(xnorm>1.0) - { - //--- check - if(work[j]>bignum/xnorm) - { - x[1].Set(1,x[1][1]/xnorm); - x[1].Set(2,x[1][2]/xnorm); - scl=scl/xnorm; - } - } - //--- Scale if necessary - if(scl!=1.0) - { - k1=1+n; - k2=ki+n; - for(i_=k1;i_<=k2;i_++) - work[i_]=scl*work[i_]; - k1=1+n2; - k2=ki+n2; - for(i_=k1;i_<=k2;i_++) - work[i_]=scl*work[i_]; - } - work[j+n]=x[1][1]; - work[j+n2]=x[1][2]; - //--- Update the right-hand side - k1=1+n; - k2=j-1+n; - k3=1; - k4=j-1; - vt=-x[1][1]; - i1_=k3-k1; - for(i_=k1;i_<=k2;i_++) - work[i_]=work[i_]+vt*t[i_+i1_][j]; - //--- change values - k1=1+n2; - k2=j-1+n2; - k3=1; - k4=j-1; - vt=-x[1][2]; - i1_=k3-k1; - for(i_=k1;i_<=k2;i_++) - work[i_]=work[i_]+vt*t[i_+i1_][j]; - } - else - { - //--- 2-by-2 diagonal block - temp22[1].Set(1,t[j-1][j-1]); - temp22[1].Set(2,t[j-1][j]); - temp22[2].Set(1,t[j][j-1]); - temp22[2].Set(2,t[j][j]); - temp22b[1].Set(1,work[j-1+n]); - temp22b[1].Set(2,work[j-1+n+n]); - temp22b[2].Set(1,work[j+n]); - temp22b[2].Set(2,work[j+n+n]); - //--- function call - InternalHsEVDLALN2(false,2,2,smin,1.0,temp22,1.0,1.0,temp22b,wr,wi,rswap4,zswap4,ipivot44,civ4,crv4,x,scl,xnorm,ierr); - //--- Scale X to avoid overflow when updating - //--- the right-hand side. - if(xnorm>1.0) - { - beta=MathMax(work[j-1],work[j]); - //--- check - if(beta>bignum/xnorm) - { - rec=1/xnorm; - x[1].Set(1,x[1][1]*rec); - x[1].Set(2,x[1][2]*rec); - x[2].Set(1,x[2][1]*rec); - x[2].Set(2,x[2][2]*rec); - scl=scl*rec; - } - } - //--- Scale if necessary - if(scl!=1.0) - { - for(i_=1+n;i_<=ki+n;i_++) - work[i_]=scl*work[i_]; - for(i_=1+n2;i_<=ki+n2;i_++) - work[i_]=scl*work[i_]; - } - //--- change values - work[j-1+n]=x[1][1]; - work[j+n]=x[2][1]; - work[j-1+n2]=x[1][2]; - work[j+n2]=x[2][2]; - //--- Update the right-hand side - vt=-x[1][1]; - i1_=-n; - for(i_=n+1;i_<=n+j-2;i_++) - work[i_]=work[i_]+vt*t[i_+i1_][j-1]; - vt=-x[2][1]; - i1_=-n; - for(i_=n+1;i_<=n+j-2;i_++) - work[i_]=work[i_]+vt*t[i_+i1_][j]; - vt=-x[1][2]; - i1_=-n2; - for(i_=n2+1;i_<=n2+j-2;i_++) - work[i_]=work[i_]+vt*t[i_+i1_][j-1]; - vt=-x[2][2]; - i1_=-n2; - for(i_=n2+1;i_<=n2+j-2;i_++) - work[i_]=work[i_]+vt*t[i_+i1_][j]; - } - } - //--- Copy the vector x or Q*x to VR and normalize. - if(!over) - { - i1_=n; - for(i_=1;i_<=ki;i_++) - vr[i_].Set(iis-1,work[i_+i1_]); - i1_=n2; - for(i_=1;i_<=ki;i_++) - vr[i_].Set(iis,work[i_+i1_]); - emax=0; - for(k=1;k<=ki;k++) - emax=MathMax(emax,MathAbs(vr[k][iis-1])+MathAbs(vr[k][iis])); - remax=1/emax; - //--- copy - for(i_=1;i_<=ki;i_++) - vr[i_].Set(iis-1,remax*vr[i_][iis-1]); - for(i_=1;i_<=ki;i_++) - vr[i_].Set(iis,remax*vr[i_][iis]); - for(k=ki+1;k<=n;k++) - vr[k].Set(iis-1,0); - vr[k].Set(iis,0); - } - else - { - //--- check - if(ki>2) - { - for(i_=1;i_<=n;i_++) - temp[i_]=vr[i_][ki-1]; - //--- function call - CBlas::MatrixVectorMultiply(vr,1,n,1,ki-2,false,work,1+n,ki-2+n,1.0,temp,1,n,work[ki-1+n]); - for(i_=1;i_<=n;i_++) - vr[i_].Set(ki-1,temp[i_]); - for(i_=1;i_<=n;i_++) - temp[i_]=vr[i_][ki]; - //--- function call - CBlas::MatrixVectorMultiply(vr,1,n,1,ki-2,false,work,1+n2,ki-2+n2,1.0,temp,1,n,work[ki+n2]); - for(i_=1;i_<=n;i_++) - vr[i_].Set(ki,temp[i_]); - } - else - { - vt=work[ki-1+n]; - //--- copy - for(i_=1;i_<=n;i_++) - vr[i_].Set(ki-1,vt*vr[i_][ki-1]); - vt=work[ki+n2]; - for(i_=1;i_<=n;i_++) - vr[i_].Set(ki,vt*vr[i_][ki]); - } - emax=0; - for(k=1;k<=n;k++) - emax=MathMax(emax,MathAbs(vr[k][ki-1])+MathAbs(vr[k][ki])); - remax=1/emax; - //--- copy - for(i_=1;i_<=n;i_++) - vr[i_].Set(ki-1,remax*vr[i_][ki-1]); - for(i_=1;i_<=n;i_++) - vr[i_].Set(ki,remax*vr[i_][ki]); - } - } - iis=iis-1; - //--- check - if(ip!=0) - iis=iis-1; - } - //--- check - if(ip==1) - ip=0; - //--- check - if(ip==-1) - ip=1; - } - } -//--- check - if(leftv) - { - //--- Compute left eigenvectors. - ip=0; - iis=1; - for(ki=1;ki<=n;ki++) - { - skipflag=false; - //--- check - if(ip==-1) - skipflag=true; - else - { - //--- check - if(ki!=n) - { - //--- check - if(t[ki+1][ki]!=0.0) - ip=1; - } - //--- check - if(somev) - { - //--- check - if(!vselect[ki]) - skipflag=true; - } - } - //--- check - if(!skipflag) - { - //--- Compute the KI-th eigenvalue (WR,WI). - wr=t[ki][ki]; - wi=0; - //--- check - if(ip!=0) - wi=MathSqrt(MathAbs(t[ki][ki+1]))*MathSqrt(MathAbs(t[ki+1][ki])); - smin=MathMax(ulp*(MathAbs(wr)+MathAbs(wi)),smlnum); - //--- check - if(ip==0) - { - //--- Real left eigenvector. - work[ki+n]=1; - //--- Form right-hand side - for(k=ki+1;k<=n;k++) - work[k+n]=-t[ki][k]; - //--- Solve the quasi-triangular system: - //--- (T(KI+1:N,KI+1:N) - WR)'*X = SCALE*WORK - vmax=1; - vcrit=bignum; - jnxt=ki+1; - for(j=ki+1;j<=n;j++) - { - //--- check - if(jvcrit) - { - rec=1/vmax; - for(i_=ki+n;i_<=n+n;i_++) - { - work[i_]=rec*work[i_]; - } - vmax=1; - vcrit=bignum; - } - i1_=n; - vt=0.0; - for(i_=ki+1;i_vcrit) - { - rec=1/vmax; - for(i_=ki+n;i_<=n+n;i_++) - work[i_]=rec*work[i_]; - vmax=1; - vcrit=bignum; - } - i1_=n; - vt=0.0; - for(i_=ki+1;i_=MathAbs(t[ki+1][ki])) - { - work[ki+n]=wi/t[ki][ki+1]; - work[ki+1+n2]=1; - } - else - { - work[ki+n]=1; - work[ki+1+n2]=-(wi/t[ki+1][ki]); - } - work[ki+1+n]=0; - work[ki+n2]=0; - //--- Form right-hand side - for(k=ki+2;k<=n;k++) - { - work[k+n]=-(work[ki+n]*t[ki][k]); - work[k+n2]=-(work[ki+1+n2]*t[ki+1][k]); - } - //--- Solve complex quasi-triangular system: - //--- ( T(KI+2,N:KI+2,N) - (WR-i*WI) )*X = WORK1+i*WORK2 - vmax=1; - vcrit=bignum; - jnxt=ki+2; - for(j=ki+2;j<=n;j++) - { - //--- check - if(jvcrit) - { - rec=1/vmax; - for(i_=ki+n;i_<=n+n;i_++) - work[i_]=rec*work[i_]; - for(i_=ki+n2;i_<=n+n2;i_++) - work[i_]=rec*work[i_]; - vmax=1; - vcrit=bignum; - } - i1_=n; - vt=0.0; - for(i_=ki+2;i_vcrit) - { - rec=1/vmax; - for(i_=ki+n;i_<=n+n;i_++) - work[i_]=rec*work[i_]; - for(i_=ki+n2;i_<=n+n2;i_++) - work[i_]=rec*work[i_]; - vmax=1; - vcrit=bignum; - } - i1_=n; - vt=0.0; - for(i_=ki+2;i_1.0) - { - //--- check - if(bnorm>bignum*cnorm) - scl=1/bnorm; - } - //--- Compute X - x[1].Set(1,b[1][1]*scl/csr); - xnorm=MathAbs(x[1][1]); - } - else - { - //--- Complex 1x1 system (w is complex) - //--- C = ca A - w D - csr=ca*a[1][1]-wr*d1; - csi=-(wi*d1); - cnorm=MathAbs(csr)+MathAbs(csi); - //--- If | C | < SMINI, use C = SMINI - if(cnorm1.0) - { - //--- check - if(bnorm>bignum*cnorm) - scl=1/bnorm; - } - //--- Compute X - InternalHsEVDLADIV(scl*b[1][1],scl*b[1][2],csr,csi,tmp1,tmp2); - x[1].Set(1,tmp1); - x[1].Set(2,tmp2); - xnorm=MathAbs(x[1][1])+MathAbs(x[1][2]); - } - } - else - { - //--- 2x2 System - //--- Compute the real part of C = ca A - w D (or ca A' - w D ) - crv4[1+0]=ca*a[1][1]-wr*d1; - crv4[2+2]=ca*a[2][2]-wr*d2; - //--- check - if(ltrans) - { - crv4[1+2]=ca*a[2][1]; - crv4[2+0]=ca*a[1][2]; - } - else - { - crv4[2+0]=ca*a[2][1]; - crv4[1+2]=ca*a[1][2]; - } - //--- check - if(nw==1) - { - //--- Real 2x2 system (w is real) - //--- Find the largest element in C - cmax=0; - icmax=0; - for(j=1;j<=4;j++) - { - //--- check - if(MathAbs(crv4[j])>cmax) - { - cmax=MathAbs(crv4[j]); - icmax=j; - } - } - //--- If norm(C) < SMINI, use SMINI*identity. - if(cmax1.0) - { - //--- check - if(bnorm>bignum*smini) - scl=1/bnorm; - } - //--- change values - temp=scl/smini; - x[1].Set(1,temp*b[1][1]); - x[2].Set(1,temp*b[2][1]); - xnorm=temp*bnorm; - info=1; - //--- exit the function - return; - } - //--- Gaussian elimination with complete pivoting. - ur11=crv4[icmax]; - cr21=crv4[ipivot44[2][icmax]]; - ur12=crv4[ipivot44[3][icmax]]; - cr22=crv4[ipivot44[4][icmax]]; - ur11r=1/ur11; - lr21=ur11r*cr21; - ur22=cr22-ur12*lr21; - //--- If smaller pivot < SMINI, use SMINI - if(MathAbs(ur22)1.0 && MathAbs(ur22)<1.0) - { - //--- check - if(bbnd>=bignum*MathAbs(ur22)) - scl=1/bbnd; - } - xr2=br2*scl/ur22; - xr1=scl*br1*ur11r-xr2*(ur11r*ur12); - //--- check - if(zswap4[icmax]) - { - x[1].Set(1,xr2); - x[2].Set(1,xr1); - } - else - { - x[1].Set(1,xr1); - x[2].Set(1,xr2); - } - xnorm=MathMax(MathAbs(xr1),MathAbs(xr2)); - //--- Further scaling if norm(A) norm(X) > overflow - if(xnorm>1.0 && cmax>1.0) - { - //--- check - if(xnorm>bignum/cmax) - { - temp=cmax/bignum; - x[1].Set(1,temp*x[1][1]); - x[2].Set(1,temp*x[2][1]); - xnorm=temp*xnorm; - scl=temp*scl; - } - } - } - else - { - //--- Complex 2x2 system (w is complex) - //--- Find the largest element in C - civ4[1+0]=-(wi*d1); - civ4[2+0]=0; - civ4[1+2]=0; - civ4[2+2]=-(wi*d2); - cmax=0; - icmax=0; - for(j=1;j<=4;j++) - { - //--- check - if(MathAbs(crv4[j])+MathAbs(civ4[j])>cmax) - { - cmax=MathAbs(crv4[j])+MathAbs(civ4[j]); - icmax=j; - } - } - //--- If norm(C) < SMINI, use SMINI*identity. - if(cmax1.0) - { - //--- check - if(bnorm>bignum*smini) - scl=1/bnorm; - } - //--- change values - temp=scl/smini; - x[1].Set(1,temp*b[1][1]); - x[2].Set(1,temp*b[2][1]); - x[1].Set(2,temp*b[1][2]); - x[2].Set(2,temp*b[2][2]); - xnorm=temp*bnorm; - info=1; - //--- exit the function - return; - } - //--- Gaussian elimination with complete pivoting. - ur11=crv4[icmax]; - ui11=civ4[icmax]; - cr21=crv4[ipivot44[2][icmax]]; - ci21=civ4[ipivot44[2][icmax]]; - ur12=crv4[ipivot44[3][icmax]]; - ui12=civ4[ipivot44[3][icmax]]; - cr22=crv4[ipivot44[4][icmax]]; - ci22=civ4[ipivot44[4][icmax]]; - //--- check - if(icmax==1 || icmax==4) - { - //--- Code when off-diagonals of pivoted C are real - if(MathAbs(ur11)>MathAbs(ui11)) - { - temp=ui11/ur11; - ur11r=1/(ur11*(1+CMath::Sqr(temp))); - ui11r=-(temp*ur11r); - } - else - { - temp=ur11/ui11; - ui11r=-(1/(ui11*(1+CMath::Sqr(temp)))); - ur11r=-(temp*ui11r); - } - //--- change values - lr21=cr21*ur11r; - li21=cr21*ui11r; - ur12s=ur12*ur11r; - ui12s=ur12*ui11r; - ur22=cr22-ur12*lr21; - ui22=ci22-ur12*li21; - } - else - { - //--- Code when diagonals of pivoted C are real - ur11r=1/ur11; - ui11r=0; - lr21=cr21*ur11r; - li21=ci21*ur11r; - ur12s=ur12*ur11r; - ui12s=ui12*ur11r; - ur22=cr22-ur12*lr21+ui12*li21; - ui22=-(ur12*li21)-ui12*lr21; - } - u22abs=MathAbs(ur22)+MathAbs(ui22); - //--- If smaller pivot < SMINI, use SMINI - if(u22abs1.0 && u22abs<1.0) - { - //--- check - if(bbnd>=bignum*u22abs) - { - //--- change values - scl=1/bbnd; - br1=scl*br1; - bi1=scl*bi1; - br2=scl*br2; - bi2=scl*bi2; - } - } - //--- function call - InternalHsEVDLADIV(br2,bi2,ur22,ui22,xr2,xi2); - xr1=ur11r*br1-ui11r*bi1-ur12s*xr2+ui12s*xi2; - xi1=ui11r*br1+ur11r*bi1-ui12s*xr2-ur12s*xi2; - //--- check - if(zswap4[icmax]) - { - x[1].Set(1,xr2); - x[2].Set(1,xr1); - x[1].Set(2,xi2); - x[2].Set(2,xi1); - } - else - { - x[1].Set(1,xr1); - x[2].Set(1,xr2); - x[1].Set(2,xi1); - x[2].Set(2,xi2); - } - xnorm=MathMax(MathAbs(xr1)+MathAbs(xi1),MathAbs(xr2)+MathAbs(xi2)); - //--- Further scaling if norm(A) norm(X) > overflow - if(xnorm>1.0 && cmax>1.0) - { - //--- check - if(xnorm>bignum/cmax) - { - //--- change values - temp=cmax/bignum; - x[1].Set(1,temp*x[1][1]); - x[2].Set(1,temp*x[2][1]); - x[1].Set(2,temp*x[1][2]); - x[2].Set(2,temp*x[2][2]); - xnorm=temp*xnorm; - scl=temp*scl; - } - } - } - } - } -//+------------------------------------------------------------------+ -//| performs complex division in real arithmetic | -//| a + i*b | -//| p + i*q = --------- | -//| c + i*d | -//| The algorithm is due to Robert L. Smith and can be found | -//| in D. Knuth, The art of Computer Programming, Vol.2, p.195 | -//| -- LAPACK auxiliary routine (version 3.0) -- | -//| Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., | -//| Courant Institute, Argonne National Lab, and Rice University| -//| October 31, 1992 | -//+------------------------------------------------------------------+ -static void CEigenVDetect::InternalHsEVDLADIV(const double a,const double b, - const double c,const double d, - double &p,double &q) - { -//--- create variables - double e=0; - double f=0; -//--- initialization - p=0; - q=0; -//--- check - if(MathAbs(d)=0 && vneeded<=3,__FUNCTION__+": incorrect VNeeded!")) - return(false); -//--- check - if(vneeded==0) - { - //--- Eigen values only - ToUpperHessenberg(a,n,tau); - //--- function call - CHsSchur::InternalSchurDecomposition(a,n,0,0,wr,wi,s,info); - //--- get result - result=info==0; - //--- return result - return(result); - } -//--- Eigen values and vectors - ToUpperHessenberg(a,n,tau); -//--- function call - UnpackQFromUpperHessenberg(a,n,tau,s); -//--- function call - CHsSchur::InternalSchurDecomposition(a,n,1,1,wr,wi,s,info); -//--- get result - result=info==0; -//--- check - if(!result) - return(result); -//--- check - if(vneeded==1 || vneeded==3) - { - vr.Resize(n+1,n+1); - for(i=1;i<=n;i++) - { - for(i_=1;i_<=n;i_++) - vr[i].Set(i_,s[i][i_]); - } - } -//--- check - if(vneeded==2 || vneeded==3) - { - vl.Resize(n+1,n+1); - for(i=1;i<=n;i++) - { - for(i_=1;i_<=n;i_++) - vl[i].Set(i_,s[i][i_]); - } - } -//--- function call - InternalTREVC(a,n,vneeded,1,sel,vl,vr,m,info); -//--- get result - result=info==0; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Upper Hessenberg form | -//+------------------------------------------------------------------+ -static void CEigenVDetect::ToUpperHessenberg(CMatrixDouble &a,const int n,double &tau[]) - { -//--- create variables - int i=0; - int ip1=0; - int nmi=0; - double v=0; - int i_=0; - int i1_=0; -//--- create arrays - double t[]; - double work[]; -//--- check - if(!CAp::Assert(n>=0,__FUNCTION__+": incorrect N!")) - return; -//--- check - if(n<=1) - return; -//--- allocation - ArrayResizeAL(tau,n); - ArrayResizeAL(t,n+1); - ArrayResizeAL(work,n+1); -//--- calculations - for(i=1;i=1 | -//| OUTPUT PARAMETERS: | -//| A - orthogonal NxN matrix, array[0..N-1,0..N-1] | -//+------------------------------------------------------------------+ -static void CMatGen::RMatrixRndOrthogonal(const int n,CMatrixDouble &a) - { -//--- create variables - int i=0; - int j=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- allocation - a.Resize(n,n); - for(i=0;i=1&&c>=1.0,__FUNCTION__+": N<1 or C<1!")) - return; -//--- allocation - a.Resize(n,n); -//--- check - if(n==1) - { - a[0].Set(0,2*CMath::RandomInteger(2)-1); - //--- exit the function - return; - } -//--- initialization - l1=0; - l2=MathLog(1/c); - for(i=0;i=1 | -//| OUTPUT PARAMETERS: | -//| A - orthogonal NxN matrix, array[0..N-1,0..N-1] | -//+------------------------------------------------------------------+ -static void CMatGen::CMatrixRndOrthogonal(const int n,CMatrixComplex &a) - { -//--- create variables - int i=0; - int j=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- allocation - a.Resize(n,n); - for(i=0;i=1&&c>=1.0,__FUNCTION__+": N<1 or C<1!")) - return; -//--- allocation - a.Resize(n,n); -//--- check - if(n==1) - { - //--- function call - CHighQualityRand::HQRndRandomize(state); - //--- function call - CHighQualityRand::HQRndUnit2(state,v.re,v.im); - a[0].Set(0,v); - return; - } -//--- initialization - l1=0; - l2=MathLog(1/c); - for(i=0;i=1&&c>=1.0,__FUNCTION__+": N<1 or C<1!")) - return; -//--- allocation - a.Resize(n,n); -//--- check - if(n==1) - { - a[0].Set(0,2*CMath::RandomInteger(2)-1); - return; - } -//--- Prepare matrix - l1=0; - l2=MathLog(1/c); - for(i=0;i=1&&c>=1.0,__FUNCTION__+": N<1 or C<1!")) - return; -//--- allocation - a.Resize(n,n); -//--- check - if(n==1) - { - a[0].Set(0,2*CMath::RandomInteger(2)-1); - return; - } -//--- Prepare matrix - l1=0; - l2=MathLog(1/c); - for(i=0;i=1 && m>=1,__FUNCTION__+": N<1 or M<1!")) - return; -//--- check - if(n==1) - { - tau=2*CMath::RandomInteger(2)-1; - for(i=0;i=1 && m>=1,__FUNCTION__+": N<1 or M<1!")) - return; -//--- check - if(m==1) - { - tau=2*CMath::RandomInteger(2)-1; - for(j=0;j=1 && m>=1,__FUNCTION__+": N<1 or M<1!")) - return; -//--- check - if(n==1) - { - //--- function call - CHighQualityRand::HQRndRandomize(state); - //--- function call - CHighQualityRand::HQRndUnit2(state,tau.re,tau.im); - for(i=0;i=1 && m>=1,__FUNCTION__+": N<1 or M<1!")) - return; -//--- check - if(m==1) - { - //--- function call - CHighQualityRand::HQRndRandomize(state); - //--- function call - CHighQualityRand::HQRndUnit2(state,tau.re,tau.im); - for(j=0;j>N | -//| * worst case - N>>M, small M, large N, matrix does not fit in CPU| -//| cache | -//| INPUT PARAMETERS: | -//| A - array[0..M-1, 0..N-1]. | -//| M - number of rows in matrix A. | -//| N - number of columns in matrix A. | -//| OUTPUT PARAMETERS: | -//| A - matrices L and U in compact form: | -//| * L is stored under main diagonal | -//| * U is stored on and above main diagonal | -//| Pivots - permutation matrix in compact form. | -//| array[0..Min(M-1,N-1)]. | -//+------------------------------------------------------------------+ -static void CTrFac::RMatrixLU(CMatrixDouble &a,const int m,const int n,int &pivots[]) - { -//--- check - if(!CAp::Assert(m>0,__FUNCTION__+": incorrect M!")) - return; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": incorrect N!")) - return; -//--- function call - RMatrixPLU(a,m,n,pivots); - } -//+------------------------------------------------------------------+ -//| LU decomposition of a general complex matrix with row pivoting | -//| A is represented as A = P*L*U, where: | -//| * L is lower unitriangular matrix | -//| * U is upper triangular matrix | -//| * P = P0*P1*...*PK, K=min(M,N)-1, | -//| Pi - permutation matrix for I and Pivots[I] | -//| This is cache-oblivous implementation of LU decomposition. It is | -//| optimized for square matrices. As for rectangular matrices: | -//| * best case - M>>N | -//| * worst case - N>>M, small M, large N, matrix does not fit in CPU| -//| cache | -//| INPUT PARAMETERS: | -//| A - array[0..M-1, 0..N-1]. | -//| M - number of rows in matrix A. | -//| N - number of columns in matrix A. | -//| OUTPUT PARAMETERS: | -//| A - matrices L and U in compact form: | -//| * L is stored under main diagonal | -//| * U is stored on and above main diagonal | -//| Pivots - permutation matrix in compact form. | -//| array[0..Min(M-1,N-1)]. | -//+------------------------------------------------------------------+ -static void CTrFac::CMatrixLU(CMatrixComplex &a,const int m,const int n,int &pivots[]) - { -//--- check - if(!CAp::Assert(m>0,__FUNCTION__+": incorrect M!")) - return; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": incorrect N!")) - return; -//--- function call - CMatrixPLU(a,m,n,pivots); - } -//+------------------------------------------------------------------+ -//| Cache-oblivious Cholesky decomposition | -//| The algorithm computes Cholesky decomposition of a Hermitian | -//| positive - definite matrix. The result of an algorithm is a | -//| representation of A as A=U'*U or A=L*L' (here X' detones | -//| conj(X^T)). | -//| INPUT PARAMETERS: | -//| A - upper or lower triangle of a factorized matrix. | -//| array with elements [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| IsUpper - if IsUpper=True, then A contains an upper | -//| triangle of a symmetric matrix, otherwise A | -//| contains a lower one. | -//| OUTPUT PARAMETERS: | -//| A - the result of factorization. If IsUpper=True, | -//| then the upper triangle contains matrix U, so | -//| that A = U'*U, and the elements below the main | -//| diagonal are not modified. Similarly, if | -//| IsUpper = False. | -//| RESULT: | -//| If the matrix is positive-definite, the function returns | -//| True. Otherwise, the function returns False. Contents of A is| -//| not determined in such case. | -//+------------------------------------------------------------------+ -static bool CTrFac::HPDMatrixCholesky(CMatrixComplex &a,const int n,const bool isupper) - { -//--- create array - al_complex tmp[]; -//--- check - if(n<1) - return(false); -//--- return result - return(HPDMatrixCholeskyRec(a,0,n,isupper,tmp)); - } -//+------------------------------------------------------------------+ -//| Cache-oblivious Cholesky decomposition | -//| The algorithm computes Cholesky decomposition of a symmetric | -//| positive - definite matrix. The result of an algorithm is a | -//| representation of A as A=U^T*U or A=L*L^T | -//| INPUT PARAMETERS: | -//| A - upper or lower triangle of a factorized matrix. | -//| array with elements [0..N-1, 0..N-1]. | -//| N - size of matrix A. | -//| IsUpper - if IsUpper=True, then A contains an upper | -//| triangle of a symmetric matrix, otherwise A | -//| contains a lower one. | -//| OUTPUT PARAMETERS: | -//| A - the result of factorization. If IsUpper=True, | -//| then the upper triangle contains matrix U, so | -//| that A = U^T*U, and the elements below the main | -//| diagonal are not modified. Similarly, if | -//| IsUpper = False. | -//| RESULT: | -//| If the matrix is positive-definite, the function returns | -//| True. Otherwise, the function returns False. Contents of A is| -//| not determined in such case. | -//+------------------------------------------------------------------+ -static bool CTrFac::SPDMatrixCholesky(CMatrixDouble &a,const int n,const bool isupper) - { -//--- create array - double tmp[]; -//--- check - if(n<1) - return(false); -//--- return result - return(SPDMatrixCholeskyRec(a,0,n,isupper,tmp)); - } -//+------------------------------------------------------------------+ -//| LUP decomposition of general real matrix | -//+------------------------------------------------------------------+ -static void CTrFac::RMatrixLUP(CMatrixDouble &a,const int m,const int n,int &pivots[]) - { -//--- create variables - int i=0; - int j=0; - double mx=0; - double v=0; - int i_=0; -//--- create array - double tmp[]; -//--- Internal LU decomposition subroutine. -//--- Never call it directly. - if(!CAp::Assert(m>0,__FUNCTION__+": incorrect M!")) - return; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": incorrect N!")) - return; -//--- Scale matrix to avoid overflows, -//--- decompose it, then scale back. - mx=0; - for(i=0;i0,__FUNCTION__+": incorrect M!")) - return; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": incorrect N!")) - return; -//--- Scale matrix to avoid overflows, -//--- decompose it, then scale back. - mx=0; - for(i=0;i0,__FUNCTION__+": incorrect M!")) - return; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": incorrect N!")) - return; -//--- allocation - ArrayResizeAL(tmp,2*MathMax(m,n)); - ArrayResizeAL(pivots,MathMin(m,n)); -//--- Scale matrix to avoid overflows, -//--- decompose it, then scale back. - mx=0; - for(i=0;i0,__FUNCTION__+": incorrect M!")) - return; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": incorrect N!")) - return; -//--- allocation - ArrayResizeAL(tmp,2*MathMax(m,n)); - ArrayResizeAL(pivots,MathMin(m,n)); -//--- Scale matrix to avoid overflows, -//--- decompose it, then scale back. - mx=0; - for(i=0;i0.0) - { - a[offs].Set(offs,MathSqrt(a[offs][offs])); - //--- return result - return(true); - } - else - { - //--- return result - return(false); - } - } -//--- check - if(n<=CAblas::AblasBlockSize()) - { - //--- return result - return(SPDMatrixCholesky2(a,offs,n,isupper,tmp)); - } -//--- general case: split task in cache-oblivious manner - result=true; - CAblas::AblasSplitLength(a,n,n1,n2); - result=SPDMatrixCholeskyRec(a,offs,n1,isupper,tmp); -//--- check - if(!result) - { - //--- return result - return(result); - } -//--- check - if(n2>0) - { - if(isupper) - { - //--- function call - CAblas::RMatrixLeftTrsM(n1,n2,a,offs,offs,isupper,false,1,a,offs,offs+n1); - //--- function call - CAblas::RMatrixSyrk(n2,n1,-1.0,a,offs,offs+n1,1,1.0,a,offs+n1,offs+n1,isupper); - } - else - { - //--- function call - CAblas::RMatrixRightTrsM(n2,n1,a,offs,offs,isupper,false,1,a,offs+n1,offs); - //--- function call - CAblas::RMatrixSyrk(n2,n1,-1.0,a,offs+n1,offs,0,1.0,a,offs+n1,offs+n1,isupper); - } - result=SPDMatrixCholeskyRec(a,offs+n1,n2,isupper,tmp); - //--- check - if(!result) - { - //--- return result - return(result); - } - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Recurrent complex LU subroutine. | -//| Never call it directly. | -//+------------------------------------------------------------------+ -static void CTrFac::CMatrixLUPRec(CMatrixComplex &a,const int offs,const int m, - const int n,int &pivots[],al_complex &tmp[]) - { -//--- create variables - int i=0; - int m1=0; - int m2=0; - int i_=0; - int i1_=0; - al_complex One(1.0,0.0); - al_complex _One(-1.0,0.0); -//--- Kernel case - if(MathMin(m,n)<=CAblas::AblasComplexBlockSize()) - { - CMatrixLUP2(a,offs,m,n,pivots,tmp); - //--- exit the function - return; - } -//--- Preliminary step, make N>=M -//--- ( A1 ) -//--- A = ( ), where A1 is square -//--- ( A2 ) -//--- Factorize A1, update A2 - if(m>n) - { - //--- function call - CMatrixLUPRec(a,offs,n,n,pivots,tmp); - for(i=0;i0) - { - for(i=0;i=M -//--- ( A1 ) -//--- A = ( ), where A1 is square -//--- ( A2 ) -//--- Factorize A1, update A2 - if(m>n) - { - //--- function call - RMatrixLUPRec(a,offs,n,n,pivots,tmp); - for(i=0;i0) - { - for(i=0;i=N. -//--- A = (A1 A2), where A1 is square -//--- Factorize A1, update A2 - if(n>m) - { - //--- function call - CMatrixPLURec(a,offs,m,m,pivots,tmp); - for(i=0;i0) - { - for(i=0;i=N. -//--- A = (A1 A2), where A1 is square -//--- Factorize A1, update A2 - if(n>m) - { - //--- function call - RMatrixPLURec(a,offs,m,m,pivots,tmp); - for(i=0;i0) - { - for(i=0;iCMath::AbsComplex(a[offs+j][offs+jp])) - jp=i; - } - pivots[offs+j]=offs+jp; - //--- check - if(jp!=j) - { - i1_=offs; - for(i_=0;i_MathAbs(a[offs+j][offs+jp])) - jp=i; - } - pivots[offs+j]=offs+jp; - //--- check - if(jp!=j) - { - i1_=offs; - for(i_=0;i_CMath::AbsComplex(a[offs+jp][offs+j])) - jp=i; - } - pivots[offs+j]=offs+jp; - if(a[offs+jp][offs+j]!=zero) - { - //--- Apply the interchange to rows - if(jp!=j) - { - for(i=0;iMathAbs(a[offs+jp][offs+j])) - jp=i; - } - pivots[offs+j]=offs+jp; - //--- check - if(a[offs+jp][offs+j]!=0.0) - { - //--- Apply the interchange to rows - if(jp!=j) - { - for(i=0;i0.0) - { - a[offs].Set(offs,MathSqrt(a[offs][offs].re)); - result=true; - } - else - { - result=false; - } - //--- return result - return(result); - } -//--- check - if(n<=CAblas::AblasComplexBlockSize()) - { - result=HPDMatrixCholesky2(a,offs,n,isupper,tmp); - //--- return result - return(result); - } -//--- general case: split task in cache-oblivious manner - result=true; -//--- function call - CAblas::AblasComplexSplitLength(a,n,n1,n2); - result=HPDMatrixCholeskyRec(a,offs,n1,isupper,tmp); -//--- check - if(!result) - return(result); -//--- check - if(n2>0) - { - //--- check - if(isupper) - { - //--- function call - CAblas::CMatrixLeftTrsM(n1,n2,a,offs,offs,isupper,false,2,a,offs,offs+n1); - //--- function call - CAblas::CMatrixSyrk(n2,n1,-1.0,a,offs,offs+n1,2,1.0,a,offs+n1,offs+n1,isupper); - } - else - { - //--- function call - CAblas::CMatrixRightTrsM(n2,n1,a,offs,offs,isupper,false,2,a,offs+n1,offs); - //--- function call - CAblas::CMatrixSyrk(n2,n1,-1.0,a,offs+n1,offs,0,1.0,a,offs+n1,offs+n1,isupper); - } - result=HPDMatrixCholeskyRec(a,offs+n1,n2,isupper,tmp); - //--- check - if(!result) - return(result); - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Level-2 Hermitian Cholesky subroutine. | -//| -- LAPACK routine (version 3.0) -- | -//| Univ. of Tennessee,Univ. of California Berkeley,NAG Ltd., | -//| Courant Institute,Argonne National Lab,and Rice University | -//| February 29,1992 | -//+------------------------------------------------------------------+ -static bool CTrFac::HPDMatrixCholesky2(CMatrixComplex &aaa,const int offs, - const int n,const bool isupper,al_complex &tmp[]) - { -//--- create variables - bool result; - int i=0; - int j=0; - double ajj=0; - al_complex v=0; - al_complex cR; - double r=0; - int i_=0; - int i1_=0; -//--- initialization - result=true; -//--- check - if(n<0) - return(false); -//--- check - if(n==0) - return(result); -//--- check - if(isupper) - { - //--- Compute the Cholesky factorization A = U'*U. - for(j=0;j0) - { - i1_=offs; - for(i_=0;i_0) - { - i1_=offs; - for(i_=0;i_0) - { - i1_=offs; - for(i_=0;i_0) - { - i1_=offs; - for(i_=0;i_=1,__FUNCTION__+": N<1!")) - return(EMPTY_VALUE); -//--- allocation - ArrayResizeAL(t,n); -//--- fiiling array - for(i=0;i=1,__FUNCTION__+": N<1!")) - return(EMPTY_VALUE); -//--- change values - nrm=0; - for(i=0;i=1,__FUNCTION__+": N<1!")) - return(EMPTY_VALUE); -//--- allocation - ArrayResizeAL(t,n); -//--- fiiling array - for(i=0;i=1,__FUNCTION__+": N<1!")) - return(EMPTY_VALUE); -//--- change values - nrm=0; - for(i=0;i=1,__FUNCTION__+": N<1!")) - return(EMPTY_VALUE); -//--- allocation - ArrayResizeAL(t,n); -//--- fiiling array - for(i=0;i=1,__FUNCTION__+": N<1!")) - return(EMPTY_VALUE); -//--- change values - nrm=0; - for(i=0;i=1,__FUNCTION__+": N<1!")) - return(EMPTY_VALUE); -//--- function call - CMatrixRCondLUInternal(lua,n,true,false,0.0,v); -//--- return result - return(v); - } -//+------------------------------------------------------------------+ -//| Estimate of the condition number of a matrix given by its LU | -//| decomposition (infinity norm). | -//| The algorithm calculates a lower bound of the condition number. | -//| In this case, the algorithm does not return a lower bound of the | -//| condition number, but an inverse number (to avoid an overflow in | -//| case of a singular matrix). | -//| Input parameters: | -//| LUA - LU decomposition of a matrix in compact form. | -//| Output of the CMatrixLU subroutine. | -//| N - size of matrix A. | -//| Result: 1/LowerBound(cond(A)) | -//| NOTE: | -//| if k(A) is very large, then matrix is assumed degenerate, | -//| k(A)=INF, 0.0 is returned in such cases. | -//+------------------------------------------------------------------+ -static double CRCond::CMatrixLURCondInf(CMatrixComplex &lua,const int n) - { -//--- create a variable - double v=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return(EMPTY_VALUE); -//--- function call - CMatrixRCondLUInternal(lua,n,false,false,0.0,v); -//--- return result - return(v); - } -//+------------------------------------------------------------------+ -//| Triangular matrix: estimate of a condition number (1-norm) | -//| The algorithm calculates a lower bound of the condition number. | -//| In this case, the algorithm does not return a lower bound of the | -//| condition number, but an inverse number (to avoid an overflow in | -//| case of a singular matrix). | -//| Input parameters: | -//| A - matrix. Array[0..N-1, 0..N-1]. | -//| N - size of A. | -//| IsUpper - True, if the matrix is upper triangular. | -//| IsUnit - True, if the matrix has a unit diagonal. | -//| Result: 1/LowerBound(cond(A)) | -//| NOTE: | -//| if k(A) is very large, then matrix is assumed degenerate, | -//| k(A)=INF, 0.0 is returned in such cases. | -//+------------------------------------------------------------------+ -static double CRCond::CMatrixTrRCond1(CMatrixComplex &a,const int n, - const bool isupper,const bool isunit) - { -//--- create variables - int i=0; - int j=0; - double v=0; - double nrm=0; - int j1=0; - int j2=0; -//--- create arrays - int pivots[]; - double t[]; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return(EMPTY_VALUE); -//--- allocation - ArrayResizeAL(t,n); -//--- fiiling array - for(i=0;i=1,__FUNCTION__+": N<1!")) - return(EMPTY_VALUE); -//--- change values - nrm=0; - for(i=0;i0 after this block - if(anorm==0.0) - return; -//--- check - if(n==1) - { - rc=1; - return; - } -//--- Estimate the norm of inv(A). - ainvnm=0; - kase=0; - while(true) - { - //--- function call - RMatrixEstimateNorm(n,ev,ex,iwork,ainvnm,kase); - //--- check - if(kase==0) - break; - //--- from 1-based array to 0-based - for(i=0;i=0;i--) - ex[i+1]=ex[i]; - } -//--- Compute the estimate of the reciprocal condition number. - if(ainvnm!=0.0) - { - rc=1/ainvnm; - rc=rc/anorm; - //--- check - if(rc=0;i--) - ex[i+1]=ex[i]; - } -//--- Compute the estimate of the reciprocal condition number. - if(ainvnm!=0.0) - { - rc=1/ainvnm; - rc=rc/anorm; - //--- check - if(rc=1)) - return; -//--- allocation - ArrayResizeAL(tmp,n); -//--- initialization - rc=0; -//--- prepare parameters for triangular solver - maxgrowth=1/RCondThreshold(); - sa=0; -//--- check - if(isupper) - { - for(i=0;i=1;i--) - { - i1_=1; - v=0.0; - for(i_=0;i_=0;i--) - ex[i+1]=ex[i]; - } -//--- Compute the estimate of the reciprocal condition number. - if(ainvnm!=0.0) - { - v=1/ainvnm; - rc=v/anorm; - //--- check - if(rc=1)) - return; -//--- allocation - ArrayResizeAL(tmp,n); -//--- initialization - rc=0; -//--- prepare parameters for triangular solver - maxgrowth=1/RCondThreshold(); - sa=0; -//--- check - if(isupper) - { - for(i=0;i=1;i--) - { - i1_=1; - v=0.0; - for(i_=0;i_0 - if(anorm==0.0) - return; -//--- check - if(n==1) - { - rc=1; - return; - } -//--- Estimate the norm of inv(A). - ainvnm=0; - kase=0; - while(true) - { - //--- function call - CMatrixEstimateNorm(n,ev,ex,ainvnm,kase,isave,rsave); - //--- check - if(kase==0) - break; - for(i=0;i=0;i--) - ex[i+1]=ex[i]; - } -//--- Compute the estimate of the reciprocal condition number. - if(ainvnm!=0.0) - { - rc=1/ainvnm; - rc=rc/anorm; - //--- check - if(rc=1;i--) - { - //--- check - if(i>1) - { - i1_=1; - v=0.0; - for(i_=0;i_<=i-2;i_++) - v+=lua[i-1][i_]*ex[i_+i1_]; - } - else - v=0; - ex[i]=ex[i]+v; - } - } - else - { - //--- Multiply by L' - for(i=0;i=1) - { - for(i_=0;i_0 after this block - if(anorm==0.0) - return; -//--- check - if(n==1) - { - rc=1; - return; - } -//--- Estimate the norm of inv(A). - ainvnm=0; - kase=0; - while(true) - { - //--- function call - RMatrixEstimateNorm(n,ev,ex,iwork,ainvnm,kase); - //--- check - if(kase==0) - break; - //--- from 1-based array to 0-based - for(i=0;i=0;i--) - ex[i+1]=ex[i]; - } -//--- Compute the estimate of the reciprocal condition number. - if(ainvnm!=0.0) - { - rc=1/ainvnm; - rc=rc/anorm; - //--- check - if(rc=1;i--) - { - v=0; - //--- check - if(i>1) - { - i1_=1; - v=0.0; - for(i_=0;i_<=i-2;i_++) - v+=lua[i-1][i_]*ex[i_+i1_]; - } - ex[i]=v+ex[i]; - } - } - else - { - //--- Multiply by L' - for(i=1;i<=n;i++) - cwork2[i]=0; - for(i=1;i<=n;i++) - { - v=ex[i]; - //--- check - if(i>1) - { - i1_=-1; - for(i_=1;i_=0;i--) - ex[i+1]=ex[i]; - } -//--- Compute the estimate of the reciprocal condition number. - if(ainvnm!=0.0) - { - rc=1/ainvnm; - rc=rc/anorm; - //--- check - if(rc=0.0) - x[i]=1; - else - x[i]=-1; - //--- check - if(x[i]>0) - isgn[i]=1; - //--- check - if(x[i]<0) - isgn[i]=-1; - //--- check - if(x[i]==0) - isgn[i]=0; - } - kase=2; - isgn[posjump]=2; - //--- exit the function - return; - } -//--- ................ entry (jump = 2) -//--- first iteration. x has been overwritten by trandpose(a)*x. - if(isgn[posjump]==2) - { - isgn[posj]=1; - for(i=2;i<=n;i++) - { - //--- check - if(MathAbs(x[i])>MathAbs(x[isgn[posj]])) - isgn[posj]=i; - } - isgn[positer]=2; - //--- main loop - iterations 2,3,...,itmax. - for(i=1;i<=n;i++) - x[i]=0; - x[isgn[posj]]=1; - kase=1; - isgn[posjump]=3; - //--- exit the function - return; - } -//--- ................ entry (jump = 3) -//--- x has been overwritten by a*x. - if(isgn[posjump]==3) - { - for(i_=1;i_<=n;i_++) - v[i_]=x[i_]; - v[posestold]=est; - //--- change value - est=0; - for(i=1;i<=n;i++) - est=est+MathAbs(v[i]); - flg=false; - for(i=1;i<=n;i++) - { - if(((x[i]>=0.0)&&(isgn[i]<0))||((x[i]<0.0)&&(isgn[i]>=0))) - flg=true; - } - //--- repeated sign vector detected, hence algorithm has converged. - //--- or may be cycling. - if(!flg || est<=v[posestold]) - { - v[posaltsgn]=1; - for(i=1;i<=n;i++) - { - x[i]=v[posaltsgn]*(1+(double)(i-1)/(double)(n-1)); - v[posaltsgn]=-v[posaltsgn]; - } - kase=1; - isgn[posjump]=5; - //--- exit the function - return; - } - for(i=1;i<=n;i++) - { - //--- check - if(x[i]>=0.0) - { - x[i]=1; - isgn[i]=1; - } - else - { - x[i]=-1; - isgn[i]=-1; - } - } - kase=2; - isgn[posjump]=4; - //--- exit the function - return; - } -//--- ................ entry (jump = 4) -//--- x has been overwritten by trandpose(a)*x. - if(isgn[posjump]==4) - { - isgn[posjlast]=isgn[posj]; - isgn[posj]=1; - for(i=2;i<=n;i++) - { - //--- check - if(MathAbs(x[i])>MathAbs(x[isgn[posj]])) - isgn[posj]=i; - } - //--- check - if(x[isgn[posjlast]]!=MathAbs(x[isgn[posj]]) && isgn[positer]est) - { - for(i_=1;i_<=n;i_++) - v[i_]=x[i_]; - est=v[postemp]; - } - kase=0; - //--- exit the function - return; - } - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static void CRCond::CMatrixEstimateNorm(const int n,al_complex &v[],al_complex &x[], - double &est,int &kase,int &isave[], - double &rsave[]) - { -//--- create variables - int itmax=0; - int i=0; - int iter=0; - int j=0; - int jlast=0; - int jump=0; - double absxi=0; - double altsgn=0; - double estold=0; - double safmin=0; - double temp=0; - int i_=0; -//--- Executable Statements - itmax=5; - safmin=CMath::m_minrealnumber; -//--- check - if(kase==0) - { - //--- allocation - ArrayResizeAL(v,n+1); - ArrayResizeAL(x,n+1); - ArrayResizeAL(isave,5); - ArrayResizeAL(rsave,4); - for(i=1;i<=n;i++) - x[i]=1.0/(double)n; - kase=1; - jump=1; - //--- function call - InternalComplexRCondSaveAll(isave,rsave,i,iter,j,jlast,jump,absxi,altsgn,estold,temp); - //--- exit the function - return; - } -//--- function call - InternalComplexRCondLoadAll(isave,rsave,i,iter,j,jlast,jump,absxi,altsgn,estold,temp); -//--- entry (jump = 1) -//--- first iteration. x has been overwritten by a*x. - if(jump==1) - { - //--- check - if(n==1) - { - v[1]=x[1]; - //--- function call - est=CMath::AbsComplex(v[1]); - kase=0; - //--- function call - InternalComplexRCondSaveAll(isave,rsave,i,iter,j,jlast,jump,absxi,altsgn,estold,temp); - //--- exit the function - return; - } - //--- function call - est=InternalComplexRCondScSum1(x,n); - for(i=1;i<=n;i++) - { - //--- function call - absxi=CMath::AbsComplex(x[i]); - //--- check - if(absxi>safmin) - x[i]=x[i]/absxi; - else - x[i]=1; - } - kase=2; - jump=2; - //--- function call - InternalComplexRCondSaveAll(isave,rsave,i,iter,j,jlast,jump,absxi,altsgn,estold,temp); - //--- exit the function - return; - } -//--- entry (jump = 2) -//--- first iteration. x has been overwritten by ctrans(a)*x. - if(jump==2) - { - j=InternalComplexRCondIcMax1(x,n); - iter=2; - //--- main loop - iterations 2,3,...,itmax. - for(i=1;i<=n;i++) - x[i]=0; - x[j]=1; - kase=1; - jump=3; - //--- function call - InternalComplexRCondSaveAll(isave,rsave,i,iter,j,jlast,jump,absxi,altsgn,estold,temp); - //--- exit the function - return; - } -//--- entry (jump = 3) -//--- x has been overwritten by a*x. - if(jump==3) - { - for(i_=1;i_<=n;i_++) - v[i_]=x[i_]; - estold=est; - //--- function call - est=InternalComplexRCondScSum1(v,n); - //--- test for cycling. - if(est<=estold) - { - //--- iteration complete. final stage. - altsgn=1; - for(i=1;i<=n;i++) - { - x[i]=altsgn*(1+(double)(i-1)/(double)(n-1)); - altsgn=-altsgn; - } - kase=1; - jump=5; - //--- function call - InternalComplexRCondSaveAll(isave,rsave,i,iter,j,jlast,jump,absxi,altsgn,estold,temp); - //--- exit the function - return; - } - for(i=1;i<=n;i++) - { - absxi=CMath::AbsComplex(x[i]); - //--- check - if(absxi>safmin) - x[i]=x[i]/absxi; - else - x[i]=1; - } - kase=2; - jump=4; - //--- function call - InternalComplexRCondSaveAll(isave,rsave,i,iter,j,jlast,jump,absxi,altsgn,estold,temp); - //--- exit the function - return; - } -//--- entry (jump = 4) -//--- x has been overwritten by ctrans(a)*x. - if(jump==4) - { - jlast=j; - j=InternalComplexRCondIcMax1(x,n); - //--- check - if(CMath::AbsComplex(x[jlast])!=CMath::AbsComplex(x[j]) && iterest) - { - for(i_=1;i_<=n;i_++) - v[i_]=x[i_]; - est=temp; - } - kase=0; - //--- function call - InternalComplexRCondSaveAll(isave,rsave,i,iter,j,jlast,jump,absxi,altsgn,estold,temp); - //--- exit the function - return; - } - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static double CRCond::InternalComplexRCondScSum1(al_complex &x[],const int n) - { -//--- create variables - double result=0; - int i=0; -//--- get result - for(i=1;i<=n;i++) - result=result+CMath::AbsComplex(x[i]); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static int CRCond::InternalComplexRCondIcMax1(al_complex &x[],const int n) - { -//--- create variables - int result=0; - int i=0; - double m=0; -//--- get result - result=1; - m=CMath::AbsComplex(x[1]); - for(i=2;i<=n;i++) - { - //--- check - if(CMath::AbsComplex(x[i])>m) - { - result=i; - m=CMath::AbsComplex(x[i]); - } - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static void CRCond::InternalComplexRCondSaveAll(int &isave[],double &rsave[], - int &i,int &iter,int &j, - int &jlast,int &jump, - double &absxi,double &altsgn, - double &estold,double &temp) - { -//--- copy - isave[0]=i; - isave[1]=iter; - isave[2]=j; - isave[3]=jlast; - isave[4]=jump; -//--- copy - rsave[0]=absxi; - rsave[1]=altsgn; - rsave[2]=estold; - rsave[3]=temp; - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static void CRCond::InternalComplexRCondLoadAll(int &isave[],double &rsave[], - int &i,int &iter,int &j, - int &jlast,int &jump, - double &absxi,double &altsgn, - double &estold,double &temp) - { -//--- get - i=isave[0]; - iter=isave[1]; - j=isave[2]; - jlast=isave[3]; - jump=isave[4]; -//--- get - absxi=rsave[0]; - altsgn=rsave[1]; - estold=rsave[2]; - temp=rsave[3]; - } -//+------------------------------------------------------------------+ -//| Matrix inverse report: | -//| * R1 reciprocal of condition number in 1-norm | -//| * RInf reciprocal of condition number in inf-norm | -//+------------------------------------------------------------------+ -class CMatInvReport - { -public: - double m_r1; - double m_rinf; - //--- constructor, destructor - CMatInvReport(void); - ~CMatInvReport(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMatInvReport::CMatInvReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMatInvReport::~CMatInvReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Matrix inverse report: | -//| * R1 reciprocal of condition number in 1-norm | -//| * RInf reciprocal of condition number in inf-norm | -//+------------------------------------------------------------------+ -class CMatInvReportShell - { -private: - CMatInvReport m_innerobj; -public: - //--- constructors, destructor - CMatInvReportShell(void); - CMatInvReportShell(CMatInvReport &obj); - ~CMatInvReportShell(void); - //--- methods - double GetR1(void); - void SetR1(double r); - double GetRInf(void); - void SetRInf(double r); - CMatInvReport *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMatInvReportShell::CMatInvReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -CMatInvReportShell::CMatInvReportShell(CMatInvReport &obj) - { - m_innerobj.m_r1=obj.m_r1; - m_innerobj.m_rinf=obj.m_rinf; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMatInvReportShell::~CMatInvReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable r1 | -//+------------------------------------------------------------------+ -double CMatInvReportShell::GetR1(void) - { - return(m_innerobj.m_r1); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable r1 | -//+------------------------------------------------------------------+ -void CMatInvReportShell::SetR1(double r) - { - m_innerobj.m_r1=r; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable rinf | -//+------------------------------------------------------------------+ -double CMatInvReportShell::GetRInf(void) - { - return(m_innerobj.m_rinf); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable rint | -//+------------------------------------------------------------------+ -void CMatInvReportShell::SetRInf(double r) - { - m_innerobj.m_rinf=r; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CMatInvReport *CMatInvReportShell::GetInnerObj(void) - { - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Inverse matrix | -//+------------------------------------------------------------------+ -class CMatInv - { -private: - //--- private methods - static void RMatrixTrInverseRec(CMatrixDouble &a,const int offs,const int n,const bool isupper,const bool isunit,double &tmp[],int &info,CMatInvReport &rep); - static void CMatrixTrInverseRec(CMatrixComplex &a,const int offs,const int n,const bool isupper,const bool isunit,al_complex &tmp[],int &info,CMatInvReport &rep); - static void RMatrixLUInverseRec(CMatrixDouble &a,const int offs,const int n,double &work[],int &info,CMatInvReport &rep); - static void CMatrixLUInverseRec(CMatrixComplex &a,const int offs,const int n,al_complex &work[],int &info,CMatInvReport &rep); - static void SPDMatrixCholeskyInverseRec(CMatrixDouble &a,const int offs,const int n,const bool isupper,double &tmp[]); - static void HPDMatrixCholeskyInverseRec(CMatrixComplex &a,const int offs,const int n,const bool isupper,al_complex &tmp[]); -public: - CMatInv(void); - ~CMatInv(void); - //--- public methods - static void RMatrixLUInverse(CMatrixDouble &a,int &pivots[],const int n,int &info,CMatInvReport &rep); - static void RMatrixInverse(CMatrixDouble &a,const int n,int &info,CMatInvReport &rep); - static void SPDMatrixCholeskyInverse(CMatrixDouble &a,const int n,const bool isupper,int &info,CMatInvReport &rep); - static void SPDMatrixInverse(CMatrixDouble &a,const int n,const bool isupper,int &info,CMatInvReport &rep); - static void RMatrixTrInverse(CMatrixDouble &a,const int n,const bool isupper,const bool isunit,int &info,CMatInvReport &rep); - static void CMatrixLUInverse(CMatrixComplex &a,int &pivots[],const int n,int &info,CMatInvReport &rep); - static void CMatrixInverse(CMatrixComplex &a,const int n,int &info,CMatInvReport &rep); - static void HPDMatrixCholeskyInverse(CMatrixComplex &a,const int n,const bool isupper,int &info,CMatInvReport &rep); - static void HPDMatrixInverse(CMatrixComplex &a,const int n,const bool isupper,int &info,CMatInvReport &rep); - static void CMatrixTrInverse(CMatrixComplex &a,const int n,const bool isupper,const bool isunit,int &info,CMatInvReport &rep); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMatInv::CMatInv(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMatInv::~CMatInv(void) - { - - } -//+------------------------------------------------------------------+ -//| Inversion of a matrix given by its LU decomposition. | -//| INPUT PARAMETERS: | -//| A - LU decomposition of the matrix | -//| (output of RMatrixLU subroutine). | -//| Pivots - table of permutations | -//| (the output of RMatrixLU subroutine). | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| OUTPUT PARAMETERS: | -//| Info - return code: | -//| * -3 A is singular, or VERY close to singular.| -//| it is filled by zeros in such cases. | -//| * 1 task is solved (but matrix A may be | -//| ill-conditioned, check R1/RInf parameters| -//| for condition numbers). | -//| Rep - solver report, see below for more info | -//| A - inverse of matrix A. | -//| Array whose indexes range within | -//| [0..N-1, 0..N-1]. | -//| SOLVER REPORT | -//| Subroutine sets following fields of the Rep structure: | -//| * R1 reciprocal of condition number: 1/cond(A), 1-norm. | -//| * RInf reciprocal of condition number: 1/cond(A), inf-norm. | -//+------------------------------------------------------------------+ -static void CMatInv::RMatrixLUInverse(CMatrixDouble &a,int &pivots[], - const int n,int &info,CMatInvReport &rep) - { -//--- create variables - int i=0; - int j=0; - int k=0; - double v=0; -//--- create array - double work[]; -//--- initialization - info=0; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(CAp::Cols(a)>=n,__FUNCTION__+": cols(A)=n,__FUNCTION__+": rows(A)=n,__FUNCTION__+": len(Pivots)n-1 || pivots[i]0,__FUNCTION__+": incorrect Pivots array!")) - return; -//--- calculate condition numbers - rep.m_r1=CRCond::RMatrixLURCond1(a,n); - rep.m_rinf=CRCond::RMatrixLURCondInf(a,n); -//--- check - if(rep.m_r1=0;j--) - { - k=pivots[j]; - v=a[i][j]; - a[i].Set(j,a[i][k]); - a[i].Set(k,v); - } - } - } -//+------------------------------------------------------------------+ -//| Inversion of a general matrix. | -//| Input parameters: | -//| A - matrix. | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| Output parameters: | -//| Info - return code, same as in RMatrixLUInverse | -//| Rep - solver report, same as in RMatrixLUInverse | -//| A - inverse of matrix A, same as in RMatrixLUInverse | -//| Result: | -//| True, if the matrix is not singular. | -//| False, if the matrix is singular. | -//+------------------------------------------------------------------+ -static void CMatInv::RMatrixInverse(CMatrixDouble &a,const int n,int &info, - CMatInvReport &rep) - { -//--- create array - int pivots[]; -//--- initialization - info=0; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(CAp::Cols(a)>=n,__FUNCTION__+": cols(A)=n,__FUNCTION__+": rows(A)0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(CAp::Cols(a)>=n,__FUNCTION__+": cols(A)=n,__FUNCTION__+": rows(A)=n,__FUNCTION__+": len(Pivots)n-1 || pivots[i]0,__FUNCTION__+": incorrect Pivots array!")) - return; -//--- calculate condition numbers - rep.m_r1=CRCond::CMatrixLURCond1(a,n); - rep.m_rinf=CRCond::CMatrixLURCondInf(a,n); -//--- check - if(rep.m_r1=0;j--) - { - k=pivots[j]; - v=a[i][j]; - a[i].Set(j,a[i][k]); - a[i].Set(k,v); - } - } - } -//+------------------------------------------------------------------+ -//| Inversion of a general matrix. | -//| Input parameters: | -//| A - matrix | -//| N - size of matrix A (optional) : | -//| * if given, only principal NxN submatrix is | -//| processed and overwritten. other elements are | -//| unchanged. | -//| * if not given, size is automatically determined | -//| from matrix size (A must be square matrix) | -//| Output parameters: | -//| Info - return code, same as in RMatrixLUInverse | -//| Rep - solver report, same as in RMatrixLUInverse | -//| A - inverse of matrix A, same as in RMatrixLUInverse | -//+------------------------------------------------------------------+ -static void CMatInv::CMatrixInverse(CMatrixComplex &a,const int n,int &info, - CMatInvReport &rep) - { -//--- create array - int pivots[]; -//--- initialization - info=0; -//--- check - if(!CAp::Assert(n>0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(CAp::Cols(a)>=n,__FUNCTION__+": cols(A)=n,__FUNCTION__+": rows(A)0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(CAp::Cols(a)>=n,__FUNCTION__+": cols(A)=n,__FUNCTION__+": rows(A)0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(CAp::Cols(a)>=n,__FUNCTION__+": cols(A)=n,__FUNCTION__+": rows(A)0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(CAp::Cols(a)>=n,__FUNCTION__+": cols(A)=n,__FUNCTION__+": rows(A)0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(CAp::Cols(a)>=n,__FUNCTION__+": cols(A)=n,__FUNCTION__+": rows(A)0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(CAp::Cols(a)>=n,__FUNCTION__+": cols(A)=n,__FUNCTION__+": rows(A)0,__FUNCTION__+": N<=0!")) - return; -//--- check - if(!CAp::Assert(CAp::Cols(a)>=n,__FUNCTION__+": cols(A)=n,__FUNCTION__+": rows(A)0) - { - i1_=offs; - for(i_=0;i_=0;j--) - { - //--- check - if(!isunit) - { - //--- check - if(a[offs+j][offs+j]==0.0) - { - info=-3; - //--- exit the function - return; - } - a[offs+j].Set(offs+j,1/a[offs+j][offs+j]); - ajj=-a[offs+j][offs+j]; - } - else - ajj=-1; - //--- check - if(jj+1) - { - i1_=-offs; - v=0.0; - for(i_=offs+j+1;i_0) - { - //--- check - if(isupper) - { - for(i=0;i0) - { - i1_=offs; - for(i_=0;i_=0;j--) - { - //--- check - if(!isunit) - { - //--- check - if(a[offs+j][offs+j]==0) - { - info=-3; - //--- exit the function - return; - } - a[offs+j].Set(offs+j,One/a[offs+j][offs+j]); - ajj=-a[offs+j][offs+j]; - } - else - ajj=-1; - //--- check - if(jj+1) - { - i1_=-offs; - v=0.0; - for(i_=offs+j+1;i_0) - { - //--- check - if(isupper) - { - for(i=0;i=0;j--) - { - //--- Copy current column of L to WORK and replace with zeros. - for(i=j+1;i0,__FUNCTION__+": internal error!")) - return; -//--- X :=inv(U1)*U12*inv(U2) - CAblas::RMatrixLeftTrsM(n1,n2,a,offs,offs,true,false,0,a,offs,offs+n1); - CAblas::RMatrixRightTrsM(n1,n2,a,offs+n1,offs+n1,true,false,0,a,offs,offs+n1); -//--- Y :=inv(L2)*L12*inv(L1) - CAblas::RMatrixLeftTrsM(n2,n1,a,offs+n1,offs+n1,false,true,0,a,offs+n1,offs); - CAblas::RMatrixRightTrsM(n2,n1,a,offs,offs,false,true,0,a,offs+n1,offs); -//--- W :=inv(L1*U1)+X*Y - RMatrixLUInverseRec(a,offs,n1,work,info,rep); -//--- check - if(info<=0) - return; -//--- function call - CAblas::RMatrixGemm(n1,n1,n2,1.0,a,offs,offs+n1,0,a,offs+n1,offs,0,1.0,a,offs,offs); -//--- X :=-X*inv(L2) -//--- Y :=-inv(U2)*Y - CAblas::RMatrixRightTrsM(n1,n2,a,offs+n1,offs+n1,false,true,0,a,offs,offs+n1); - for(i=0;i=0;j--) - { - //--- Copy current column of L to WORK and replace with zeros. - for(i=j+1;i0,__FUNCTION__+": internal error!")) - return; -//--- X :=inv(U1)*U12*inv(U2) - CAblas::CMatrixLeftTrsM(n1,n2,a,offs,offs,true,false,0,a,offs,offs+n1); - CAblas::CMatrixRightTrsM(n1,n2,a,offs+n1,offs+n1,true,false,0,a,offs,offs+n1); -//--- Y :=inv(L2)*L12*inv(L1) - CAblas::CMatrixLeftTrsM(n2,n1,a,offs+n1,offs+n1,false,true,0,a,offs+n1,offs); - CAblas::CMatrixRightTrsM(n2,n1,a,offs,offs,false,true,0,a,offs+n1,offs); -//--- W :=inv(L1*U1)+X*Y - CMatrixLUInverseRec(a,offs,n1,work,info,rep); -//--- check - if(info<=0) - return; - CAblas::CMatrixGemm(n1,n1,n2,One,a,offs,offs+n1,0,a,offs+n1,offs,0,One,a,offs,offs); -//--- X :=-X*inv(L2) -//--- Y :=-inv(U2)*Y - CAblas::CMatrixRightTrsM(n1,n2,a,offs+n1,offs+n1,false,true,0,a,offs,offs+n1); - for(i=0;i0, contains matrix U*Q. | -//| VT - if NCVT>0, contains matrix (P^T)*VT. | -//| C - if NCC>0, contains matrix Q'*C. | -//| Result: | -//| True, if the algorithm has converged. | -//| False, if the algorithm hasn't converged (rare case). | -//| Additional information: | -//| The type of convergence is controlled by the internal | -//| parameter TOL. If the parameter is greater than 0, the | -//| singular values will have relative accuracy TOL. If TOL<0, | -//| the singular values will have absolute accuracy | -//| ABS(TOL)*norm(B). By default, |TOL| falls within the range of| -//| 10*Epsilon and 100*Epsilon, where Epsilon is the machine | -//| precision. It is not recommended to use TOL less than | -//| 10*Epsilon since this will considerably slow down the | -//| algorithm and may not lead to error decreasing. | -//| History: | -//| * 31 March, 2007. | -//| changed MAXITR from 6 to 12. | -//| -- LAPACK routine (version 3.0) -- | -//| Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., | -//| Courant Institute, Argonne National Lab, and Rice University| -//| October 31, 1999. | -//+------------------------------------------------------------------+ -static bool CBdSingValueDecompose::RMatrixBdSVD(double &d[],double &ce[], - const int n,const bool isupper, - const bool isfractionalaccuracyrequired, - CMatrixDouble &u,const int nru, - CMatrixDouble &c,const int ncc, - CMatrixDouble &vt,const int ncvt) - { -//--- create variables - bool result; -//--- create arrays - double d1[]; - double e1[]; - int i_=0; - int i1_=0; -//--- create copy - double e[]; - ArrayCopy(e,ce); -//--- allocation - ArrayResizeAL(d1,n+1); -//--- change values - i1_=-1; - for(i_=1;i_<=n;i_++) - d1[i_]=d[i_+i1_]; -//--- check - if(n>1) - { - //--- allocation - ArrayResizeAL(e1,n); - //--- change values - i1_=-1; - for(i_=1;i_0) - for(i_=vstart;i_<=vstart+ncvt-1;i_++) - vt[vstart].Set(i_,-1*vt[vstart][i_]); - } - //--- return result - return(result); - } -//--- initialization - ll=0; - oldsn=0; -//--- allocation - ArrayResizeAL(work0,n); - ArrayResizeAL(work1,n); - ArrayResizeAL(work2,n); - ArrayResizeAL(work3,n); - uend=ustart+(int)MathMax(nru-1,0); - vend=vstart+(int)MathMax(ncvt-1,0); - cend=cstart+(int)MathMax(ncc-1,0); - ArrayResizeAL(utemp,uend+1); - ArrayResizeAL(vttemp,vend+1); - ArrayResizeAL(ctemp,cend+1); -//--- initialization - maxitr=12; - rightside=true; - fwddir=true; -//--- resize E from N-1 to N - ArrayResizeAL(etemp,n+1); - for(i=1;i0) - { - //--- function call - CRotations::ApplyRotationsFromTheRight(fwddir,ustart,uend,1+ustart-1,n+ustart-1,work0,work1,u,utemp); - } - //--- check - if(ncc>0) - { - //--- function call - CRotations::ApplyRotationsFromTheLeft(fwddir,1+cstart-1,n+cstart-1,cstart,cend,work0,work1,c,ctemp); - } - } -//--- Compute singular values to relative accuracy TOL -//--- (By setting TOL to be negative, algorithm will compute -//--- singular values to absolute accuracy ABS(TOL)*norm(input matrix)) - tolmul=MathMax(10,MathMin(100,MathPow(eps,-0.125))); - tol=tolmul*eps; -//--- check - if(!isfractionalaccuracyrequired) - tol=-tol; -//--- Compute approximate maximum, minimum singular values - smax=0; - for(i=1;i<=n;i++) - smax=MathMax(smax,MathAbs(d[i])); - for(i=1;i=0.0) - { - //--- Relative accuracy desired - sminoa=MathAbs(d[1]); - //--- check - if(sminoa!=0.0) - { - mu=sminoa; - for(i=2;i<=n;i++) - { - mu=MathAbs(d[i])*(mu/(mu+MathAbs(e[i-1]))); - sminoa=MathMin(sminoa,mu); - //--- check - if(sminoa==0.0) - break; - } - } - //--- change values - sminoa=sminoa/MathSqrt(n); - thresh=MathMax(tol*sminoa,maxitr*n*n*unfl); - } - else - { - //--- Absolute accuracy desired - thresh=MathMax(MathAbs(tol)*smax,maxitr*n*n*unfl); - } -//--- Prepare for main iteration loop for the singular values -//--- (MAXIT is the maximum number of passes through the inner -//--- loop permitted before nonconvergence signalled.) - maxit=maxitr*n*n; - iter=0; - oldll=-1; - oldm=-1; -//--- M points to last element of unconverged part of matrix - m=n; -//--- Begin main iteration loop - while(true) - { - //--- Check for convergence or exceeding iteration count - if(m<=1) - break; - //--- check - if(iter>maxit) - return(false); - //--- Find diagonal block of matrix to work on - if(tol<0.0 && MathAbs(d[m])<=thresh) - d[m]=0; - //--- change values - smax=MathAbs(d[m]); - smin=smax; - matrixsplitflag=false; - for(lll=1;lll<=m-1;lll++) - { - ll=m-lll; - abss=MathAbs(d[ll]); - abse=MathAbs(e[ll]); - //--- check - if(tol<0.0 && abss<=thresh) - d[ll]=0; - //--- check - if(abse<=thresh) - { - matrixsplitflag=true; - break; - } - //--- change values - smin=MathMin(smin,abss); - smax=MathMax(smax,MathMax(abss,abse)); - } - //--- check - if(!matrixsplitflag) - ll=0; - else - { - //--- Matrix splits since E(LL) = 0 - e[ll]=0; - //--- check - if(ll==m-1) - { - //--- Convergence of bottom singular value, return to top of loop - m=m-1; - continue; - } - } - ll=ll+1; - //--- E(LL) through E(M-1) are nonzero, E(LL-1) is zero - if(ll==m-1) - { - //--- 2 by 2 block, handle separately - SVDV2x2(d[m-1],e[m-1],d[m],sigmn,sigmx,sinr,cosr,sinl,cosl); - d[m-1]=sigmx; - e[m-1]=0; - d[m]=sigmn; - //--- Compute singular vectors, if desired - if(ncvt>0) - { - mm0=m+(vstart-1); - mm1=m-1+(vstart-1); - //--- swap - for(i_=vstart;i_<=vend;i_++) - vttemp[i_]=cosr*vt[mm1][i_]; - for(i_=vstart;i_<=vend;i_++) - vttemp[i_]=vttemp[i_]+sinr*vt[mm0][i_]; - for(i_=vstart;i_<=vend;i_++) - vt[mm0].Set(i_,cosr*vt[mm0][i_]); - for(i_=vstart;i_<=vend;i_++) - vt[mm0].Set(i_,vt[mm0][i_]-sinr*vt[mm1][i_]); - for(i_=vstart;i_<=vend;i_++) - vt[mm1].Set(i_,vttemp[i_]); - } - //--- check - if(nru>0) - { - mm0=m+ustart-1; - mm1=m-1+ustart-1; - //--- swap - for(i_=ustart;i_<=uend;i_++) - utemp[i_]=cosl*u[i_][mm1]; - for(i_=ustart;i_<=uend;i_++) - utemp[i_]=utemp[i_]+sinl*u[i_][mm0]; - for(i_=ustart;i_<=uend;i_++) - u[i_].Set(mm0,cosl*u[i_][mm0]); - for(i_=ustart;i_<=uend;i_++) - u[i_].Set(mm0,u[i_][mm0]-sinl*u[i_][mm1]); - for(i_=ustart;i_<=uend;i_++) - u[i_].Set(mm1,utemp[i_]); - } - //--- check - if(ncc>0) - { - mm0=m+cstart-1; - mm1=m-1+cstart-1; - //--- swap - for(i_=cstart;i_<=cend;i_++) - ctemp[i_]=cosl*c[mm1][i_]; - for(i_=cstart;i_<=cend;i_++) - ctemp[i_]=ctemp[i_]+sinl*c[mm0][i_]; - for(i_=cstart;i_<=cend;i_++) - c[mm0].Set(i_,cosl*c[mm0][i_]); - for(i_=cstart;i_<=cend;i_++) - c[mm0].Set(i_,c[mm0][i_]-sinl*c[mm1][i_]); - for(i_=cstart;i_<=cend;i_++) - c[mm1].Set(i_,ctemp[i_]); - } - m=m-2; - continue; - } - //--- If working on new submatrix, choose shift direction - //--- (from larger end diagonal element towards smaller) - //--- Previously was - //--- "if (LL>OLDM) or (M - //--- Very strange that LAPACK still contains it. - bchangedir=false; - //--- check - if(idir==1 && MathAbs(d[ll])<1.0E-3*MathAbs(d[m])) - bchangedir=true; - //--- check - if(idir==2 && MathAbs(d[m])<1.0E-3*MathAbs(d[ll])) - bchangedir=true; - //--- check - if(ll!=oldll || m!=oldm || bchangedir) - { - //--- check - if(MathAbs(d[ll])>=MathAbs(d[m])) - { - //--- Chase bulge from top(big end) to bottom(small end) - idir=1; - } - else - { - //--- Chase bulge from bottom (big end) to top (small end) - idir=2; - } - } - //--- Apply convergence tests - if(idir==1) - { - //--- Run convergence test in forward direction - //--- First apply standard test to bottom of matrix - if(MathAbs(e[m-1])<=MathAbs(tol)*MathAbs(d[m]) || (tol<0.0 && MathAbs(e[m-1])<=thresh)) - { - e[m-1]=0; - continue; - } - //--- check - if(tol>=0.0) - { - //--- If relative accuracy desired, - //--- apply convergence criterion forward - mu=MathAbs(d[ll]); - sminl=mu; - iterflag=false; - for(lll=ll;lll<=m-1;lll++) - { - //--- check - if(MathAbs(e[lll])<=tol*mu) - { - e[lll]=0; - iterflag=true; - //--- break the cycle - break; - } - //--- change values - sminlo=sminl; - mu=MathAbs(d[lll+1])*(mu/(mu+MathAbs(e[lll]))); - sminl=MathMin(sminl,mu); - } - //--- check - if(iterflag) - continue; - } - } - else - { - //--- Run convergence test in backward direction - //--- First apply standard test to top of matrix - if(MathAbs(e[ll])<=MathAbs(tol)*MathAbs(d[ll]) || (tol<0.0 && MathAbs(e[ll])<=thresh)) - { - e[ll]=0; - continue; - } - //--- check - if(tol>=0.0) - { - //--- If relative accuracy desired, - //--- apply convergence criterion backward - mu=MathAbs(d[m]); - sminl=mu; - iterflag=false; - for(lll=m-1;lll>=ll;lll--) - { - //--- check - if(MathAbs(e[lll])<=(double)(tol*mu)) - { - e[lll]=0; - iterflag=true; - //--- break the cycle - break; - } - sminlo=sminl; - mu=MathAbs(d[lll])*(mu/(mu+MathAbs(e[lll]))); - sminl=MathMin(sminl,mu); - } - //--- check - if(iterflag) - continue; - } - } - //--- change values - oldll=ll; - oldm=m; - //--- Compute shift. First, test if shifting would ruin relative - //--- accuracy, and if so set the shift to zero. - if(tol>=0.0 && n*tol*(sminl/smax)<=MathMax(eps,0.01*tol)) - { - //--- Use a zero shift to avoid loss of relative accuracy - shift=0; - } - else - { - //--- Compute the shift from 2-by-2 block at end of matrix - if(idir==1) - { - sll=MathAbs(d[ll]); - SVD2x2(d[m-1],e[m-1],d[m],shift,r); - } - else - { - sll=MathAbs(d[m]); - SVD2x2(d[ll],e[ll],d[ll+1],shift,r); - } - //--- Test if shift negligible, and if so set to zero - if(sll>0.0) - { - //--- check - if(CMath::Sqr(shift/sll)ll) - e[i-1]=oldsn*r; - //--- function call - CRotations::GenerateRotation(oldcs*r,d[i+1]*sn,oldcs,oldsn,tmp); - //--- change values - d[i]=tmp; - work0[i-ll+1]=cs; - work1[i-ll+1]=sn; - work2[i-ll+1]=oldcs; - work3[i-ll+1]=oldsn; - } - //--- change values - h=d[m]*cs; - d[m]=h*oldcs; - e[m-1]=h*oldsn; - //--- Update singular vectors - if(ncvt>0) - { - //--- function call - CRotations::ApplyRotationsFromTheLeft(fwddir,ll+vstart-1,m+vstart-1,vstart,vend,work0,work1,vt,vttemp); - } - //--- check - if(nru>0) - { - //--- function call - CRotations::ApplyRotationsFromTheRight(fwddir,ustart,uend,ll+ustart-1,m+ustart-1,work2,work3,u,utemp); - } - //--- check - if(ncc>0) - { - //--- function call - CRotations::ApplyRotationsFromTheLeft(fwddir,ll+cstart-1,m+cstart-1,cstart,cend,work2,work3,c,ctemp); - } - //--- Check for convergence - if(MathAbs(e[m-1])<=thresh) - e[m-1]=0; - } - else - { - //--- Chase bulge from bottom to top - //--- Save cosines and sines for later singular vector updates - cs=1; - oldcs=1; - for(i=m;i>=ll+1;i--) - { - //--- function call - CRotations::GenerateRotation(d[i]*cs,e[i-1],cs,sn,r); - //--- check - if(i0) - { - //--- function call - CRotations::ApplyRotationsFromTheLeft(!fwddir,ll+vstart-1,m+vstart-1,vstart,vend,work2,work3,vt,vttemp); - } - //--- check - if(nru>0) - { - //--- function call - CRotations::ApplyRotationsFromTheRight(!fwddir,ustart,uend,ll+ustart-1,m+ustart-1,work0,work1,u,utemp); - } - //--- check - if(ncc>0) - { - //--- function call - CRotations::ApplyRotationsFromTheLeft(!fwddir,ll+cstart-1,m+cstart-1,cstart,cend,work0,work1,c,ctemp); - } - //--- Check for convergence - if(MathAbs(e[ll])<=thresh) - e[ll]=0; - } - } - else - { - //--- Use nonzero shift - if(idir==1) - { - //--- Chase bulge from top to bottom - //--- Save cosines and sines for later singular vector updates - f=(MathAbs(d[ll])-shift)*(ExtSignBdSQR(1,d[ll])+shift/d[ll]); - g=e[ll]; - for(i=ll;ill) - e[i-1]=r; - //--- change values - f=cosr*d[i]+sinr*e[i]; - e[i]=cosr*e[i]-sinr*d[i]; - g=sinr*d[i+1]; - d[i+1]=cosr*d[i+1]; - //--- function call - CRotations::GenerateRotation(f,g,cosl,sinl,r); - //--- change values - d[i]=r; - f=cosl*e[i]+sinl*d[i+1]; - d[i+1]=cosl*d[i+1]-sinl*e[i]; - //--- check - if(i0) - { - //--- function call - CRotations::ApplyRotationsFromTheLeft(fwddir,ll+vstart-1,m+vstart-1,vstart,vend,work0,work1,vt,vttemp); - } - //--- check - if(nru>0) - { - //--- function call - CRotations::ApplyRotationsFromTheRight(fwddir,ustart,uend,ll+ustart-1,m+ustart-1,work2,work3,u,utemp); - } - //--- check - if(ncc>0) - { - //--- function call - CRotations::ApplyRotationsFromTheLeft(fwddir,ll+cstart-1,m+cstart-1,cstart,cend,work2,work3,c,ctemp); - } - //--- Check for convergence - if(MathAbs(e[m-1])<=thresh) - e[m-1]=0; - } - else - { - //--- Chase bulge from bottom to top - //--- Save cosines and sines for later singular vector updates - f=(MathAbs(d[m])-shift)*(ExtSignBdSQR(1,d[m])+shift/d[m]); - g=e[m-1]; - for(i=m;i>=ll+1;i--) - { - //--- function call - CRotations::GenerateRotation(f,g,cosr,sinr,r); - //--- check - if(ill+1) - { - g=sinl*e[i-2]; - e[i-2]=cosl*e[i-2]; - } - //--- change values - work0[i-ll]=cosr; - work1[i-ll]=-sinr; - work2[i-ll]=cosl; - work3[i-ll]=-sinl; - } - e[ll]=f; - //--- Check for convergence - if(MathAbs(e[ll])<=thresh) - e[ll]=0; - //--- Update singular vectors if desired - if(ncvt>0) - { - //--- function call - CRotations::ApplyRotationsFromTheLeft(!fwddir,ll+vstart-1,m+vstart-1,vstart,vend,work2,work3,vt,vttemp); - } - //--- check - if(nru>0) - { - //--- function call - CRotations::ApplyRotationsFromTheRight(!fwddir,ustart,uend,ll+ustart-1,m+ustart-1,work0,work1,u,utemp); - } - //--- check - if(ncc>0) - { - //--- function call - CRotations::ApplyRotationsFromTheLeft(!fwddir,ll+cstart-1,m+cstart-1,cstart,cend,work0,work1,c,ctemp); - } - } - } - //--- QR iteration finished, go back and check convergence - continue; - } -//--- All singular values converged, so make them positive - for(i=1;i<=n;i++) - { - //--- check - if(d[i]<0.0) - { - d[i]=-d[i]; - //--- Change sign of singular vectors, if desired - if(ncvt>0) - { - for(i_=vstart;i_<=vend;i_++) - vt[i+vstart-1].Set(i_,-1*vt[i+vstart-1][i_]); - } - } - } -//--- Sort the singular values into decreasing order (insertion sort on -//--- singular values, but only one transposition per singular vector) - for(i=1;i0) - { - j=n+1-i; - //--- swap - for(i_=vstart;i_<=vend;i_++) - vttemp[i_]=vt[isub+vstart-1][i_]; - for(i_=vstart;i_<=vend;i_++) - vt[isub+vstart-1].Set(i_,vt[j+vstart-1][i_]); - for(i_=vstart;i_<=vend;i_++) - vt[j+vstart-1].Set(i_,vttemp[i_]); - } - if(nru>0) - { - j=n+1-i; - //--- swap - for(i_=ustart;i_<=uend;i_++) - utemp[i_]=u[i_][isub+ustart-1]; - for(i_=ustart;i_<=uend;i_++) - u[i_].Set(isub+ustart-1,u[i_][j+ustart-1]); - for(i_=ustart;i_<=uend;i_++) - u[i_].Set(j+ustart-1,utemp[i_]); - } - //--- check - if(ncc>0) - { - j=n+1-i; - //--- swap - for(i_=cstart;i_<=cend;i_++) - ctemp[i_]=c[isub+cstart-1][i_]; - for(i_=cstart;i_<=cend;i_++) - c[isub+cstart-1].Set(i_,c[j+cstart-1][i_]); - for(i_=cstart;i_<=cend;i_++) - c[j+cstart-1].Set(i_,ctemp[i_]); - } - } - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static double CBdSingValueDecompose::ExtSignBdSQR(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); - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static void CBdSingValueDecompose::SVD2x2(const double f,const double g, - const double h,double &ssmin, - double &ssmax) - { -//--- create variables - double aas=0; - double at=0; - double au=0; - double c=0; - double fa=0; - double fhmn=0; - double fhmx=0; - double ga=0; - double ha=0; -//--- initialization - ssmin=0; - ssmax=0; - fa=MathAbs(f); - ga=MathAbs(g); - ha=MathAbs(h); - fhmn=MathMin(fa,ha); - fhmx=MathMax(fa,ha); -//--- check - if(fhmn==0.0) - { - ssmin=0; - //--- check - if(fhmx==0.0) - ssmax=ga; - else - ssmax=MathMax(fhmx,ga)*MathSqrt(1+CMath::Sqr(MathMin(fhmx,ga)/MathMax(fhmx,ga))); - } - else - { - //--- check - if(gafa; -//--- check - if(swp) - { - //--- Now FA .ge. HA - pmax=3; - temp=ft; - ft=ht; - ht=temp; - temp=fa; - fa=ha; - ha=temp; - } - gt=g; - ga=MathAbs(gt); -//--- check - if(ga==0.0) - { - //--- Diagonal matrix - ssmin=ha; - ssmax=fa; - clt=1; - crt=1; - slt=0; - srt=0; - } - else - { - gasmal=true; - //--- check - if(ga>fa) - { - pmax=2; - //--- check - if(fa/ga1.0) - { - v=ga/ha; - ssmin=fa/v; - } - else - { - v=fa/ga; - ssmin=v*ha; - } - //--- change values - clt=1; - slt=ht/gt; - srt=1; - crt=ft/gt; - } - } - //--- check - if(gasmal) - { - //--- Normal case - d=fa-ha; - //--- check - if(d==fa) - l=1; - else - l=d/fa; - //--- change values - m=gt/ft; - t=2-l; - mm=m*m; - tt=t*t; - s=MathSqrt(tt+mm); - //--- check - if(l==0.0) - r=MathAbs(m); - else - r=MathSqrt(l*l+mm); - //--- change values - a=0.5*(s+r); - ssmin=ha/a; - ssmax=fa*a; - //--- check - if(mm==0.0) - { - //--- Note that M is very tiny - if(l==0.0) - t=ExtSignBdSQR(2,ft)*ExtSignBdSQR(1,gt); - else - t=gt/ExtSignBdSQR(d,ft)+m/t; - } - else - t=(m/(s+t)+m/(r+l))*(1+a); - //--- change values - l=MathSqrt(t*t+4); - crt=2/l; - srt=t/l; - clt=(crt+srt*m)/a; - v=ht/ft; - slt=v*srt/a; - } - } -//--- check - if(swp) - { - csl=srt; - snl=crt; - csr=slt; - snr=clt; - } - else - { - csl=clt; - snl=slt; - csr=crt; - snr=srt; - } -//--- Correct signs of SSMAX and SSMIN - if(pmax==1) - tsign=ExtSignBdSQR(1,csr)*ExtSignBdSQR(1,csl)*ExtSignBdSQR(1,f); -//--- check - if(pmax==2) - tsign=ExtSignBdSQR(1,snr)*ExtSignBdSQR(1,csl)*ExtSignBdSQR(1,g); -//--- check - if(pmax==3) - tsign=ExtSignBdSQR(1,snr)*ExtSignBdSQR(1,snl)*ExtSignBdSQR(1,h); -//--- get result - ssmax=ExtSignBdSQR(ssmax,tsign); - ssmin=ExtSignBdSQR(ssmin,tsign*ExtSignBdSQR(1,f)*ExtSignBdSQR(1,h)); - } -//+------------------------------------------------------------------+ -//| Singular value decomposition | -//+------------------------------------------------------------------+ -class CSingValueDecompose - { -public: - //--- constructor, destructor - CSingValueDecompose(void); - ~CSingValueDecompose(void); - //--- method - static bool RMatrixSVD(CMatrixDouble &ca,const int m,const int n,const int uneeded,const int vtneeded,const int additionalmemory,double &w[],CMatrixDouble &u,CMatrixDouble &vt); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CSingValueDecompose::CSingValueDecompose(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSingValueDecompose::~CSingValueDecompose(void) - { - - } -//+------------------------------------------------------------------+ -//| Singular value decomposition of a rectangular matrix. | -//| The algorithm calculates the singular value decomposition of a | -//| matrix of size MxN: A = U * S * V^T | -//| The algorithm finds the singular values and, optionally, matrices| -//| U and V^T. The algorithm can find both first min(M,N) columns of | -//| matrix U and rows of matrix V^T (singular vectors), and matrices | -//| U and V^T wholly (of sizes MxM and NxN respectively). | -//| Take into account that the subroutine does not return matrix V | -//| but V^T. | -//| Input parameters: | -//| A - matrix to be decomposed. | -//| Array whose indexes range within | -//| [0..M-1, 0..N-1]. | -//| M - number of rows in matrix A. | -//| N - number of columns in matrix A. | -//| UNeeded - 0, 1 or 2. See the description of the | -//| parameter U. | -//| VTNeeded - 0, 1 or 2. See the description of the | -//| parameter VT. | -//| AdditionalMemory - | -//| If the parameter: | -//| * equals 0, the algorithm doesn?t use | -//| additional memory (lower requirements, | -//| lower performance). | -//| * equals 1, the algorithm uses additional | -//| memory of size min(M,N)*min(M,N) of real | -//| numbers. It often speeds up the algorithm.| -//| * equals 2, the algorithm uses additional | -//| memory of size M*min(M,N) of real numbers.| -//| It allows to get a maximum performance. | -//| The recommended value of the parameter is 2. | -//| Output parameters: | -//| W - contains singular values in descending order.| -//| U - if UNeeded=0, U isn't changed, the left | -//| singular vectors are not calculated. | -//| if Uneeded=1, U contains left singular | -//| vectors (first min(M,N) columns of matrix U).| -//| Array whose indexes range within | -//| [0..M-1, 0..Min(M,N)-1]. if UNeeded=2, U | -//| contains matrix U wholly. Array whose indexes| -//| range within [0..M-1, 0..M-1]. | -//| VT - if VTNeeded=0, VT isn?t changed, the right | -//| singular vectors are not calculated. | -//| if VTNeeded=1, VT contains right singular | -//| vectors (first min(M,N) rows of matrix V^T). | -//| Array whose indexes range within | -//| [0..min(M,N)-1, 0..N-1]. if VTNeeded=2, VT | -//| contains matrix V^T wholly. Array whose | -//| indexes range within [0..N-1, 0..N-1]. | -//+------------------------------------------------------------------+ -static bool CSingValueDecompose::RMatrixSVD(CMatrixDouble &ca,const int m, - const int n,const int uneeded, - const int vtneeded, - const int additionalmemory, - double &w[],CMatrixDouble &u, - CMatrixDouble &vt) - { -//--- create variables - bool result; - bool isupper; - int minmn=0; - int ncu=0; - int nrvt=0; - int nru=0; - int ncvt=0; - int i=0; - int j=0; -//--- create arrays - double tauq[]; - double taup[]; - double tau[]; - double e[]; - double work[]; -//--- create matrix - CMatrixDouble t2; -//--- create copy - CMatrixDouble a; - a=ca; -//--- initialization - result=true; -//--- check - if(m==0 || n==0) - return(true); -//--- check - if(!CAp::Assert(uneeded>=0 && uneeded<=2,__FUNCTION__+": wrong parameters!")) - return(false); -//--- check - if(!CAp::Assert(vtneeded>=0 && vtneeded<=2,__FUNCTION__+": wrong parameters!")) - return(false); -//--- check - if(!CAp::Assert(additionalmemory>=0 && additionalmemory<=2,__FUNCTION__+": wrong parameters!")) - return(false); -//--- initialization - minmn=MathMin(m,n); - ArrayResizeAL(w,minmn+1); - ncu=0; - nru=0; -//--- check - if(uneeded==1) - { - nru=m; - ncu=minmn; - u.Resize(nru,ncu); - } -//--- check - if(uneeded==2) - { - nru=m; - ncu=m; - u.Resize(nru,ncu); - } - nrvt=0; - ncvt=0; -//--- check - if(vtneeded==1) - { - nrvt=minmn; - ncvt=n; - vt.Resize(nrvt,ncvt); - } -//--- check - if(vtneeded==2) - { - nrvt=n; - ncvt=n; - vt.Resize(nrvt,ncvt); - } -//--- M much larger than N -//--- Use bidiagonal reduction with QR-decomposition - if((double)(m)>(double)(1.6*n)) - { - //--- check - if(uneeded==0) - { - //-- No left singular vectors to be computed - COrtFac::RMatrixQR(a,m,n,tau); - for(i=0;i(double)(1.6*m)) - { - //--- check - if(vtneeded==0) - { - //--- No right singular vectors to be computed - COrtFac::RMatrixLQ(a,m,n,tau); - for(i=0;i<=m-1;i++) - { - for(j=i+1;j<=m-1;j++) - a[i].Set(j,0); - } - //--- function call - COrtFac::RMatrixBD(a,m,m,tauq,taup); - //--- function call - COrtFac::RMatrixBDUnpackQ(a,m,m,tauq,ncu,u); - //--- function call - COrtFac::RMatrixBDUnpackDiagonals(a,m,m,isupper,w,e); - ArrayResizeAL(work,m+1); - //--- function call - CBlas::InplaceTranspose(u,0,nru-1,0,ncu-1,work); - //--- get result - result=CBdSingValueDecompose::RMatrixBdSVD(w,e,m,isupper,false,a,0,u,nru,vt,0); - //--- function call - CBlas::InplaceTranspose(u,0,nru-1,0,ncu-1,work); - //--- return result - return(result); - } - else - { - //--- Right singular vectors (may be full matrix VT) to be computed - COrtFac::RMatrixLQ(a,m,n,tau); - //--- function call - COrtFac::RMatrixLQUnpackQ(a,m,n,tau,nrvt,vt); - for(i=0;i<=m-1;i++) - { - for(j=i+1;j<=m-1;j++) - a[i].Set(j,0); - } - //--- function call - COrtFac::RMatrixBD(a,m,m,tauq,taup); - //--- function call - COrtFac::RMatrixBDUnpackQ(a,m,m,tauq,ncu,u); - //--- function call - COrtFac::RMatrixBDUnpackDiagonals(a,m,m,isupper,w,e); - ArrayResizeAL(work,MathMax(m,n)+1); - //--- function call - CBlas::InplaceTranspose(u,0,nru-1,0,ncu-1,work); - //--- check - if(additionalmemory<1) - { - //--- No additional memory available - COrtFac::RMatrixBDMultiplyByP(a,m,m,taup,vt,m,n,false,true); - //--- get result - result=CBdSingValueDecompose::RMatrixBdSVD(w,e,m,isupper,false,a,0,u,nru,vt,n); - } - else - { - //--- Large VT. Transforming intermediate matrix T2 - COrtFac::RMatrixBDUnpackPT(a,m,m,taup,m,t2); - //--- get result - result=CBdSingValueDecompose::RMatrixBdSVD(w,e,m,isupper,false,a,0,u,nru,t2,m); - //--- function call - CBlas::CopyMatrix(vt,0,m-1,0,n-1,a,0,m-1,0,n-1); - //--- function call - CBlas::MatrixMatrixMultiply(t2,0,m-1,0,m-1,false,a,0,m-1,0,n-1,false,1.0,vt,0,m-1,0,n-1,0.0,work); - } - //--- function call - CBlas::InplaceTranspose(u,0,nru-1,0,ncu-1,work); - //--- return result - return(result); - } - } -//--- M<=N -//--- We can use inplace transposition of U to get rid of columnwise operations - if(m<=n) - { - //--- function call - COrtFac::RMatrixBD(a,m,n,tauq,taup); - //--- function call - COrtFac::RMatrixBDUnpackQ(a,m,n,tauq,ncu,u); - //--- function call - COrtFac::RMatrixBDUnpackPT(a,m,n,taup,nrvt,vt); - //--- function call - COrtFac::RMatrixBDUnpackDiagonals(a,m,n,isupper,w,e); - ArrayResizeAL(work,m+1); - //--- function call - CBlas::InplaceTranspose(u,0,nru-1,0,ncu-1,work); - //--- get result - result=CBdSingValueDecompose::RMatrixBdSVD(w,e,minmn,isupper,false,a,0,u,nru,vt,ncvt); - //--- function call - CBlas::InplaceTranspose(u,0,nru-1,0,ncu-1,work); - //--- return result - return(result); - } -//--- Simple bidiagonal reduction - COrtFac::RMatrixBD(a,m,n,tauq,taup); -//--- function call - COrtFac::RMatrixBDUnpackQ(a,m,n,tauq,ncu,u); -//--- function call - COrtFac::RMatrixBDUnpackPT(a,m,n,taup,nrvt,vt); -//--- function call - COrtFac::RMatrixBDUnpackDiagonals(a,m,n,isupper,w,e); -//--- check - if(additionalmemory<2 || uneeded==0) - { - //--- We cant use additional memory or there is no need in such operations - result=CBdSingValueDecompose::RMatrixBdSVD(w,e,minmn,isupper,false,u,nru,a,0,vt,ncvt); - } - else - { - //--- We can use additional memory - t2.Resize(minmn,m); - //--- function call - CBlas::CopyAndTranspose(u,0,m-1,0,minmn-1,t2,0,minmn-1,0,m-1); - //--- get result - result=CBdSingValueDecompose::RMatrixBdSVD(w,e,minmn,isupper,false,u,0,t2,m,vt,ncvt); - //--- function call - CBlas::CopyAndTranspose(t2,0,minmn-1,0,m-1,u,0,m-1,0,minmn-1); - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Structure which stores state of linear CG solver between | -//| subsequent calls of FBLSCgIteration(). Initialized with | -//| FBLSCGCreate(). | -//| USAGE: | -//| 1. call to FBLSCGCreate() | -//| 2. F:=FBLSCgIteration(State) | -//| 3. if F is False, iterations are over | -//| 4. otherwise, fill State.AX with A*x, State.XAX with x'*A*x | -//| 5. goto 2 | -//| If you want to rerminate iterations, pass zero or negative value | -//| to XAX. | -//| FIELDS: | -//| E1 - 2-norm of residual at the start | -//| E2 - 2-norm of residual at the end | -//| X - on return from FBLSCgIteration() it contains | -//| vector for matrix-vector product | -//| AX - must be filled with A*x if FBLSCgIteration() | -//| returned True | -//| XAX - must be filled with x'*A*x | -//| XK - contains result (if FBLSCgIteration() returned | -//| False) | -//| Other fields are private and should not be used by outsiders. | -//+------------------------------------------------------------------+ -class CFblsLinCgState - { -public: - //--- variables - double m_e1; - double m_e2; - double m_x[]; - double m_ax[]; - double m_xax; - double m_xk[]; - int m_n; - double m_rk[]; - double m_rk1[]; - double m_xk1[]; - double m_pk[]; - double m_pk1[]; - double m_b[]; - RCommState m_rstate; - double m_tmp2[]; - //--- constructor, destructor - CFblsLinCgState(void); - ~CFblsLinCgState(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CFblsLinCgState::CFblsLinCgState(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CFblsLinCgState::~CFblsLinCgState(void) - { - - } -//+------------------------------------------------------------------+ -//| Fast basic linear solutions | -//+------------------------------------------------------------------+ -class CFbls - { -private: - //--- auxiliary functions for FblsCGiteration - static void Func_lbl_rcomm(CFblsLinCgState &state,int n,int k,double rk2,double rk12,double pap,double s,double betak,double v1,double v2); - static bool Func_lbl_3(CFblsLinCgState &state,int &n,int &k,double &rk2,double &rk12,double &pap,double &s,double &betak,double &v1,double &v2); - static bool Func_lbl_5(CFblsLinCgState &state,int &n,int &k,double &rk2,double &rk12,double &pap,double &s,double &betak,double &v1,double &v2); -public: - //--- constructor, destructor - CFbls(void); - ~CFbls(void); - //--- methods - static void FblsCholeskySolve(CMatrixDouble &cha,const double sqrtscalea,const int n,const bool isupper,double &xb[],double &tmp[]); - static void FblsSolveCGx(CMatrixDouble &a,const int m,const int n,const double alpha,const double &b[],double &x[],double &buf[]); - static void FblsCGCreate(double &x[],double &b[],const int n,CFblsLinCgState &state); - static bool FblsCGIteration(CFblsLinCgState &state); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CFbls::CFbls(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CFbls::~CFbls(void) - { - - } -//+------------------------------------------------------------------+ -//| Basic Cholesky solver for ScaleA*Cholesky(A)'*x = y. | -//| This subroutine assumes that: | -//| * A*ScaleA is well scaled | -//| * A is well-conditioned, so no zero divisions or overflow may | -//| occur | -//| INPUT PARAMETERS: | -//| CHA - Cholesky decomposition of A | -//| SqrtScaleA- square root of scale factor ScaleA | -//| N - matrix size | -//| IsUpper - storage type | -//| XB - right part | -//| Tmp - buffer; function automatically allocates it, if | -//| it is too small. It can be reused if function is | -//| called several times. | -//| OUTPUT PARAMETERS: | -//| XB - solution | -//| NOTES: no assertion or tests are done during algorithm operation | -//+------------------------------------------------------------------+ -static void CFbls::FblsCholeskySolve(CMatrixDouble &cha,const double sqrtscalea, - const int n,const bool isupper,double &xb[], - double &tmp[]) - { -//--- create variables - int i=0; - double v=0; - int i_=0; -//--- check - if(CAp::Len(tmp)=0;i--) - { - //--- check - if(i0) - { - for(i_=0;i_=0;i--) - { - xb[i]=xb[i]/(sqrtscalea*cha[i][i]); - //--- check - if(i>0) - { - v=xb[i]; - for(i_=0;i_0 is a scalar | -//| * I is NxN identity matrix | -//| * b is Nx1 vector | -//| * X is Nx1 unknown vector. | -//| N iterations of linear conjugate gradient are used to solve | -//| problem. | -//| INPUT PARAMETERS: | -//| A - array[M,N], matrix | -//| M - number of rows | -//| N - number of unknowns | -//| B - array[N], right part | -//| X - initial approxumation, array[N] | -//| Buf - buffer; function automatically allocates it, if it | -//| is too small. It can be reused if function is called | -//| several times with same M and N. | -//| OUTPUT PARAMETERS: | -//| X - improved solution | -//| NOTES: | -//| * solver checks quality of improved solution. If (because of | -//| problem condition number, numerical noise, etc.) new solution| -//| is WORSE than original approximation, then original | -//| approximation is returned. | -//| * solver assumes that both A, B, Alpha are well scaled (i.e. | -//| they are less than sqrt(overflow) and greater than | -//| sqrt(underflow)). | -//+------------------------------------------------------------------+ -static void CFbls::FblsSolveCGx(CMatrixDouble &a,const int m,const int n, - const double alpha,const double &b[], - double &x[],double &buf[]) - { -//--- create variables - int k=0; - int offsrk=0; - int offsrk1=0; - int offsxk=0; - int offsxk1=0; - int offspk=0; - int offspk1=0; - int offstmp1=0; - int offstmp2=0; - int bs=0; - double e1=0; - double e2=0; - double rk2=0; - double rk12=0; - double pap=0; - double s=0; - double betak=0; - double v1=0; - double v2=0; - int i_=0; - int i1_=0; -//--- Test for special case: B=0 - v1=0.0; - for(i_=0;i_=0) - { - //--- initialization - n=state.m_rstate.ia[0]; - k=state.m_rstate.ia[1]; - rk2=state.m_rstate.ra[0]; - rk12=state.m_rstate.ra[1]; - pap=state.m_rstate.ra[2]; - s=state.m_rstate.ra[3]; - betak=state.m_rstate.ra[4]; - v1=state.m_rstate.ra[5]; - v2=state.m_rstate.ra[6]; - } - else - { - //--- initialization - n=-983; - k=-989; - rk2=-834; - rk12=900; - pap=-287; - s=364; - betak=214; - v1=-338; - v2=-686; - } -//--- check - if(state.m_rstate.stage==0) - { - //--- copy - for(i_=0;i_n-1) - return(Func_lbl_5(state,n,k,rk2,rk12,pap,s,betak,v1,v2)); -//--- Calculate A*p(k) - store in State.Tmp2 -//--- and p(k)'*A*p(k) - store in PAP -//--- If PAP=0,break (iteration is over) - for(int i_=0;i_=1,__FUNCTION__+": N<1!")) - return(EMPTY_VALUE); -//--- check - if(!CAp::Assert(CAp::Len(pivots)>=n,__FUNCTION__+": Pivots array is too short!")) - return(EMPTY_VALUE); -//--- check - if(!CAp::Assert(CAp::Rows(a)>=n,__FUNCTION__+": rows(A)=n,__FUNCTION__+": cols(A)=1,__FUNCTION__+": N<1!")) - return(EMPTY_VALUE); -//--- check - if(!CAp::Assert(CAp::Rows(a)>=n,__FUNCTION__+": rows(A)=n,__FUNCTION__+": cols(A)=1,__FUNCTION__+": N<1!")) - return(EMPTY_VALUE); -//--- check - if(!CAp::Assert(CAp::Len(pivots)>=n,__FUNCTION__+": Pivots array is too short!")) - return(EMPTY_VALUE); -//--- check - if(!CAp::Assert(CAp::Rows(a)>=n,__FUNCTION__+": rows(A)=n,__FUNCTION__+": cols(A)=1,__FUNCTION__+": N<1!")) - return(EMPTY_VALUE); -//--- check - if(!CAp::Assert(CAp::Rows(a)>=n,__FUNCTION__+": rows(A)=n,__FUNCTION__+": cols(A)=1,__FUNCTION__+": N<1!")) - return(EMPTY_VALUE); -//--- check - if(!CAp::Assert(CAp::Rows(a)>=n,__FUNCTION__+": rows(A)=n,__FUNCTION__+": cols(A)=1,__FUNCTION__+": N<1!")) - return(EMPTY_VALUE); -//--- check - if(!CAp::Assert(CAp::Rows(a)>=n,__FUNCTION__+": rows(A)=n,__FUNCTION__+": cols(A)0,__FUNCTION__+": N<=0!")) - return(false); -//--- check - if(!CAp::Assert(problemtype==1 || problemtype==2 || problemtype==3,__FUNCTION__+": incorrect ProblemType!")) - return(false); -//--- initialization - result=true; -//--- Problem 1: A*x = lambda*B*x -//--- Reducing to: -//--- C*y = lambda*y -//--- C = L^(-1) * A * L^(-T) -//--- x = L^(-T) * y - if(problemtype==1) - { - //--- Factorize B in T: B = LL' - t.Resize(n,n); - //--- check - if(isupperb) - { - for(i=0;i=0 && updrow=0 && updcolumn=0. | -//| Output parameters: | -//| A - contains matrix T. | -//| Array whose indexes range within [0..N-1, 0..N-1]. | -//| S - contains Schur vectors. | -//| Array whose indexes range within [0..N-1, 0..N-1]. | -//| Note 1: | -//| The block structure of matrix T can be easily recognized: | -//| since all the elements below the blocks are zeros, the | -//| elements a[i+1,i] which are equal to 0 show the block border.| -//| Note 2: | -//| The algorithm performance depends on the value of the | -//| internal parameter NS of the InternalSchurDecomposition | -//| subroutine which defines the number of shifts in the QR | -//| algorithm (similarly to the block width in block-matrix | -//| algorithms in linear algebra). If you require maximum | -//| performance on your machine, it is recommended to adjust | -//| this parameter manually. | -//| Result: | -//| True, | -//| if the algorithm has converged and parameters A and S | -//| contain the result. | -//| False, | -//| if the algorithm has not converged. | -//| Algorithm implemented on the basis of the DHSEQR subroutine | -//| (LAPACK 3.0 library). | -//+------------------------------------------------------------------+ -static bool CSchur::RMatrixSchur(CMatrixDouble &a,const int n,CMatrixDouble &s) - { -//--- create variables - bool result; - int info=0; - int i=0; - int j=0; -//--- create arrays - double tau[]; - double wi[]; - double wr[]; -//--- create matrix - CMatrixDouble a1; - CMatrixDouble s1; -//--- Upper Hessenberg form of the 0-based matrix - COrtFac::RMatrixHessenberg(a,n,tau); - COrtFac::RMatrixHessenbergUnpackQ(a,n,tau,s); -//--- Convert from 0-based arrays to 1-based, -//--- then call InternalSchurDecomposition -//--- Awkward, of course, but Schur decompisiton subroutine -//--- is too complex to fix it. - a1.Resize(n+1,n+1); - s1.Resize(n+1,n+1); - for(i=1;i<=n;i++) - { - for(j=1;j<=n;j++) - { - a1[i].Set(j,a[i-1][j-1]); - s1[i].Set(j,s[i-1][j-1]); - } - } -//--- function call - CHsSchur::InternalSchurDecomposition(a1,n,1,1,wr,wi,s1,info); - result=info==0; -//--- convert from 1-based arrays to -based - for(i=1;i<=n;i++) - { - for(j=1;j<=n;j++) - { - a[i-1].Set(j-1,a1[i][j]); - s[i-1].Set(j-1,s1[i][j]); - } - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Alglib/matrix.mqh b/Include/Math/Alglib/matrix.mqh deleted file mode 100644 index 02bf07f..0000000 --- a/Include/Math/Alglib/matrix.mqh +++ /dev/null @@ -1,629 +0,0 @@ -//+------------------------------------------------------------------+ -//| matrix.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 "complex.mqh" -#include "arrayresize.mqh" -//+------------------------------------------------------------------+ -//| Rows (double) | -//+------------------------------------------------------------------+ -class CRowDouble - { -private: - double m_array[]; - -public: - CRowDouble(void); - ~CRowDouble(void); - //--- methods - int Size(void) const; - void Resize(const int n); - void Set(const int i,const double d); - //--- overloading - double operator[](const int i) const; - void operator=(const double &array[]); - void operator=(const CRowDouble &r); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CRowDouble::CRowDouble(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CRowDouble::~CRowDouble(void) - { - - } -//+------------------------------------------------------------------+ -//| Row size | -//+------------------------------------------------------------------+ -int CRowDouble::Size(void) const - { - return(ArraySize(m_array)); - } -//+------------------------------------------------------------------+ -//| Resize | -//+------------------------------------------------------------------+ -void CRowDouble::Resize(const int n) - { - ArrayResizeAL(m_array,n); - } -//+------------------------------------------------------------------+ -//| Set value | -//+------------------------------------------------------------------+ -void CRowDouble::Set(const int i,const double d) - { - m_array[i]=d; - } -//+------------------------------------------------------------------+ -//| Indexing operator | -//+------------------------------------------------------------------+ -double CRowDouble::operator[](const int i) const - { - return(m_array[i]); - } -//+------------------------------------------------------------------+ -//| Overloading (=) | -//+------------------------------------------------------------------+ -void CRowDouble::operator=(const double &array[]) - { - int size=ArraySize(array); -//--- check - if(size==0) - return; -//--- filling array - ArrayResizeAL(m_array,size); - for(int i=0;i0: | -//| * if given, only leading N elements of X are used| -//| * if not given, automatically determined from | -//| size of X | -//| X - starting point, array[0..N-1]. | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//+------------------------------------------------------------------+ -static void CMinCG::MinCGCreate(const int n,double &x[],CMinCGState &state) - { -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N too small!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)0: | -//| * if given, only leading N elements of X are | -//| used | -//| * if not given, automatically determined from | -//| size of X | -//| X - starting point, array[0..N-1]. | -//| DiffStep- differentiation step, >0 | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTES: | -//| 1. algorithm uses 4-point central formula for differentiation. | -//| 2. differentiation step along I-th axis is equal to | -//| DiffStep*S[I] where S[] is scaling vector which can be set by | -//| MinCGSetScale() call. | -//| 3. we recommend you to use moderate values of differentiation | -//| step. Too large step will result in too large truncation | -//| errors, while too small step will result in too large | -//| numerical errors. 1.0E-6 can be good value to start with. | -//| 4. Numerical differentiation is very inefficient - one gradient | -//| calculation needs 4*N function evaluations. This function will| -//| work for any N - either small (1...10), moderate (10...100) or| -//| large (100...). However, performance penalty will be too | -//| severe for any N's except for small ones. | -//| We should also say that code which relies on numerical | -//| differentiation is less robust and precise. L-BFGS needs | -//| exact gradient values. Imprecise gradient may slow down | -//| convergence, especially on highly nonlinear problems. | -//| Thus we recommend to use this function for fast prototyping | -//| on small- dimensional problems only, and to implement | -//| analytical gradient as soon as possible. | -//+------------------------------------------------------------------+ -static void CMinCG::MinCGCreateF(const int n,double &x[],const double diffstep, - CMinCGState &state) - { -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N too small!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)0.0,__FUNCTION__+": DiffStep is non-positive!")) - return; -//--- function call - MinCGInitInternal(n,diffstep,state); -//--- function call - MinCGRestartFrom(state,x); - } -//+------------------------------------------------------------------+ -//| This function sets stopping conditions for CG optimization | -//| algorithm. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| EpsG - >=0 | -//| The subroutine finishes its work if the condition| -//| |v|=0 | -//| The subroutine finishes its work if on k+1-th | -//| iteration the condition |F(k+1)-F(k)| <= | -//| <= EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. | -//| EpsX - >=0 | -//| The subroutine finishes its work if on k+1-th | -//| iteration the condition |v|<=EpsX is fulfilled, | -//| where: | -//| * |.| means Euclidian norm | -//| * v - scaled step vector, v[i]=dx[i]/s[i] | -//| * dx - ste pvector, dx=X(k+1)-X(k) | -//| * s - scaling coefficients set by MinCGSetScale()| -//| MaxIts - maximum number of iterations. If MaxIts=0, the | -//| number of iterations is unlimited. | -//| Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will| -//| lead to automatic stopping criterion selection (small EpsX). | -//+------------------------------------------------------------------+ -static void CMinCG::MinCGSetCond(CMinCGState &state,const double epsg, - const double epsf,double epsx,const int maxits) - { -//--- check - if(!CAp::Assert(CMath::IsFinite(epsg),__FUNCTION__+": EpsG is not finite number!")) - return; -//--- check - if(!CAp::Assert(epsg>=0.0,__FUNCTION__+": negative EpsG!")) - return; -//--- check - if(!CAp::Assert(CMath::IsFinite(epsf),__FUNCTION__+": EpsF is not finite number!")) - return; -//--- check - if(!CAp::Assert(epsf>=0.0,__FUNCTION__+": negative EpsF!")) - return; -//--- check - if(!CAp::Assert(CMath::IsFinite(epsx),__FUNCTION__+": EpsX is not finite number!")) - return; -//--- check - if(!CAp::Assert(epsx>=0.0,__FUNCTION__+": negative EpsX!")) - return; -//--- check - if(!CAp::Assert(maxits>=0,__FUNCTION__+": negative MaxIts!")) - return; -//--- check - if(epsg==0.0 && epsf==0.0 && epsx==0.0 && maxits==0) - epsx=1.0E-6; -//--- change values - state.m_epsg=epsg; - state.m_epsf=epsf; - state.m_epsx=epsx; - state.m_maxits=maxits; - } -//+------------------------------------------------------------------+ -//| This function sets scaling coefficients for CG optimizer. | -//| ALGLIB optimizers use scaling matrices to test stopping | -//| conditions (step size and gradient are scaled before comparison | -//| with tolerances). Scale of the I-th variable is a translation | -//| invariant measure of: | -//| a) "how large" the variable is | -//| b) how large the step should be to make significant changes in | -//| the function | -//| Scaling is also used by finite difference variant of CG | -//| optimizer - step along I-th axis is equal to DiffStep*S[I]. | -//| In most optimizers (and in the CG too) scaling is NOT a form of | -//| preconditioning. It just affects stopping conditions. You should | -//| set preconditioner by separate call to one of the | -//| MinCGSetPrec...() functions. | -//| There is special preconditioning mode, however, which uses | -//| scaling coefficients to form diagonal preconditioning matrix. | -//| You can turn this mode on, if you want. But you should understand| -//| that scaling is not the same thing as preconditioning - these are| -//| two different, although related forms of tuning solver. | -//| INPUT PARAMETERS: | -//| State - structure stores algorithm state | -//| S - array[N], non-zero scaling coefficients | -//| S[i] may be negative, sign doesn't matter. | -//+------------------------------------------------------------------+ -static void CMinCG::MinCGSetScale(CMinCGState &state,double &s[]) - { -//--- create a variable - int i=0; -//--- check - if(!CAp::Assert(CAp::Len(s)>=state.m_n,__FUNCTION__+": Length(S)=-1 && cgtype<=1,__FUNCTION__+": incorrect CGType!")) - return; -//--- check - if(cgtype==-1) - cgtype=1; -//--- change value - state.m_cgtype=cgtype; - } -//+------------------------------------------------------------------+ -//| This function sets maximum step length | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| StpMax - maximum step length, >=0. Set StpMax to 0.0, if | -//| you don't want to limit step length. | -//| Use this subroutine when you optimize target function which | -//| contains exp() or other fast growing functions, and optimization | -//| algorithm makes too large steps which leads to overflow. This | -//| function allows us to reject steps that are too large (and | -//| therefore expose us to the possible overflow) without actually | -//| calculating function value at the x+stp*d. | -//+------------------------------------------------------------------+ -static void CMinCG::MinCGSetStpMax(CMinCGState &state,const double stpmax) - { -//--- check - if(!CAp::Assert(CMath::IsFinite(stpmax),__FUNCTION__+": StpMax is not finite!")) - return; -//--- check - if(!CAp::Assert(stpmax>=0.0,__FUNCTION__+": StpMax<0!")) - return; -//--- change value - state.m_stpmax=stpmax; - } -//+------------------------------------------------------------------+ -//| This function allows to suggest initial step length to the CG | -//| algorithm. | -//| Suggested step length is used as starting point for the line | -//| search. It can be useful when you have badly scaled problem, i.e.| -//| when ||grad|| (which is used as initial estimate for the first | -//| step) is many orders of magnitude different from the desired | -//| step. | -//| Line search may fail on such problems without good estimate of | -//| initial step length. Imagine, for example, problem with | -//| ||grad||=10^50 and desired step equal to 0.1 Line search | -//| function will use 10^50 as initial step, then it will decrease | -//| step length by 2 (up to 20 attempts) and will get 10^44, which is| -//| still too large. | -//| This function allows us to tell than line search should be | -//| started from some moderate step length, like 1.0, so algorithm | -//| will be able to detect desired step length in a several searches.| -//| Default behavior (when no step is suggested) is to use | -//| preconditioner, if it is available, to generate initial estimate | -//| of step length. | -//| This function influences only first iteration of algorithm. It | -//| should be called between MinCGCreate/MinCGRestartFrom() call and | -//| MinCGOptimize call. Suggested step is ignored if you have | -//| preconditioner. | -//| INPUT PARAMETERS: | -//| State - structure used to store algorithm state. | -//| Stp - initial estimate of the step length. | -//| Can be zero (no estimate). | -//+------------------------------------------------------------------+ -static void CMinCG::MinCGSuggestStep(CMinCGState &state,const double stp) - { -//--- check - if(!CAp::Assert(CMath::IsFinite(stp),__FUNCTION__+": Stp is infinite or NAN")) - return; -//--- check - if(!CAp::Assert(stp>=0.0,__FUNCTION__+": Stp<0")) - return; -//--- change value - state.m_suggestedstep=stp; - } -//+------------------------------------------------------------------+ -//| Modification of the preconditioner: preconditioning is turned | -//| off. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTE: you can change preconditioner "on the fly", during | -//| algorithm iterations. | -//+------------------------------------------------------------------+ -static void CMinCG::MinCGSetPrecDefault(CMinCGState &state) - { -//--- change values - state.m_prectype=0; - state.m_innerresetneeded=true; - } -//+------------------------------------------------------------------+ -//| Modification of the preconditioner: diagonal of approximate | -//| Hessian is used. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| D - diagonal of the approximate Hessian, | -//| array[0..N-1], (if larger, only leading N | -//| elements are used). | -//| NOTE: you can change preconditioner "on the fly", during | -//| algorithm iterations. | -//| NOTE 2: D[i] should be positive. Exception will be thrown | -//| otherwise. | -//| NOTE 3: you should pass diagonal of approximate Hessian - NOT | -//| ITS INVERSE. | -//+------------------------------------------------------------------+ -static void CMinCG::MinCGSetPrecDiag(CMinCGState &state,double &d[]) - { -//--- create a variable - int i=0; -//--- check - if(!CAp::Assert(CAp::Len(d)>=state.m_n,__FUNCTION__+": D is too short")) - return; - for(i=0;i<=state.m_n-1;i++) - { - //--- check - if(!CAp::Assert(CMath::IsFinite(d[i]),__FUNCTION__+": D contains infinite or NAN elements")) - return; - //--- check - if(!CAp::Assert((double)(d[i])>0.0,__FUNCTION__+": D contains non-positive elements")) - return; - } -//--- function call - MinCGSetPrecDiagFast(state,d); - } -//+------------------------------------------------------------------+ -//| Modification of the preconditioner: scale-based diagonal | -//| preconditioning. | -//| This preconditioning mode can be useful when you don't have | -//| approximate diagonal of Hessian, but you know that your variables| -//| are badly scaled (for example, one variable is in [1,10], and | -//| another in [1000,100000]), and most part of the ill-conditioning | -//| comes from different scales of vars. | -//| In this case simple scale-based preconditioner, | -//| with H[i] = 1/(s[i]^2), can greatly improve convergence. | -//| IMPRTANT: you should set scale of your variables with | -//| MinCGSetScale() call (before or after MinCGSetPrecScale() call). | -//| Without knowledge of the scale of your variables scale-based | -//| preconditioner will be just unit matrix. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTE: you can change preconditioner "on the fly", during | -//| algorithm iterations. | -//+------------------------------------------------------------------+ -static void CMinCG::MinCGSetPrecScale(CMinCGState &state) - { -//--- change values - state.m_prectype=3; - state.m_innerresetneeded=true; - } -//+------------------------------------------------------------------+ -//| Conjugate gradient results | -//| INPUT PARAMETERS: | -//| State - algorithm state | -//| OUTPUT PARAMETERS: | -//| X - array[0..N-1], solution | -//| Rep - optimization report: | -//| * Rep.TerminationType completetion code: | -//| * 1 relative function improvement is no | -//| more than EpsF. | -//| * 2 relative step is no more than EpsX. | -//| * 4 gradient norm is no more than EpsG | -//| * 5 MaxIts steps was taken | -//| * 7 stopping conditions are too | -//| stringent, further improvement is | -//| impossible, we return best X found | -//| so far | -//| * 8 terminated by user | -//| * Rep.IterationsCount contains iterations count | -//| * NFEV countains number of function calculations | -//+------------------------------------------------------------------+ -static void CMinCG::MinCGResults(CMinCGState &state,double &x[],CMinCGReport &rep) - { -//--- reset memory - ArrayResizeAL(x,0); -//--- function call - MinCGResultsBuf(state,x,rep); - } -//+------------------------------------------------------------------+ -//| Conjugate gradient results | -//| Buffered implementation of MinCGResults(), which uses | -//| pre-allocated buffer to store X[]. If buffer size is too small, | -//| it resizes buffer.It is intended to be used in the inner cycles | -//| of performance critical algorithms where array reallocation | -//| penalty is too large to be ignored. | -//+------------------------------------------------------------------+ -static void CMinCG::MinCGResultsBuf(CMinCGState &state,double &x[],CMinCGReport &rep) - { -//--- create a variable - int i_=0; -//--- check - if(CAp::Len(x)=state.m_n,__FUNCTION__+": Length(X)0 - for(i=0;i<=n-1;i++) - x[i]=x[i]/(state.m_diagh[i]+state.m_diaghl2[i]); -//--- if VCnt>0 - if(vcnt>0) - { - //--- calculation work0 - for(i=0;i<=vcnt-1;i++) - { - v=0.0; - for(i_=0;i_<=n-1;i_++) - v+=state.m_vcorr[i][i_]*x[i_]; - work0[i]=v; - } - //--- calculation work1 - for(i=0;i<=n-1;i++) - work1[i]=0; - for(i=0;i<=vcnt-1;i++) - { - v=work0[i]; - for(i_=0;i_<=n-1;i_++) - state.m_work1[i_]=state.m_work1[i_]+v*state.m_vcorr[i][i_]; - } - //--- change x - for(i=0;i<=n-1;i++) - x[i]=x[i]-state.m_work1[i]/(state.m_diagh[i]+state.m_diaghl2[i]); - } - } -//+------------------------------------------------------------------+ -//| This function calculates preconditioned product x'*H^(-1)*y. | -//| Work0[] and Work1[] are used as temporaries (size must be at | -//| least N; this function doesn't allocate arrays). | -//+------------------------------------------------------------------+ -static double CMinCG::PreconditionedMultiply2(CMinCGState &state,double &x[], - double &y[],double &work0[], - double &work1[]) - { -//--- create variables - double result=0; - int i=0; - int n=0; - int vcnt=0; - double v0=0; - double v1=0; - int i_=0; -//--- initialization - n=state.m_n; - vcnt=state.m_vcnt; -//--- no preconditioning - if(state.m_prectype==0) - { - v0=0.0; - for(i_=0;i_<=n-1;i_++) - v0+=x[i_]*y[i_]; - //--- return result - return(v0); - } -//--- check - if(state.m_prectype==3) - { - result=0; - for(i=0;i<=n-1;i++) - result=result+x[i]*state.m_s[i]*state.m_s[i]*y[i]; - //--- return result - return(result); - } -//--- check - if(!CAp::Assert(state.m_prectype==2,__FUNCTION__+": internal error (unexpected PrecType)")) - return(EMPTY_VALUE); -//--- low rank preconditioning - result=0.0; - for(i=0;i<=n-1;i++) - result=result+x[i]*y[i]/(state.m_diagh[i]+state.m_diaghl2[i]); -//--- check - if(vcnt>0) - { - //--- prepare arrays - for(i=0;i<=n-1;i++) - { - work0[i]=x[i]/(state.m_diagh[i]+state.m_diaghl2[i]); - work1[i]=y[i]/(state.m_diagh[i]+state.m_diaghl2[i]); - } - for(i=0;i<=vcnt-1;i++) - { - //--- calculation - v0=0.0; - for(i_=0;i_<=n-1;i_++) - v0+=work0[i_]*state.m_vcorr[i][i_]; - v1=0.0; - for(i_=0;i_<=n-1;i_++) - v1+=work1[i_]*state.m_vcorr[i][i_]; - //--- get result - result=result-v0*v1; - } - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Internal initialization subroutine | -//+------------------------------------------------------------------+ -static void CMinCG::MinCGInitInternal(const int n,const double diffstep, - CMinCGState &state) - { -//--- create a variable - int i=0; -//--- initialization - state.m_n=n; - state.m_diffstep=diffstep; -//--- function call - MinCGSetCond(state,0,0,0,0); -//--- function call - MinCGSetXRep(state,false); -//--- function call - MinCGSetDRep(state,false); -//--- function call - MinCGSetStpMax(state,0); -//--- function call - MinCGSetCGType(state,-1); -//--- function call - MinCGSetPrecDefault(state); -//--- allocation - ArrayResizeAL(state.m_xk,n); - ArrayResizeAL(state.m_dk,n); - ArrayResizeAL(state.m_xn,n); - ArrayResizeAL(state.m_dn,n); - ArrayResizeAL(state.m_x,n); - ArrayResizeAL(state.m_d,n); - ArrayResizeAL(state.m_g,n); - ArrayResizeAL(state.m_work0,n); - ArrayResizeAL(state.m_work1,n); - ArrayResizeAL(state.m_yk,n); - ArrayResizeAL(state.m_s,n); -//--- copy - for(i=0;i<=n-1;i++) - state.m_s[i]=1.0; - } -//+------------------------------------------------------------------+ -//| NOTES: | -//| 1. This function has two different implementations: one which | -//| uses exact (analytical) user-supplied gradient, and one which| -//| uses function value only and numerically differentiates | -//| function in order to obtain gradient. | -//| Depending on the specific function used to create optimizer | -//| object (either MinCGCreate() for analytical gradient or | -//| MinCGCreateF() for numerical differentiation) you should | -//| choose appropriate variant of MinCGOptimize() - one which | -//| accepts function AND gradient or one which accepts function | -//| ONLY. | -//| Be careful to choose variant of MinCGOptimize() which | -//| corresponds to your optimization scheme! Table below lists | -//| different combinations of callback (function/gradient) passed | -//| to MinCGOptimize() and specific function used to create | -//| optimizer. | -//| | USER PASSED TO MinCGOptimize() | -//| CREATED WITH | function only | function and gradient | -//| ------------------------------------------------------------ | -//| MinCGCreateF() | work FAIL | -//| MinCGCreate() | FAIL work | -//| Here "FAIL" denotes inappropriate combinations of optimizer | -//| creation function and MinCGOptimize() version. Attemps to use | -//| such combination (for example, to create optimizer with | -//| MinCGCreateF() and to pass gradient information to | -//| MinCGOptimize()) will lead to exception being thrown. Either | -//| you did not pass gradient when it WAS needed or you passed | -//| gradient when it was NOT needed. | -//+------------------------------------------------------------------+ -static bool CMinCG::MinCGIteration(CMinCGState &state) - { -//--- create variables - int n=0; - int i=0; - double betak=0; - double v=0; - double vv=0; - int i_=0; -//--- This code initializes locals by: -//--- * random values determined during code -//--- generation - on first subroutine call -//--- * values from previous call - on subsequent calls - if(state.m_rstate.stage>=0) - { - //--- initialization - n=state.m_rstate.ia[0]; - i=state.m_rstate.ia[1]; - betak=state.m_rstate.ra[0]; - v=state.m_rstate.ra[1]; - vv=state.m_rstate.ra[2]; - } - else - { - //--- initialization - n=-983; - i=-989; - betak=-834; - v=900; - vv=-287; - } -//--- check - if(state.m_rstate.stage==0) - { - //--- change value - state.m_needfg=false; - //--- function call, return result - return(Func_lbl_18(state,n,i,betak,v,vv)); - } -//--- check - if(state.m_rstate.stage==1) - { - //--- change values - state.m_fbase=state.m_f; - i=0; - //--- function call, return result - return(Func_lbl_19(state,n,i,betak,v,vv)); - } -//--- check - if(state.m_rstate.stage==2) - { - //--- change values - state.m_fm2=state.m_f; - state.m_x[i]=v-0.5*state.m_diffstep*state.m_s[i]; - state.m_rstate.stage=3; - //--- Saving state - Func_lbl_rcomm(state,n,i,betak,v,vv); - return(true); - } -//--- check - if(state.m_rstate.stage==3) - { - //--- change values - state.m_fm1=state.m_f; - state.m_x[i]=v+0.5*state.m_diffstep*state.m_s[i]; - state.m_rstate.stage=4; - //--- Saving state - Func_lbl_rcomm(state,n,i,betak,v,vv); - return(true); - } -//--- check - if(state.m_rstate.stage==4) - { - //--- change values - state.m_fp1=state.m_f; - state.m_x[i]=v+state.m_diffstep*state.m_s[i]; - state.m_rstate.stage=5; - //--- Saving state - Func_lbl_rcomm(state,n,i,betak,v,vv); - return(true); - } -//--- check - if(state.m_rstate.stage==5) - { - //--- change values - state.m_fp2=state.m_f; - state.m_x[i]=v; - state.m_g[i]=(8*(state.m_fp1-state.m_fm1)-(state.m_fp2-state.m_fm2))/(6*state.m_diffstep*state.m_s[i]); - i=i+1; - //--- function call, return result - return(Func_lbl_19(state,n,i,betak,v,vv)); - } -//--- check - if(state.m_rstate.stage==6) - { - //--- change value - state.m_algpowerup=false; - //--- function call, return result - return(Func_lbl_22(state,n,i,betak,v,vv)); - } -//--- check - if(state.m_rstate.stage==7) - { - //--- change value - state.m_xupdated=false; - //--- function call, return result - return(Func_lbl_24(state,n,i,betak,v,vv)); - } -//--- check - if(state.m_rstate.stage==8) - { - //--- change value - state.m_lsstart=false; - //--- function call, return result - return(Func_lbl_28(state,n,i,betak,v,vv)); - } -//--- check - if(state.m_rstate.stage==9) - { - //--- change value - state.m_needfg=false; - //--- function call, return result - return(Func_lbl_33(state,n,i,betak,v,vv)); - } -//--- check - if(state.m_rstate.stage==10) - { - //--- change values - state.m_fbase=state.m_f; - i=0; - //--- function call, return result - return(Func_lbl_34(state,n,i,betak,v,vv)); - } -//--- check - if(state.m_rstate.stage==11) - { - //--- change values - state.m_fm2=state.m_f; - state.m_x[i]=v-0.5*state.m_diffstep*state.m_s[i]; - state.m_rstate.stage=12; - //--- Saving state - Func_lbl_rcomm(state,n,i,betak,v,vv); - return(true); - } -//--- check - if(state.m_rstate.stage==12) - { - //--- change values - state.m_fm1=state.m_f; - state.m_x[i]=v+0.5*state.m_diffstep*state.m_s[i]; - state.m_rstate.stage=13; - //--- Saving state - Func_lbl_rcomm(state,n,i,betak,v,vv); - return(true); - } -//--- check - if(state.m_rstate.stage==13) - { - //--- change values - state.m_fp1=state.m_f; - state.m_x[i]=v+state.m_diffstep*state.m_s[i]; - state.m_rstate.stage=14; - //--- Saving state - Func_lbl_rcomm(state,n,i,betak,v,vv); - return(true); - } -//--- check - if(state.m_rstate.stage==14) - { - //--- change values - state.m_fp2=state.m_f; - state.m_x[i]=v; - state.m_g[i]=(8*(state.m_fp1-state.m_fm1)-(state.m_fp2-state.m_fm2))/(6*state.m_diffstep*state.m_s[i]); - i=i+1; - //--- function call, return result - return(Func_lbl_34(state,n,i,betak,v,vv)); - } -//--- check - if(state.m_rstate.stage==15) - { - //--- change value - state.m_lsend=false; - //--- function call, return result - return(Func_lbl_37(state,n,i,betak,v,vv)); - } -//--- check - if(state.m_rstate.stage==16) - { - //--- change value - state.m_xupdated=false; - //--- function call, return result - return(Func_lbl_39(state,n,i,betak,v,vv)); - } -//--- Routine body -//--- Prepare - n=state.m_n; - state.m_repterminationtype=0; - state.m_repiterationscount=0; - state.m_repnfev=0; - state.m_debugrestartscount=0; -//--- Preparations continue: -//--- * set XK -//--- * calculate F/G -//--- * set DK to -G -//--- * powerup algo (it may change preconditioner) -//--- * apply preconditioner to DK -//--- * report update of X -//--- * check stopping conditions for G - for(i_=0;i_<=n-1;i_++) - state.m_xk[i_]=state.m_x[i_]; -//--- change value - state.m_terminationneeded=false; -//--- function call - ClearRequestFields(state); -//--- check - if(state.m_diffstep!=0.0) - { - state.m_needf=true; - state.m_rstate.stage=1; - //--- Saving state - Func_lbl_rcomm(state,n,i,betak,v,vv); - //--- return result - return(true); - } -//--- change values - state.m_needfg=true; - state.m_rstate.stage=0; -//--- Saving state - Func_lbl_rcomm(state,n,i,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinCGIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static void CMinCG::Func_lbl_rcomm(CMinCGState &state,int n,int i, - double betak,double v,double vv) - { -//--- save - state.m_rstate.ia[0]=n; - state.m_rstate.ia[1]=i; - state.m_rstate.ra[0]=betak; - state.m_rstate.ra[1]=v; - state.m_rstate.ra[2]=vv; - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinCGIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinCG::Func_lbl_18(CMinCGState &state,int &n,int &i, - double &betak,double &v,double &vv) - { -//--- check - if(!state.m_drep) - return(Func_lbl_22(state,n,i,betak,v,vv)); -//--- Report algorithm powerup (if needed) - ClearRequestFields(state); -//--- change values - state.m_algpowerup=true; - state.m_rstate.stage=6; -//--- Saving state - Func_lbl_rcomm(state,n,i,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinCGIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinCG::Func_lbl_19(CMinCGState &state,int &n,int &i, - double &betak,double &v,double &vv) - { -//--- check - if(i>n-1) - { - state.m_f=state.m_fbase; - state.m_needf=false; - //--- function call, return result - return(Func_lbl_18(state,n,i,betak,v,vv)); - } -//--- change values - v=state.m_x[i]; - state.m_x[i]=v-state.m_diffstep*state.m_s[i]; - state.m_rstate.stage=2; -//--- Saving state - Func_lbl_rcomm(state,n,i,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinCGIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinCG::Func_lbl_22(CMinCGState &state,int &n,int &i, - double &betak,double &v,double &vv) - { -//--- function call - COptServ::TrimPrepare(state.m_f,state.m_trimthreshold); - for(int i_=0;i_<=n-1;i_++) - state.m_dk[i_]=-state.m_g[i_]; -//--- function call - PreconditionedMultiply(state,state.m_dk,state.m_work0,state.m_work1); -//--- check - if(!state.m_xrep) - return(Func_lbl_24(state,n,i,betak,v,vv)); -//--- function call - ClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_rstate.stage=7; -//--- Saving state - Func_lbl_rcomm(state,n,i,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinCGIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinCG::Func_lbl_24(CMinCGState &state,int &n,int &i, - double &betak,double &v,double &vv) - { -//--- check - if(state.m_terminationneeded) - { - for(int i_=0;i_<=n-1;i_++) - state.m_xn[i_]=state.m_xk[i_]; - state.m_repterminationtype=8; - //--- return result - return(false); - } -//--- change value - v=0; - for(i=0;i<=n-1;i++) - v=v+CMath::Sqr(state.m_g[i]*state.m_s[i]); -//--- check - if(MathSqrt(v)<=state.m_epsg) - { - for(int i_=0;i_<=n-1;i_++) - state.m_xn[i_]=state.m_xk[i_]; - state.m_repterminationtype=4; - //--- return result - return(false); - } -//--- change values - state.m_repnfev=1; - state.m_k=0; - state.m_fold=state.m_f; -//--- Choose initial step. -//--- Apply preconditioner,if we have something other than default. - if(state.m_prectype==2||state.m_prectype==3) - { - //--- because we use preconditioner,step length must be equal - //--- to the norm of DK - v=0.0; - for(int i_=0;i_<=n-1;i_++) - v+=state.m_dk[i_]*state.m_dk[i_]; - state.m_laststep=MathSqrt(v); - } - else - { - //--- No preconditioner is used,we try to use suggested step - if(state.m_suggestedstep>0.0) - state.m_laststep=state.m_suggestedstep; - else - { - //--- change value - v=0.0; - for(int i_=0;i_<=n-1;i_++) - v+=state.m_g[i_]*state.m_g[i_]; - v=MathSqrt(v); - //--- check - if(state.m_stpmax==0.0) - state.m_laststep=MathMin(1.0/v,1); - else - state.m_laststep=MathMin(1.0/v,state.m_stpmax); - } - } -//--- Main cycle - state.m_rstimer=m_rscountdownlen; -//--- function call, return result - return(Func_lbl_26(state,n,i,betak,v,vv)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinCGIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinCG::Func_lbl_26(CMinCGState &state,int &n,int &i, - double &betak,double &v,double &vv) - { -//--- * clear reset flag -//--- * clear termination flag -//--- * store G[k] for later calculation of Y[k] -//--- * prepare starting point and direction and step length for line search - state.m_innerresetneeded=false; - state.m_terminationneeded=false; - for(int i_=0;i_<=n-1;i_++) - state.m_yk[i_]=-state.m_g[i_]; - for(int i_=0;i_<=n-1;i_++) - state.m_d[i_]=state.m_dk[i_]; - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xk[i_]; -//--- change values - state.m_mcstage=0; - state.m_stp=1.0; -//--- function call - CLinMin::LinMinNormalized(state.m_d,state.m_stp,n); -//--- check - if(state.m_laststep!=0.0) - state.m_stp=state.m_laststep; - state.m_curstpmax=state.m_stpmax; -//--- Report beginning of line search (if needed) -//--- Terminate algorithm,if user request was detected - if(!state.m_drep) - return(Func_lbl_28(state,n,i,betak,v,vv)); -//--- function call - ClearRequestFields(state); -//--- change values - state.m_lsstart=true; - state.m_rstate.stage=8; -//--- Saving state - Func_lbl_rcomm(state,n,i,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinCGIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinCG::Func_lbl_28(CMinCGState &state,int &n,int &i, - double &betak,double &v,double &vv) - { -//--- check - if(state.m_terminationneeded) - { - for(int i_=0;i_<=n-1;i_++) - state.m_xn[i_]=state.m_x[i_]; - state.m_repterminationtype=8; - //--- return result - return(false); - } -//--- Minimization along D - CLinMin::MCSrch(n,state.m_x,state.m_f,state.m_g,state.m_d,state.m_stp,state.m_curstpmax,m_gtol,state.m_mcinfo,state.m_nfev,state.m_work0,state.m_lstate,state.m_mcstage); -//--- function call, return result - return(Func_lbl_30(state,n,i,betak,v,vv)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinCGIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinCG::Func_lbl_30(CMinCGState &state,int &n,int &i, - double &betak,double &v,double &vv) - { -//--- check - if(state.m_mcstage==0) - return(Func_lbl_31(state,n,i,betak,v,vv)); -//--- Calculate function/gradient using either -//--- analytical gradient supplied by user -//--- or finite difference approximation. -//--- "Trim" function in order to handle near-singularity points. - ClearRequestFields(state); -//--- check - if((double)(state.m_diffstep)!=0.0) - { - state.m_needf=true; - state.m_rstate.stage=10; - //--- Saving state - Func_lbl_rcomm(state,n,i,betak,v,vv); - //--- return result - return(true); - } -//--- change values - state.m_needfg=true; - state.m_rstate.stage=9; -//--- Saving state - Func_lbl_rcomm(state,n,i,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinCGIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinCG::Func_lbl_31(CMinCGState &state,int &n,int &i, - double &betak,double &v,double &vv) - { -//--- * report end of line search -//--- * store current point to XN -//--- * report iteration -//--- * terminate algorithm if user request was detected - if(!state.m_drep) - return(Func_lbl_37(state,n,i,betak,v,vv)); -//--- Report end of line search (if needed) - ClearRequestFields(state); -//--- change values - state.m_lsend=true; - state.m_rstate.stage=15; -//--- Saving state - Func_lbl_rcomm(state,n,i,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinCGIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinCG::Func_lbl_33(CMinCGState &state,int &n,int &i, - double &betak,double &v,double &vv) - { -//--- function call - COptServ::TrimFunction(state.m_f,state.m_g,n,state.m_trimthreshold); -//--- Call MCSRCH again - CLinMin::MCSrch(n,state.m_x,state.m_f,state.m_g,state.m_d,state.m_stp,state.m_curstpmax,m_gtol,state.m_mcinfo,state.m_nfev,state.m_work0,state.m_lstate,state.m_mcstage); -//--- function call, return result - return(Func_lbl_30(state,n,i,betak,v,vv)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinCGIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinCG::Func_lbl_34(CMinCGState &state,int &n,int &i, - double &betak,double &v,double &vv) - { -//--- check - if(i>n-1) - { - state.m_f=state.m_fbase; - state.m_needf=false; - //--- function call, return result - return(Func_lbl_33(state,n,i,betak,v,vv)); - } -//--- change values - v=state.m_x[i]; - state.m_x[i]=v-state.m_diffstep*state.m_s[i]; - state.m_rstate.stage=11; -//--- Saving state - Func_lbl_rcomm(state,n,i,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinCGIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinCG::Func_lbl_37(CMinCGState &state,int &n,int &i, - double &betak,double &v,double &vv) - { -//--- copy - for(int i_=0;i_<=n-1;i_++) - state.m_xn[i_]=state.m_x[i_]; -//--- check - if(!state.m_xrep) - return(Func_lbl_39(state,n,i,betak,v,vv)); -//--- function call - ClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_rstate.stage=16; -//--- Saving state - Func_lbl_rcomm(state,n,i,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinCGIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinCG::Func_lbl_39(CMinCGState &state,int &n,int &i, - double &betak,double &v,double &vv) - { -//--- check - if(state.m_terminationneeded) - { - for(int i_=0;i_<=n-1;i_++) - state.m_xn[i_]=state.m_x[i_]; - state.m_repterminationtype=8; - //--- return result - return(false); - } -//--- Line search is finished. -//--- * calculate BetaK -//--- * calculate DN -//--- * update timers -//--- * calculate step length - if(state.m_mcinfo==1 && !state.m_innerresetneeded) - { - //--- Standard Wolfe conditions hold - //--- Calculate Y[K] and D[K]'*Y[K] - for(int i_=0;i_<=n-1;i_++) - state.m_yk[i_]=state.m_yk[i_]+state.m_g[i_]; - //--- change value - vv=0.0; - for(int i_=0;i_<=n-1;i_++) - vv+=state.m_yk[i_]*state.m_dk[i_]; - //--- Calculate BetaK according to DY formula - v=PreconditionedMultiply2(state,state.m_g,state.m_g,state.m_work0,state.m_work1); - state.m_betady=v/vv; - //--- Calculate BetaK according to HS formula - v=PreconditionedMultiply2(state,state.m_g,state.m_yk,state.m_work0,state.m_work1); - state.m_betahs=v/vv; - //--- Choose BetaK - if(state.m_cgtype==0) - betak=state.m_betady; - //--- check - if(state.m_cgtype==1) - betak=MathMax(0,MathMin(state.m_betady,state.m_betahs)); - } - else - { - //--- Something is wrong (may be function is too wild or too flat) - //--- or we just have to restart algo. - //--- We'll set BetaK=0,which will restart CG algorithm. - //--- We can stop later (during normal checks) if stopping conditions are met. - betak=0; - state.m_debugrestartscount=state.m_debugrestartscount+1; - } -//--- check - if(state.m_repiterationscount>0&&state.m_repiterationscount%(3+n)==0) - { - //--- clear Beta every N iterations - betak=0; - } -//--- check - if(state.m_mcinfo==1||state.m_mcinfo==5) - state.m_rstimer=m_rscountdownlen; - else - state.m_rstimer=state.m_rstimer-1; - for(int i_=0;i_<=n-1;i_++) - state.m_dn[i_]=-state.m_g[i_]; -//--- function call - PreconditionedMultiply(state,state.m_dn,state.m_work0,state.m_work1); - for(int i_=0;i_<=n-1;i_++) - state.m_dn[i_]=state.m_dn[i_]+betak*state.m_dk[i_]; -//--- change values - state.m_laststep=0; - state.m_lastscaledstep=0.0; - for(i=0;i<=n-1;i++) - { - state.m_laststep=state.m_laststep+CMath::Sqr(state.m_d[i]); - state.m_lastscaledstep=state.m_lastscaledstep+CMath::Sqr(state.m_d[i]/state.m_s[i]); - } -//--- change values - state.m_laststep=state.m_stp*MathSqrt(state.m_laststep); - state.m_lastscaledstep=state.m_stp*MathSqrt(state.m_lastscaledstep); -//--- Update information. -//--- Check stopping conditions. - state.m_repnfev=state.m_repnfev+state.m_nfev; - state.m_repiterationscount=state.m_repiterationscount+1; -//--- check - if(state.m_repiterationscount>=state.m_maxits&&state.m_maxits>0) - { - //--- Too many iterations - state.m_repterminationtype=5; - //--- return result - return(false); - } -//--- change value - v=0; - for(i=0;i<=n-1;i++) - v=v+CMath::Sqr(state.m_g[i]*state.m_s[i]); -//--- check - if(MathSqrt(v)<=state.m_epsg) - { - //--- Gradient is small enough - state.m_repterminationtype=4; - //--- return result - return(false); - } -//--- check - if(!state.m_innerresetneeded) - { - //--- These conditions are checked only when no inner reset was requested by user - if(state.m_fold-state.m_f<=state.m_epsf*MathMax(MathAbs(state.m_fold),MathMax(MathAbs(state.m_f),1.0))) - { - //--- F(k+1)-F(k) is small enough - state.m_repterminationtype=1; - //--- return result - return(false); - } - //--- check - if(state.m_lastscaledstep<=state.m_epsx) - { - //--- X(k+1)-X(k) is small enough - state.m_repterminationtype=2; - //--- return result - return(false); - } - } -//--- check - if(state.m_rstimer<=0) - { - //--- Too many subsequent restarts - state.m_repterminationtype=7; - //--- return result - return(false); - } -//--- Shift Xk/Dk,update other information - for(int i_=0;i_<=n-1;i_++) - state.m_xk[i_]=state.m_xn[i_]; - for(int i_=0;i_<=n-1;i_++) - state.m_dk[i_]=state.m_dn[i_]; -//--- change values - state.m_fold=state.m_f; - state.m_k=state.m_k+1; -//--- function call, return result - return(Func_lbl_26(state,n,i,betak,v,vv)); - } -//+------------------------------------------------------------------+ -//| This object stores nonlinear optimizer state. | -//| You should use functions provided by MinBLEIC subpackage to work | -//| with this object | -//+------------------------------------------------------------------+ -class CMinBLEICState - { -public: - //--- variables - int m_nmain; - int m_nslack; - double m_innerepsg; - double m_innerepsf; - double m_innerepsx; - double m_outerepsx; - double m_outerepsi; - int m_maxits; - bool m_xrep; - double m_stpmax; - double m_diffstep; - int m_prectype; - double m_f; - bool m_needf; - bool m_needfg; - bool m_xupdated; - RCommState m_rstate; - int m_repinneriterationscount; - int m_repouteriterationscount; - int m_repnfev; - int m_repterminationtype; - double m_repdebugeqerr; - double m_repdebugfs; - double m_repdebugff; - double m_repdebugdx; - int m_itsleft; - double m_trimthreshold; - int m_cecnt; - int m_cedim; - double m_v0; - double m_v1; - double m_v2; - double m_t; - double m_errfeas; - double m_gnorm; - double m_mpgnorm; - double m_mba; - int m_variabletofreeze; - double m_valuetofreeze; - double m_fbase; - double m_fm2; - double m_fm1; - double m_fp1; - double m_fp2; - double m_xm1; - double m_xp1; - CMinCGState m_cgstate; - CMinCGReport m_cgrep; - int m_optdim; - //--- arrays - double m_diaghoriginal[]; - double m_diagh[]; - double m_x[]; - double m_g[]; - double m_xcur[]; - double m_xprev[]; - double m_xstart[]; - double m_xend[]; - double m_lastg[]; - int m_ct[]; - double m_xe[]; - bool m_hasbndl[]; - bool m_hasbndu[]; - double m_bndloriginal[]; - double m_bnduoriginal[]; - double m_bndleffective[]; - double m_bndueffective[]; - bool m_activeconstraints[]; - double m_constrainedvalues[]; - double m_transforms[]; - double m_seffective[]; - double m_soriginal[]; - double m_w[]; - double m_tmp0[]; - double m_tmp1[]; - double m_tmp2[]; - double m_r[]; - //--- matrix - CMatrixDouble m_ceoriginal; - CMatrixDouble m_ceeffective; - CMatrixDouble m_cecurrent; - CMatrixDouble m_lmmatrix; - //--- constructor, destructor - CMinBLEICState(void); - ~CMinBLEICState(void); - //--- copy - void Copy(CMinBLEICState &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinBLEICState::CMinBLEICState(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinBLEICState::~CMinBLEICState(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CMinBLEICState::Copy(CMinBLEICState &obj) - { -//--- copy variables - m_nmain=obj.m_nmain; - m_nslack=obj.m_nslack; - m_innerepsg=obj.m_innerepsg; - m_innerepsf=obj.m_innerepsf; - m_innerepsx=obj.m_innerepsx; - m_outerepsx=obj.m_outerepsx; - m_outerepsi=obj.m_outerepsi; - m_maxits=obj.m_maxits; - m_xrep=obj.m_xrep; - m_stpmax=obj.m_stpmax; - m_diffstep=obj.m_diffstep; - m_prectype=obj.m_prectype; - m_f=obj.m_f; - m_needf=obj.m_needf; - m_needfg=obj.m_needfg; - m_xupdated=obj.m_xupdated; - m_repinneriterationscount=obj.m_repinneriterationscount; - m_repouteriterationscount=obj.m_repouteriterationscount; - m_repnfev=obj.m_repnfev; - m_repterminationtype=obj.m_repterminationtype; - m_repdebugeqerr=obj.m_repdebugeqerr; - m_repdebugfs=obj.m_repdebugfs; - m_repdebugff=obj.m_repdebugff; - m_repdebugdx=obj.m_repdebugdx; - m_itsleft=obj.m_itsleft; - m_trimthreshold=obj.m_trimthreshold; - m_cecnt=obj.m_cecnt; - m_cedim=obj.m_cedim; - m_v0=obj.m_v0; - m_v1=obj.m_v1; - m_v2=obj.m_v2; - m_t=obj.m_t; - m_errfeas=obj.m_errfeas; - m_gnorm=obj.m_gnorm; - m_mpgnorm=obj.m_mpgnorm; - m_mba=obj.m_mba; - m_variabletofreeze=obj.m_variabletofreeze; - m_valuetofreeze=obj.m_valuetofreeze; - m_fbase=obj.m_fbase; - m_fm2=obj.m_fm2; - m_fm1=obj.m_fm1; - m_fp1=obj.m_fp1; - m_fp2=obj.m_fp2; - m_xm1=obj.m_xm1; - m_xp1=obj.m_xp1; - m_optdim=obj.m_optdim; - m_rstate.Copy(obj.m_rstate); - m_cgstate.Copy(obj.m_cgstate); - m_cgrep.Copy(obj.m_cgrep); -//--- copy arrays - ArrayCopy(m_diaghoriginal,obj.m_diaghoriginal); - ArrayCopy(m_diagh,obj.m_diagh); - ArrayCopy(m_x,obj.m_x); - ArrayCopy(m_g,obj.m_g); - ArrayCopy(m_xcur,obj.m_xcur); - ArrayCopy(m_xprev,obj.m_xprev); - ArrayCopy(m_xstart,obj.m_xstart); - ArrayCopy(m_xend,obj.m_xend); - ArrayCopy(m_lastg,obj.m_lastg); - ArrayCopy(m_ct,obj.m_ct); - ArrayCopy(m_xe,obj.m_xe); - ArrayCopy(m_hasbndl,obj.m_hasbndl); - ArrayCopy(m_hasbndu,obj.m_hasbndu); - ArrayCopy(m_bndloriginal,obj.m_bndloriginal); - ArrayCopy(m_bnduoriginal,obj.m_bnduoriginal); - ArrayCopy(m_bndleffective,obj.m_bndleffective); - ArrayCopy(m_bndueffective,obj.m_bndueffective); - ArrayCopy(m_activeconstraints,obj.m_activeconstraints); - ArrayCopy(m_constrainedvalues,obj.m_constrainedvalues); - ArrayCopy(m_transforms,obj.m_transforms); - ArrayCopy(m_seffective,obj.m_seffective); - ArrayCopy(m_soriginal,obj.m_soriginal); - ArrayCopy(m_w,obj.m_w); - ArrayCopy(m_tmp0,obj.m_tmp0); - ArrayCopy(m_tmp1,obj.m_tmp1); - ArrayCopy(m_tmp2,obj.m_tmp2); - ArrayCopy(m_r,obj.m_r); -//--- copy matrix - m_ceoriginal=obj.m_ceoriginal; - m_ceeffective=obj.m_ceeffective; - m_cecurrent=obj.m_cecurrent; - m_lmmatrix=obj.m_lmmatrix; - } -//+------------------------------------------------------------------+ -//| This object stores nonlinear optimizer state. | -//| You should use functions provided by MinBLEIC subpackage to work | -//| with this object | -//+------------------------------------------------------------------+ -class CMinBLEICStateShell - { -private: - CMinBLEICState m_innerobj; -public: - //--- constructors, destructor - CMinBLEICStateShell(void); - CMinBLEICStateShell(CMinBLEICState &obj); - ~CMinBLEICStateShell(void); - //--- methods - bool GetNeedF(void); - void SetNeedF(const bool b); - bool GetNeedFG(void); - void SetNeedFG(const bool b); - bool GetXUpdated(void); - void SetXUpdated(const bool b); - double GetF(void); - void SetF(const double d); - CMinBLEICState *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinBLEICStateShell::CMinBLEICStateShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CMinBLEICStateShell::CMinBLEICStateShell(CMinBLEICState &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinBLEICStateShell::~CMinBLEICStateShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable needf | -//+------------------------------------------------------------------+ -bool CMinBLEICStateShell::GetNeedF(void) - { -//--- return result - return(m_innerobj.m_needf); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable needf | -//+------------------------------------------------------------------+ -void CMinBLEICStateShell::SetNeedF(const bool b) - { -//--- change value - m_innerobj.m_needf=b; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable needfg | -//+------------------------------------------------------------------+ -bool CMinBLEICStateShell::GetNeedFG(void) - { -//--- return result - return(m_innerobj.m_needfg); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable needfg | -//+------------------------------------------------------------------+ -void CMinBLEICStateShell::SetNeedFG(const bool b) - { -//--- change value - m_innerobj.m_needfg=b; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable xupdated | -//+------------------------------------------------------------------+ -bool CMinBLEICStateShell::GetXUpdated(void) - { -//--- return result - return(m_innerobj.m_xupdated); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable xupdated | -//+------------------------------------------------------------------+ -void CMinBLEICStateShell::SetXUpdated(const bool b) - { -//--- change value - m_innerobj.m_xupdated=b; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable f | -//+------------------------------------------------------------------+ -double CMinBLEICStateShell::GetF(void) - { -//--- return result - return(m_innerobj.m_f); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable f | -//+------------------------------------------------------------------+ -void CMinBLEICStateShell::SetF(const double d) - { -//--- change value - m_innerobj.m_f=d; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CMinBLEICState *CMinBLEICStateShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| This structure stores optimization report: | -//| * InnerIterationsCount number of inner iterations | -//| * OuterIterationsCount number of outer iterations | -//| * NFEV number of gradient evaluations | -//| * TerminationType termination type (see below) | -//| TERMINATION CODES | -//| TerminationType field contains completion code,which can be: | -//| -10 unsupported combination of algorithm settings: | -//| 1) StpMax is set to non-zero value, | -//| AND 2) non-default preconditioner is used. | -//| You can't use both features at the same moment, | -//| so you have to choose one of them (and to turn | -//| off another one). | -//| -3 inconsistent constraints. Feasible point is | -//| either nonexistent or too hard to find. Try to | -//| restart optimizer with better initial | -//| approximation | -//| 4 conditions on constraints are fulfilled | -//| with error less than or equal to EpsC | -//| 5 MaxIts steps was taken | -//| 7 stopping conditions are too stringent, | -//| further improvement is impossible, | -//| X contains best point found so far. | -//| ADDITIONAL FIELDS | -//| There are additional fields which can be used for debugging: | -//| * DebugEqErr error in the equality constraints | -//| (2-norm) | -//| * DebugFS f,calculated at projection of initial| -//| point to the feasible set | -//| * DebugFF f,calculated at the final point | -//| * DebugDX |X_start-X_final| | -//+------------------------------------------------------------------+ -class CMinBLEICReport - { -public: - //--- variables - int m_inneriterationscount; - int m_outeriterationscount; - int m_nfev; - int m_terminationtype; - double m_debugeqerr; - double m_debugfs; - double m_debugff; - double m_debugdx; - //--- constructor, destructor - CMinBLEICReport(void); - ~CMinBLEICReport(void); - //--- copy - void Copy(CMinBLEICReport &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinBLEICReport::CMinBLEICReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinBLEICReport::~CMinBLEICReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CMinBLEICReport::Copy(CMinBLEICReport &obj) - { -//--- copy variables - m_inneriterationscount=obj.m_inneriterationscount; - m_outeriterationscount=obj.m_outeriterationscount; - m_nfev=obj.m_nfev; - m_terminationtype=obj.m_terminationtype; - m_debugeqerr=obj.m_debugeqerr; - m_debugfs=obj.m_debugfs; - m_debugff=obj.m_debugff; - m_debugdx=obj.m_debugdx; - } -//+------------------------------------------------------------------+ -//| This structure stores optimization report: | -//| * InnerIterationsCount number of inner iterations | -//| * OuterIterationsCount number of outer iterations | -//| * NFEV number of gradient evaluations | -//| * TerminationType termination type (see below) | -//| TERMINATION CODES | -//| TerminationType field contains completion code,which can be: | -//| -10 unsupported combination of algorithm settings: | -//| 1) StpMax is set to non-zero value, | -//| AND 2) non-default preconditioner is used. | -//| You can't use both features at the same moment, | -//| so you have to choose one of them (and to turn | -//| off another one). | -//| -3 inconsistent constraints. Feasible point is | -//| either nonexistent or too hard to find. Try to | -//| restart optimizer with better initial | -//| approximation | -//| 4 conditions on constraints are fulfilled | -//| with error less than or equal to EpsC | -//| 5 MaxIts steps was taken | -//| 7 stopping conditions are too stringent, | -//| further improvement is impossible, | -//| X contains best point found so far. | -//| ADDITIONAL FIELDS | -//| There are additional fields which can be used for debugging: | -//| * DebugEqErr error in the equality constraints | -//| (2-norm) | -//| * DebugFS f,calculated at projection of initial| -//| point to the feasible set | -//| * DebugFF f,calculated at the final point | -//| * DebugDX |X_start-X_final| | -//+------------------------------------------------------------------+ -class CMinBLEICReportShell - { -private: - CMinBLEICReport m_innerobj; -public: - //--- constructors, destructor - CMinBLEICReportShell(void); - CMinBLEICReportShell(CMinBLEICReport &obj); - ~CMinBLEICReportShell(void); - //--- methods - int GetInnerIterationsCount(void); - void SetInnerIterationsCount(const int i); - int GetOuterIterationsCount(void); - void SetOuterIterationsCount(const int i); - int GetNFev(void); - void SetNFev(const int i); - int GetTerminationType(void); - void SetTerminationType(const int i); - double GetDebugEqErr(void); - void SetDebugEqErr(const double d); - double GetDebugFS(void); - void SetDebugFS(const double d); - double GetDebugFF(void); - void SetDebugFF(const double d); - double GetDebugDX(void); - void SetDebugDX(const double d); - CMinBLEICReport *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinBLEICReportShell::CMinBLEICReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CMinBLEICReportShell::CMinBLEICReportShell(CMinBLEICReport &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinBLEICReportShell::~CMinBLEICReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable inneriterationscount | -//+------------------------------------------------------------------+ -int CMinBLEICReportShell::GetInnerIterationsCount(void) - { -//--- return result - return(m_innerobj.m_inneriterationscount); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable inneriterationscount | -//+------------------------------------------------------------------+ -void CMinBLEICReportShell::SetInnerIterationsCount(const int i) - { -//--- change value - m_innerobj.m_inneriterationscount=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable outeriterationscount | -//+------------------------------------------------------------------+ -int CMinBLEICReportShell::GetOuterIterationsCount(void) - { -//--- return result - return(m_innerobj.m_outeriterationscount); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable outeriterationscount | -//+------------------------------------------------------------------+ -void CMinBLEICReportShell::SetOuterIterationsCount(const int i) - { -//--- change value - m_innerobj.m_outeriterationscount=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable nfev | -//+------------------------------------------------------------------+ -int CMinBLEICReportShell::GetNFev(void) - { -//--- return result - return(m_innerobj.m_nfev); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable nfev | -//+------------------------------------------------------------------+ -void CMinBLEICReportShell::SetNFev(const int i) - { -//--- change value - m_innerobj.m_nfev=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable terminationtype | -//+------------------------------------------------------------------+ -int CMinBLEICReportShell::GetTerminationType(void) - { -//--- return result - return(m_innerobj.m_terminationtype); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable terminationtype | -//+------------------------------------------------------------------+ -void CMinBLEICReportShell::SetTerminationType(const int i) - { -//--- change value - m_innerobj.m_terminationtype=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable debugeqerr | -//+------------------------------------------------------------------+ -double CMinBLEICReportShell::GetDebugEqErr(void) - { -//--- return result - return(m_innerobj.m_debugeqerr); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable debugeqerr | -//+------------------------------------------------------------------+ -void CMinBLEICReportShell::SetDebugEqErr(const double d) - { -//--- change value - m_innerobj.m_debugeqerr=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable debugfs | -//+------------------------------------------------------------------+ -double CMinBLEICReportShell::GetDebugFS(void) - { -//--- return result - return(m_innerobj.m_debugfs); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable debugfs | -//+------------------------------------------------------------------+ -void CMinBLEICReportShell::SetDebugFS(const double d) - { -//--- change value - m_innerobj.m_debugfs=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable debugff | -//+------------------------------------------------------------------+ -double CMinBLEICReportShell::GetDebugFF(void) - { -//--- return result - return(m_innerobj.m_debugff); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable debugff | -//+------------------------------------------------------------------+ -void CMinBLEICReportShell::SetDebugFF(const double d) - { -//--- change value - m_innerobj.m_debugff=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable debugdx | -//+------------------------------------------------------------------+ -double CMinBLEICReportShell::GetDebugDX(void) - { -//--- return result - return(m_innerobj.m_debugdx); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable debugdx | -//+------------------------------------------------------------------+ -void CMinBLEICReportShell::SetDebugDX(const double d) - { -//--- change value - m_innerobj.m_debugdx=d; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CMinBLEICReport *CMinBLEICReportShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Bound constrained optimization with additional linear equality | -//| and inequality constraints | -//+------------------------------------------------------------------+ -class CMinBLEIC - { -private: - //--- private methods - static void ClearRequestFields(CMinBLEICState &state); - static void UnscalePoint(CMinBLEICState &state,double &xscaled[],double &xunscaled[]); - static void ProjectPointAndUnscale(CMinBLEICState &state,double &xscaled[],double &xunscaled[],double &rscaled[],double &rnorm2); - static void ScaleGradientAndExpand(CMinBLEICState &state,double &gunscaled[],double &gscaled[]); - static void ModifyTargetFunction(CMinBLEICState &state,double &x[],double &r[],const double rnorm2,double &f,double &g[],double &gnorm,double &mpgnorm); - static bool AdditionalCheckForConstraints(CMinBLEICState &state,double &x[]); - static void RebuildCEXE(CMinBLEICState &state); - static void MakeGradientProjection(CMinBLEICState &state,double &pg[]); - static bool PrepareConstraintMatrix(CMinBLEICState &state,double &x[],double &g[],double &px[],double &pg[]); - static void MinBLEICInitInternal(const int n,double &x[],const double diffstep,CMinBLEICState &state); - //--- auxiliary functions for MinBLEICIteration - static void Func_lbl_rcomm(CMinBLEICState &state,int nmain,int nslack,int m,int i,int j,bool b,double v,double vv); - static bool Func_lbl_14(CMinBLEICState &state,int &nmain,int &nslack,int &m,int &i,int &j,bool &b,double &v,double &vv); - static bool Func_lbl_15(CMinBLEICState &state,int &nmain,int &nslack,int &m,int &i,int &j,bool &b,double &v,double &vv); - static bool Func_lbl_16(CMinBLEICState &state,int &nmain,int &nslack,int &m,int &i,int &j,bool &b,double &v,double &vv); - static bool Func_lbl_17(CMinBLEICState &state,int &nmain,int &nslack,int &m,int &i,int &j,bool &b,double &v,double &vv); - static bool Func_lbl_18(CMinBLEICState &state,int &nmain,int &nslack,int &m,int &i,int &j,bool &b,double &v,double &vv); - static bool Func_lbl_19(CMinBLEICState &state,int &nmain,int &nslack,int &m,int &i,int &j,bool &b,double &v,double &vv); - static bool Func_lbl_22(CMinBLEICState &state,int &nmain,int &nslack,int &m,int &i,int &j,bool &b,double &v,double &vv); - static bool Func_lbl_23(CMinBLEICState &state,int &nmain,int &nslack,int &m,int &i,int &j,bool &b,double &v,double &vv); - static bool Func_lbl_31(CMinBLEICState &state,int &nmain,int &nslack,int &m,int &i,int &j,bool &b,double &v,double &vv); -public: - //--- class constants - static const double m_svdtol; - static const double m_maxouterits; - //--- constructor, destructor - CMinBLEIC(void); - ~CMinBLEIC(void); - //--- public methods - static void MinBLEICCreate(const int n,double &x[],CMinBLEICState &state); - static void MinBLEICCreateF(const int n,double &x[],const double diffstep,CMinBLEICState &state); - static void MinBLEICSetBC(CMinBLEICState &state,double &bndl[],double &bndu[]); - static void MinBLEICSetLC(CMinBLEICState &state,CMatrixDouble &c,int &ct[],const int k); - static void MinBLEICSetInnerCond(CMinBLEICState &state,const double epsg,const double epsf,const double epsx); - static void MinBLEICSetOuterCond(CMinBLEICState &state,const double epsx,const double epsi); - static void MinBLEICSetScale(CMinBLEICState &state,double &s[]); - static void MinBLEICSetPrecDefault(CMinBLEICState &state); - static void MinBLEICSetPrecDiag(CMinBLEICState &state,double &d[]); - static void MinBLEICSetPrecScale(CMinBLEICState &state); - static void MinBLEICSetMaxIts(CMinBLEICState &state,const int maxits); - static void MinBLEICSetXRep(CMinBLEICState &state,const bool needxrep); - static void MinBLEICSetStpMax(CMinBLEICState &state,const double stpmax); - static void MinBLEICResults(CMinBLEICState &state,double &x[],CMinBLEICReport &rep); - static void MinBLEICResultsBuf(CMinBLEICState &state,double &x[],CMinBLEICReport &rep); - static void MinBLEICRestartFrom(CMinBLEICState &state,double &x[]); - static bool MinBLEICIteration(CMinBLEICState &state); - }; -//+------------------------------------------------------------------+ -//| Initialize constants | -//+------------------------------------------------------------------+ -const double CMinBLEIC::m_svdtol=100; -const double CMinBLEIC::m_maxouterits=20; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinBLEIC::CMinBLEIC(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinBLEIC::~CMinBLEIC(void) - { - - } -//+------------------------------------------------------------------+ -//| BOUND CONSTRAINED OPTIMIZATION | -//| WITH ADDITIONAL LINEAR EQUALITY AND INEQUALITY CONSTRAINTS| -//| DESCRIPTION: | -//| The subroutine minimizes function F(x) of N arguments subject to | -//| any combination of: | -//| * bound constraints | -//| * linear inequality constraints | -//| * linear equality constraints | -//| REQUIREMENTS: | -//| * user must provide function value and gradient | -//| * starting point X0 must be feasible or | -//| not too far away from the feasible set | -//| * grad(f) must be Lipschitz continuous on a level set: | -//| L = { x : f(x)<=f(x0) } | -//| * function must be defined everywhere on the feasible set F | -//| USAGE: | -//| Constrained optimization if far more complex than the | -//| unconstrained one. Here we give very brief outline of the BLEIC | -//| optimizer. We strongly recommend you to read examples in the | -//| ALGLIB Reference Manual and to read ALGLIB User Guide on | -//| optimization, which is available at | -//| http://www.alglib.net/optimization/ | -//| 1. User initializes algorithm state with MinBLEICCreate() call | -//| 2. USer adds boundary and/or linear constraints by calling | -//| MinBLEICSetBC() and MinBLEICSetLC() functions. | -//| 3. User sets stopping conditions for underlying unconstrained | -//| solver with MinBLEICSetInnerCond() call. | -//| This function controls accuracy of underlying optimization | -//| algorithm. | -//| 4. User sets stopping conditions for outer iteration by calling | -//| MinBLEICSetOuterCond() function. | -//| This function controls handling of boundary and inequality | -//| constraints. | -//| 5. Additionally, user may set limit on number of internal | -//| iterations by MinBLEICSetMaxIts() call. | -//| This function allows to prevent algorithm from looping | -//| forever. | -//| 6. User calls MinBLEICOptimize() function which takes algorithm | -//| state and pointer (delegate, etc.) to callback function | -//| which calculates F/G. | -//| 7. User calls MinBLEICResults() to get solution | -//| 8. Optionally user may call MinBLEICRestartFrom() to solve | -//| another problem with same N but another starting point. | -//| MinBLEICRestartFrom() allows to reuse already initialized | -//| structure. | -//| INPUT PARAMETERS: | -//| N - problem dimension, N>0: | -//| * if given, only leading N elements of X are | -//| used | -//| * if not given, automatically determined from | -//| size ofX | -//| X - starting point, array[N]: | -//| * it is better to set X to a feasible point | -//| * but X can be infeasible, in which case | -//| algorithm will try to find feasible point | -//| first, using X as initial approximation. | -//| OUTPUT PARAMETERS: | -//| State - structure stores algorithm state | -//+------------------------------------------------------------------+ -static void CMinBLEIC::MinBLEICCreate(const int n,double &x[],CMinBLEICState &state) - { -//--- create matrix - CMatrixDouble c; -//--- create array - int ct[]; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)0: | -//| * if given, only leading N elements of X are used| -//| * if not given, automatically determined from | -//| size of X | -//| X - starting point, array[0..N-1]. | -//| DiffStep- differentiation step, >0 | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTES: | -//| 1. algorithm uses 4-point central formula for differentiation. | -//| 2. differentiation step along I-th axis is equal to DiffStep*S[I]| -//| where S[] is scaling vector which can be set by | -//| MinBLEICSetScale() call. | -//| 3. we recommend you to use moderate values of differentiation | -//| step. Too large step will result in too large truncation | -//| errors, while too small step will result in too large | -//| numerical errors. 1.0E-6 can be good value to start with. | -//| 4. Numerical differentiation is very inefficient - one gradient | -//| calculation needs 4*N function evaluations. This function will| -//| work for any N - either small (1...10), moderate (10...100) or| -//| large (100...). However, performance penalty will be too | -//| severe for any N's except for small ones. | -//| We should also say that code which relies on numerical | -//| differentiation is less robust and precise. CG needs exact | -//| gradient values. Imprecise gradient may slow down convergence,| -//| especially on highly nonlinear problems. | -//| Thus we recommend to use this function for fast prototyping on| -//| small - dimensional problems only, and to implement analytical| -//| gradient as soon as possible. | -//+------------------------------------------------------------------+ -static void CMinBLEIC::MinBLEICCreateF(const int n,double &x[], - const double diffstep, - CMinBLEICState &state) - { -//--- create matrix - CMatrixDouble c; -//--- create array - int ct[]; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)0.0,__FUNCTION__+": DiffStep is non-positive!")) - return; -//--- function call - MinBLEICInitInternal(n,x,diffstep,state); - } -//+------------------------------------------------------------------+ -//| This function sets boundary constraints for BLEIC optimizer. | -//| Boundary constraints are inactive by default (after initial | -//| creation). They are preserved after algorithm restart with | -//| MinBLEICRestartFrom(). | -//| INPUT PARAMETERS: | -//| State - structure stores algorithm state | -//| BndL - lower bounds, array[N]. | -//| If some (all) variables are unbounded, you may | -//| specify very small number or -INF. | -//| BndU - upper bounds, array[N]. | -//| If some (all) variables are unbounded, you may | -//| specify very large number or +INF. | -//| NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case | -//| I-th variable will be "frozen" at X[i]=BndL[i]=BndU[i]. | -//| NOTE 2: this solver has following useful properties: | -//| * bound constraints are always satisfied exactly | -//| * function is evaluated only INSIDE area specified by bound | -//| constraints, even when numerical differentiation is used | -//| (algorithm adjusts nodes according to boundary constraints) | -//+------------------------------------------------------------------+ -static void CMinBLEIC::MinBLEICSetBC(CMinBLEICState &state,double &bndl[], - double &bndu[]) - { -//--- create variables - int i=0; - int n=0; -//--- initialization - n=state.m_nmain; -//--- check - if(!CAp::Assert(CAp::Len(bndl)>=n,__FUNCTION__+": Length(BndL)=n,__FUNCTION__+": Length(BndU)0, then I-th constraint is | -//| C[i,*]*x >= C[i,n+1] | -//| * if CT[i]=0, then I-th constraint is | -//| C[i,*]*x = C[i,n+1] | -//| * if CT[i]<0, then I-th constraint is | -//| C[i,*]*x <= C[i,n+1] | -//| K - number of equality/inequality constraints, K>=0: | -//| * if given, only leading K elements of C/CT are | -//| used | -//| * if not given, automatically determined from | -//| sizes of C/CT | -//| NOTE 1: linear (non-bound) constraints are satisfied only | -//| approximately: | -//| * there always exists some minor violation (about Epsilon in | -//| magnitude) due to rounding errors | -//| * numerical differentiation, if used, may lead to function | -//| evaluations outside of the feasible area, because algorithm | -//| does NOT change numerical differentiation formula according to | -//| linear constraints. | -//| If you want constraints to be satisfied exactly, try to | -//| reformulate your problem in such manner that all constraints will| -//| become boundary ones (this kind of constraints is always | -//| satisfied exactly, both in the final solution and in all | -//| intermediate points). | -//+------------------------------------------------------------------+ -static void CMinBLEIC::MinBLEICSetLC(CMinBLEICState &state,CMatrixDouble &c, - int &ct[],const int k) - { -//--- create variables - int nmain=0; - int i=0; - int i_=0; -//--- initialization - nmain=state.m_nmain; -//--- First,check for errors in the inputs - if(!CAp::Assert(k>=0,__FUNCTION__+": K<0")) - return; -//--- check - if(!CAp::Assert(CAp::Cols(c)>=nmain+1||k==0,__FUNCTION__+": Cols(C)=k,__FUNCTION__+": Rows(C)=k,__FUNCTION__+": Length(CT)=0 | -//| The subroutine finishes its work if the condition| -//| |v|=0 | -//| The subroutine finishes its work if on k+1-th | -//| iteration the condition |F(k+1)-F(k)| <= | -//| <= EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. | -//| EpsX - >=0 | -//| The subroutine finishes its work if on k+1-th | -//| iteration the condition |v|<=EpsX is fulfilled, | -//| where: | -//| * |.| means Euclidian norm | -//| * v - scaled step vector, v[i]=dx[i]/s[i] | -//| * dx - ste pvector, dx=X(k+1)-X(k) | -//| * s - scaling coefficients set by | -//| MinBLEICSetScale() | -//| Passing EpsG=0, EpsF=0 and EpsX=0 (simultaneously) will lead to | -//| automatic stopping criterion selection. | -//| These conditions are used to terminate inner iterations. However,| -//| you need to tune termination conditions for outer iterations too.| -//+------------------------------------------------------------------+ -static void CMinBLEIC::MinBLEICSetInnerCond(CMinBLEICState &state,const double epsg, - const double epsf,const double epsx) - { -//--- check - if(!CAp::Assert(CMath::IsFinite(epsg),__FUNCTION__+": EpsG is not finite number")) - return; -//--- check - if(!CAp::Assert(epsg>=0.0,__FUNCTION__+": negative EpsG")) - return; -//--- check - if(!CAp::Assert(CMath::IsFinite(epsf),__FUNCTION__+": EpsF is not finite number")) - return; -//--- check - if(!CAp::Assert(epsf>=0.0,__FUNCTION__+": negative EpsF")) - return; -//--- check - if(!CAp::Assert(CMath::IsFinite(epsx),__FUNCTION__+": EpsX is not finite number")) - return; -//--- check - if(!CAp::Assert(epsx>=0.0,__FUNCTION__+": negative EpsX")) - return; -//--- change values - state.m_innerepsg=epsg; - state.m_innerepsf=epsf; - state.m_innerepsx=epsx; - } -//+------------------------------------------------------------------+ -//| This function sets stopping conditions for outer iteration of | -//| BLEIC algo. | -//| These conditions control accuracy of constraint handling and | -//| amount of infeasibility allowed in the solution. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| EpsX - >0, stopping condition on outer iteration step | -//| length | -//| EpsI - >0, stopping condition on infeasibility | -//| Both EpsX and EpsI must be non-zero. | -//| MEANING OF EpsX | -//| EpsX is a stopping condition for outer iterations. Algorithm will| -//| stop when solution of the current modified subproblem will be | -//| within EpsX (using 2-norm) of the previous solution. | -//| MEANING OF EpsI | -//| EpsI controls feasibility properties - algorithm won't stop until| -//| all inequality constraints will be satisfied with error (distance| -//| from current point to the feasible area) at most EpsI. | -//+------------------------------------------------------------------+ -static void CMinBLEIC::MinBLEICSetOuterCond(CMinBLEICState &state,const double epsx, - const double epsi) - { -//--- check - if(!CAp::Assert(CMath::IsFinite(epsx),__FUNCTION__+": EpsX is not finite number")) - return; -//--- check - if(!CAp::Assert(epsx>0.0,__FUNCTION__+": non-positive EpsX")) - return; -//--- check - if(!CAp::Assert(CMath::IsFinite(epsi),__FUNCTION__+": EpsI is not finite number")) - return; -//--- check - if(!CAp::Assert((double)(epsi)>0.0,__FUNCTION__+": non-positive EpsI")) - return; -//--- change values - state.m_outerepsx=epsx; - state.m_outerepsi=epsi; - } -//+------------------------------------------------------------------+ -//| This function sets scaling coefficients for BLEIC optimizer. | -//| ALGLIB optimizers use scaling matrices to test stopping | -//| conditions (step size and gradient are scaled before comparison | -//| with tolerances). Scale of the I-th variable is a translation | -//| invariant measure of: | -//| a) "how large" the variable is | -//| b) how large the step should be to make significant changes in | -//| the function | -//| Scaling is also used by finite difference variant of the | -//| optimizer - step along I-th axis is equal to DiffStep*S[I]. | -//| In most optimizers (and in the BLEIC too) scaling is NOT a form | -//| of preconditioning. It just affects stopping conditions. You | -//| should set preconditioner by separate call to one of the | -//| MinBLEICSetPrec...() functions. | -//| There is a special preconditioning mode, however, which uses | -//| scaling coefficients to form diagonal preconditioning matrix. | -//| You can turn this mode on, if you want. But you should understand| -//| that scaling is not the same thing as preconditioning - these are| -//| two different, although related forms of tuning solver. | -//| INPUT PARAMETERS: | -//| State - structure stores algorithm state | -//| S - array[N], non-zero scaling coefficients | -//| S[i] may be negative, sign doesn't matter. | -//+------------------------------------------------------------------+ -static void CMinBLEIC::MinBLEICSetScale(CMinBLEICState &state,double &s[]) - { -//--- create a variable - int i=0; -//--- check - if(!CAp::Assert(CAp::Len(s)>=state.m_nmain,__FUNCTION__+": Length(S)=state.m_nmain,__FUNCTION__+": D is too short")) - return; - for(i=0;i<=state.m_nmain-1;i++) - { - //--- check - if(!CAp::Assert(CMath::IsFinite(d[i]),__FUNCTION__+": D contains infinite or NAN elements")) - return; - //--- check - if(!CAp::Assert((double)(d[i])>0.0,__FUNCTION__+": D contains non-positive elements")) - return; - } -//--- function call - CApServ::RVectorSetLengthAtLeast(state.m_diaghoriginal,state.m_nmain); - state.m_prectype=2; -//--- copy - for(i=0;i<=state.m_nmain-1;i++) - state.m_diaghoriginal[i]=d[i]; - } -//+------------------------------------------------------------------+ -//| Modification of the preconditioner: scale-based diagonal | -//| preconditioning. | -//| This preconditioning mode can be useful when you don't have | -//| approximate diagonal of Hessian, but you know that your variables| -//| are badly scaled (for example, one variable is in [1,10], and | -//| another in [1000,100000]), and most part of the ill-conditioning | -//| comes from different scales of vars. | -//| In this case simple scale-based preconditioner, with H[i] = | -//| = 1/(s[i]^2), can greatly improve convergence. | -//| IMPRTANT: you should set scale of your variables with | -//| MinBLEICSetScale() call (before or after MinBLEICSetPrecScale() | -//| call). Without knowledge of the scale of your variables | -//| scale-based preconditioner will be just unit matrix. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//+------------------------------------------------------------------+ -static void CMinBLEIC::MinBLEICSetPrecScale(CMinBLEICState &state) - { -//--- change value - state.m_prectype=3; - } -//+------------------------------------------------------------------+ -//| This function allows to stop algorithm after specified number of | -//| inner iterations. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| MaxIts - maximum number of inner iterations. | -//| If MaxIts=0, the number of iterations is | -//| unlimited. | -//+------------------------------------------------------------------+ -static void CMinBLEIC::MinBLEICSetMaxIts(CMinBLEICState &state, - const int maxits) - { -//--- check - if(!CAp::Assert(maxits>=0,__FUNCTION__+": negative MaxIts!")) - return; -//--- change value - state.m_maxits=maxits; - } -//+------------------------------------------------------------------+ -//| This function turns on/off reporting. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NeedXRep- whether iteration reports are needed or not | -//| If NeedXRep is True, algorithm will call rep() callback function | -//| if it is provided to MinBLEICOptimize(). | -//+------------------------------------------------------------------+ -static void CMinBLEIC::MinBLEICSetXRep(CMinBLEICState &state, - const bool needxrep) - { -//--- change value - state.m_xrep=needxrep; - } -//+------------------------------------------------------------------+ -//| This function sets maximum step length | -//| IMPORTANT: this feature is hard to combine with preconditioning. | -//| You can't set upper limit on step length, when you solve | -//| optimization problem with linear (non-boundary) constraints AND | -//| preconditioner turned on. | -//| When non-boundary constraints are present, you have to either a) | -//| use preconditioner, or b) use upper limit on step length. YOU | -//| CAN'T USE BOTH! In this case algorithm will terminate with | -//| appropriate error code. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| StpMax - maximum step length, >=0. Set StpMax to 0.0, if | -//| you don't want to limit step length. | -//| Use this subroutine when you optimize target function which | -//| contains exp() or other fast growing functions, and optimization | -//| algorithm makes too large steps which lead to overflow. This | -//| function allows us to reject steps that are too large (and | -//| therefore expose us to the possible overflow) without actually | -//| calculating function value at the x+stp*d. | -//+------------------------------------------------------------------+ -static void CMinBLEIC::MinBLEICSetStpMax(CMinBLEICState &state, - const double stpmax) - { -//--- check - if(!CAp::Assert(CMath::IsFinite(stpmax),__FUNCTION__+": StpMax is not finite!")) - return; -//--- check - if(!CAp::Assert(stpmax>=0.0,__FUNCTION__+": StpMax<0!")) - return; -//--- change value - state.m_stpmax=stpmax; - } -//+------------------------------------------------------------------+ -//| BLEIC results | -//| INPUT PARAMETERS: | -//| State - algorithm state | -//| OUTPUT PARAMETERS: | -//| X - array[0..N-1], solution | -//| Rep - optimization report. You should check Rep. | -//| TerminationType in order to distinguish | -//| successful termination from unsuccessful one. | -//| More information about fields of this structure | -//| can be found in the comments on MinBLEICReport | -//| datatype. | -//+------------------------------------------------------------------+ -static void CMinBLEIC::MinBLEICResults(CMinBLEICState &state,double &x[], - CMinBLEICReport &rep) - { -//--- reset memory - ArrayResizeAL(x,0); -//--- function call - MinBLEICResultsBuf(state,x,rep); - } -//+------------------------------------------------------------------+ -//| BLEIC results | -//| Buffered implementation of MinBLEICResults() which uses | -//| pre-allocated buffer to store X[]. If buffer size is too small, | -//| it resizes buffer. It is intended to be used in the inner cycles | -//| of performance critical algorithms where array reallocation | -//| penalty is too large to be ignored. | -//+------------------------------------------------------------------+ -static void CMinBLEIC::MinBLEICResultsBuf(CMinBLEICState &state,double &x[], - CMinBLEICReport &rep) - { -//--- create variables - int i=0; - int i_=0; -//--- check - if(CAp::Len(x)0) - { - for(i_=0;i_<=state.m_nmain-1;i_++) - x[i_]=state.m_xend[i_]; - } - else - { - for(i=0;i<=state.m_nmain-1;i++) - x[i]=CInfOrNaN::NaN(); - } -//--- change values - rep.m_debugeqerr=state.m_repdebugeqerr; - rep.m_debugfs=state.m_repdebugfs; - rep.m_debugff=state.m_repdebugff; - rep.m_debugdx=state.m_repdebugdx; - } -//+------------------------------------------------------------------+ -//| This subroutine restarts algorithm from new point. | -//| All optimization parameters (including constraints) are left | -//| unchanged. | -//| This function allows to solve multiple optimization problems | -//| (which must have same number of dimensions) without object | -//| reallocation penalty. | -//| INPUT PARAMETERS: | -//| State - structure previously allocated with | -//| MinBLEICCreate call. | -//| X - new starting point. | -//+------------------------------------------------------------------+ -static void CMinBLEIC::MinBLEICRestartFrom(CMinBLEICState &state,double &x[]) - { -//--- create variables - int n=0; - int i_=0; -//--- initialization - n=state.m_nmain; -//--- First,check for errors in the inputs - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)state.m_bnduoriginal[i]) - v=state.m_bnduoriginal[i]; - } - xunscaled[i]=v; - } - } -//+------------------------------------------------------------------+ -//| This function: | -//| 1. makes projection of XScaled into equality constrained subspace| -//| (X is modified in-place) | -//| 2. stores residual from the projection into R | -//| 3. unscales projected XScaled and stores result into XUnscaled | -//| with additional enforcement | -//| It calculates set of additional values which are used later for | -//| modification of the target function F. | -//| INPUT PARAMETERS: | -//| State - optimizer state (we use its fields to get | -//| information about constraints) | -//| X - vector being projected | -//| R - preallocated buffer, used to store residual from | -//| projection | -//| OUTPUT PARAMETERS: | -//| X - projection of input X | -//| R - residual | -//| RNorm - residual norm squared, used later to modify | -//| target function | -//+------------------------------------------------------------------+ -static void CMinBLEIC::ProjectPointAndUnscale(CMinBLEICState &state, - double &xscaled[],double &xunscaled[], - double &rscaled[],double &rnorm2) - { -//--- create variables - double v=0; - int i=0; - int nmain=0; - int nslack=0; - int i_=0; -//--- initialization - rnorm2=0; - nmain=state.m_nmain; - nslack=state.m_nslack; -//--- * subtract XE from XScaled -//--- * project XScaled -//--- * calculate norm of deviation from null space,store it in RNorm2 -//--- * calculate residual from projection,store it in R -//--- * add XE to XScaled -//--- * unscale variables - for(i_=0;i_<=nmain+nslack-1;i_++) - xscaled[i_]=xscaled[i_]-state.m_xe[i_]; - rnorm2=0; - for(i=0;i<=nmain+nslack-1;i++) - rscaled[i]=0; -//--- change values - for(i=0;i<=nmain+nslack-1;i++) - { - //--- check - if(state.m_activeconstraints[i]) - { - v=xscaled[i]; - xscaled[i]=0; - rscaled[i]=rscaled[i]+v; - rnorm2=rnorm2+CMath::Sqr(v); - } - } -//--- calculation - for(i=0;i<=state.m_cecnt-1;i++) - { - v=0.0; - for(i_=0;i_<=nmain+nslack-1;i_++) - v+=xscaled[i_]*state.m_cecurrent[i][i_]; - for(i_=0;i_<=nmain+nslack-1;i_++) - xscaled[i_]=xscaled[i_]-v*state.m_cecurrent[i][i_]; - for(i_=0;i_<=nmain+nslack-1;i_++) - rscaled[i_]=rscaled[i_]+v*state.m_cecurrent[i][i_]; - rnorm2=rnorm2+CMath::Sqr(v); - } - for(i_=0;i_<=nmain+nslack-1;i_++) - xscaled[i_]=xscaled[i_]+state.m_xe[i_]; -//--- function call - UnscalePoint(state,xscaled,xunscaled); - } -//+------------------------------------------------------------------+ -//| This function scales and copies NMain elements of GUnscaled into | -//| GScaled. Other NSlack components of GScaled are set to zero. | -//+------------------------------------------------------------------+ -static void CMinBLEIC::ScaleGradientAndExpand(CMinBLEICState &state, - double &gunscaled[], - double &gscaled[]) - { -//--- create a variable - int i=0; -//--- change values - for(i=0;i<=state.m_nmain-1;i++) - gscaled[i]=gunscaled[i]*state.m_transforms[i]; - for(i=0;i<=state.m_nslack-1;i++) - gscaled[state.m_nmain+i]=0; - } -//+------------------------------------------------------------------+ -//| This subroutine applies modifications to the target function | -//| given by its value F and gradient G at the projected point X | -//| which lies in the equality constrained subspace. | -//| Following modifications are applied: | -//| * modified barrier functions to handle inequality constraints | -//| (both F and G are modified) | -//| * projection of gradient into equality constrained subspace | -//| (only G is modified) | -//| * quadratic penalty for deviations from equality constrained | -//| subspace (both F and G are modified) | -//| It also calculates gradient norm (three different norms for three| -//| different types of gradient), feasibility and complementary | -//| slackness errors. | -//| INPUT PARAMETERS: | -//| State - optimizer state (we use its fields to get | -//| information about constraints) | -//| X - point (projected into equality constrained | -//| subspace) | -//| R - residual from projection | -//| RNorm2 - residual norm squared | -//| F - function value at X | -//| G - function gradient at X | -//| OUTPUT PARAMETERS: | -//| F - modified function value at X | -//| G - modified function gradient at X | -//| GNorm - 2-norm of unmodified G | -//| MPGNorm - 2-norm of modified G | -//| MBA - minimum argument of barrier functions. | -//| If X is strictly feasible, it is greater than | -//| zero. | -//| If X lies on a boundary, it is zero. | -//| It is negative for infeasible X. | -//| FIErr - 2-norm of feasibility error with respect to | -//| inequality/bound constraints | -//| CSErr - 2-norm of complementarity slackness error | -//+------------------------------------------------------------------+ -static void CMinBLEIC::ModifyTargetFunction(CMinBLEICState &state,double &x[], - double &r[],const double rnorm2, - double &f,double &g[], - double &gnorm,double &mpgnorm) - { -//--- create variables - double v=0; - int i=0; - int nmain=0; - int nslack=0; - bool hasconstraints; - int i_=0; -//--- initialization - gnorm=0; - mpgnorm=0; - nmain=state.m_nmain; - nslack=state.m_nslack; - hasconstraints=false; -//--- GNorm - v=0.0; - for(i_=0;i_<=nmain+nslack-1;i_++) - v+=g[i_]*g[i_]; - gnorm=MathSqrt(v); -//--- Process equality constraints: -//--- * modify F to handle penalty term for equality constraints -//--- * project gradient on null space of equality constraints -//--- * add penalty term for equality constraints to gradient - f=f+rnorm2; - for(i=0;i<=nmain+nslack-1;i++) - { - //--- check - if(state.m_activeconstraints[i]) - g[i]=0; - } - for(i=0;i<=state.m_cecnt-1;i++) - { - v=0.0; - //--- change values - for(i_=0;i_<=nmain+nslack-1;i_++) - v+=g[i_]*state.m_cecurrent[i][i_]; - for(i_=0;i_<=nmain+nslack-1;i_++) - g[i_]=g[i_]-v*state.m_cecurrent[i][i_]; - } - for(i_=0;i_<=nmain+nslack-1;i_++) - g[i_]=g[i_]+2*r[i_]; -//--- MPGNorm - v=0.0; - for(i_=0;i_<=nmain+nslack-1;i_++) - v+=g[i_]*g[i_]; - mpgnorm=MathSqrt(v); - } -//+------------------------------------------------------------------+ -//| This function makes additional check for constraints which can be| -//| activated. | -//| We try activate constraints one by one, but it is possible that | -//| several constraints should be activated during one iteration. It | -//| this case only one of them (probably last) will be activated. | -//| This function will fix it - it will pass through constraints and | -//| activate those which are at the boundary or beyond it. | -//| It will return True, if at least one constraint was activated by | -//| this function. | -//+------------------------------------------------------------------+ -static bool CMinBLEIC::AdditionalCheckForConstraints(CMinBLEICState &state, - double &x[]) - { -//--- create variables - bool result; - int i=0; - int nmain=0; - int nslack=0; -//--- initialization - result=false; - nmain=state.m_nmain; - nslack=state.m_nslack; -//--- calculation - for(i=0;i<=nmain-1;i++) - { - //--- check - if(!state.m_activeconstraints[i]) - { - //--- check - if(state.m_hasbndl[i]) - { - //--- check - if(x[i]<=state.m_bndleffective[i]) - { - state.m_activeconstraints[i]=true; - state.m_constrainedvalues[i]=state.m_bndleffective[i]; - result=true; - } - } - //--- check - if(state.m_hasbndu[i]) - { - //--- check - if(x[i]>=state.m_bndueffective[i]) - { - state.m_activeconstraints[i]=true; - state.m_constrainedvalues[i]=state.m_bndueffective[i]; - result=true; - } - } - } - } - for(i=0;i<=nslack-1;i++) - { - //--- check - if(!state.m_activeconstraints[nmain+i]) - { - //--- check - if(x[nmain+i]<=0.0) - { - state.m_activeconstraints[nmain+i]=true; - state.m_constrainedvalues[nmain+i]=0; - result=true; - } - } - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| This function rebuilds CECurrent and XE according to current set | -//| of active bound constraints. | -//+------------------------------------------------------------------+ -static void CMinBLEIC::RebuildCEXE(CMinBLEICState &state) - { -//--- create variables - int i=0; - int j=0; - int k=0; - int nmain=0; - int nslack=0; - double v=0; - int i_=0; -//--- initialization - nmain=state.m_nmain; - nslack=state.m_nslack; -//--- function call - CAblas::RMatrixCopy(state.m_cecnt,nmain+nslack+1,state.m_ceeffective,0,0,state.m_cecurrent,0,0); -//--- calculation - for(i=0;i<=state.m_cecnt-1;i++) - { - //--- "Subtract" active bound constraints from I-th linear constraint - for(j=0;j<=nmain+nslack-1;j++) - { - //--- check - if(state.m_activeconstraints[j]) - { - state.m_cecurrent[i].Set(nmain+nslack,state.m_cecurrent[i][nmain+nslack]-state.m_cecurrent[i][j]*state.m_constrainedvalues[j]); - state.m_cecurrent[i].Set(j,0.0); - } - } - //--- Reorthogonalize I-th constraint with respect to previous ones - //--- NOTE: we also update right part,which is CECurrent[...,NMain+NSlack]. - for(k=0;k<=i-1;k++) - { - v=0.0; - for(i_=0;i_<=nmain+nslack-1;i_++) - v+=state.m_cecurrent[k][i_]*state.m_cecurrent[i][i_]; - for(i_=0;i_<=nmain+nslack;i_++) - state.m_cecurrent[i].Set(i_,state.m_cecurrent[i][i_]-v*state.m_cecurrent[k][i_]); - } - //--- Calculate norm of I-th row of CECurrent. Fill by zeros,if it is - //--- too small. Normalize otherwise. - //--- NOTE: we also scale last column of CECurrent (right part) - v=0.0; - for(i_=0;i_<=nmain+nslack-1;i_++) - v+=state.m_cecurrent[i][i_]*state.m_cecurrent[i][i_]; - v=MathSqrt(v); - //--- check - if(v>10000*CMath::m_machineepsilon) - { - v=1/v; - for(i_=0;i_<=nmain+nslack;i_++) - state.m_cecurrent[i].Set(i_,v*state.m_cecurrent[i][i_]); - } - else - { - for(j=0;j<=nmain+nslack;j++) - state.m_cecurrent[i].Set(j,0); - } - } -//--- change values - for(j=0;j<=nmain+nslack-1;j++) - state.m_xe[j]=0; - for(i=0;i<=nmain+nslack-1;i++) - { - //--- check - if(state.m_activeconstraints[i]) - state.m_xe[i]=state.m_xe[i]+state.m_constrainedvalues[i]; - } -//--- change values - for(i=0;i<=state.m_cecnt-1;i++) - { - v=state.m_cecurrent[i][nmain+nslack]; - for(i_=0;i_<=nmain+nslack-1;i_++) - state.m_xe[i_]=state.m_xe[i_]+v*state.m_cecurrent[i][i_]; - } - } -//+------------------------------------------------------------------+ -//| This function projects gradient onto equality constrained | -//| subspace | -//+------------------------------------------------------------------+ -static void CMinBLEIC::MakeGradientProjection(CMinBLEICState &state, - double &pg[]) - { -//--- create variables - int i=0; - int nmain=0; - int nslack=0; - double v=0; - int i_=0; -//--- initialization - nmain=state.m_nmain; - nslack=state.m_nslack; - for(i=0;i<=nmain+nslack-1;i++) - { - //--- check - if(state.m_activeconstraints[i]) - pg[i]=0; - } -//--- calculation - for(i=0;i<=state.m_cecnt-1;i++) - { - v=0.0; - for(i_=0;i_<=nmain+nslack-1;i_++) - v+=pg[i_]*state.m_cecurrent[i][i_]; - for(i_=0;i_<=nmain+nslack-1;i_++) - pg[i_]=pg[i_]-v*state.m_cecurrent[i][i_]; - } - } -//+------------------------------------------------------------------+ -//| This function prepares equality constrained subproblem: | -//| 1. X is used to activate constraints (if there are ones which are| -//| still inactive, but should be activated). | -//| 2. constraints matrix CEOrt is copied to CECurrent and modified | -//| according to the list of active bound constraints | -//| (corresponding elements are filled by zeros and | -//| reorthogonalized). | -//| 3. XE - least squares solution of equality constraints - is | -//| recalculated | -//| 4. X is copied to PX and projected onto equality constrained | -//| subspace | -//| 5. inactive constraints are checked against PX - if there is at | -//| least one which should be activated, we activate it and move | -//| back to (2) | -//| 6. as result, PX is feasible with respect to bound constraints - | -//| step (5) guarantees it. But PX can be infeasible with respect | -//| to equality ones, because step (2) is done without checks for | -//| consistency. As the final step, we check that PX is feasible. | -//| If not, we return False. True is returned otherwise. | -//| If this algorithm returned True, then: | -//| * X is not changed | -//| * PX contains projection of X onto constrained subspace | -//| * G is not changed | -//| * PG contains projection of G onto constrained subspace | -//| * PX is feasible with respect to all constraints | -//| * all constraints which are active at PX, are activated | -//+------------------------------------------------------------------+ -static bool CMinBLEIC::PrepareConstraintMatrix(CMinBLEICState &state,double &x[], - double &g[],double &px[],double &pg[]) - { -//--- create variables - int i=0; - int nmain=0; - int nslack=0; - double v=0; - double ferr=0; - int i_=0; -//--- initialization - nmain=state.m_nmain; - nslack=state.m_nslack; -//--- Step 1 - AdditionalCheckForConstraints(state,x); -//--- Steps 2-5 - do - { - //--- Steps 2-3 - RebuildCEXE(state); - //--- Step 4 - //--- Calculate PX,PG - for(i_=0;i_<=nmain+nslack-1;i_++) - px[i_]=x[i_]; - for(i_=0;i_<=nmain+nslack-1;i_++) - px[i_]=px[i_]-state.m_xe[i_]; - for(i_=0;i_<=nmain+nslack-1;i_++) - pg[i_]=g[i_]; - for(i=0;i<=nmain+nslack-1;i++) - { - //--- check - if(state.m_activeconstraints[i]) - { - px[i]=0; - pg[i]=0; - } - } - //--- calculation - for(i=0;i<=state.m_cecnt-1;i++) - { - //--- change values - v=0.0; - for(i_=0;i_<=nmain+nslack-1;i_++) - v+=px[i_]*state.m_cecurrent[i][i_]; - for(i_=0;i_<=nmain+nslack-1;i_++) - px[i_]=px[i_]-v*state.m_cecurrent[i][i_]; - //--- change values - v=0.0; - for(i_=0;i_<=nmain+nslack-1;i_++) - v+=pg[i_]*state.m_cecurrent[i][i_]; - for(i_=0;i_<=nmain+nslack-1;i_++) - pg[i_]=pg[i_]-v*state.m_cecurrent[i][i_]; - } - for(i_=0;i_<=nmain+nslack-1;i_++) - px[i_]=px[i_]+state.m_xe[i_]; - //--- Step 5 (loop condition below) - } - while(AdditionalCheckForConstraints(state,px)); -//--- Step 6 - ferr=0; - for(i=0;i<=state.m_cecnt-1;i++) - { - v=0.0; - for(i_=0;i_<=nmain+nslack-1;i_++) - v+=px[i_]*state.m_ceeffective[i][i_]; - //--- change values - v=v-state.m_ceeffective[i][nmain+nslack]; - ferr=MathMax(ferr,MathAbs(v)); - } -//--- check - if(ferr<=state.m_outerepsi) - return(true); -//--- return result - return(false); - } -//+------------------------------------------------------------------+ -//| Internal initialization subroutine | -//+------------------------------------------------------------------+ -static void CMinBLEIC::MinBLEICInitInternal(const int n,double &x[], - const double diffstep, - CMinBLEICState &state) - { -//--- create a variable - int i=0; -//--- create matrix - CMatrixDouble c; -//--- create array - int ct[]; -//--- initialization - state.m_nmain=n; - state.m_optdim=0; - state.m_diffstep=diffstep; -//--- allocation - ArrayResizeAL(state.m_bndloriginal,n); - ArrayResizeAL(state.m_bndleffective,n); - ArrayResizeAL(state.m_hasbndl,n); - ArrayResizeAL(state.m_bnduoriginal,n); - ArrayResizeAL(state.m_bndueffective,n); - ArrayResizeAL(state.m_hasbndu,n); - ArrayResizeAL(state.m_xstart,n); - ArrayResizeAL(state.m_soriginal,n); - ArrayResizeAL(state.m_x,n); - ArrayResizeAL(state.m_g,n); - for(i=0;i<=n-1;i++) - { - state.m_bndloriginal[i]=CInfOrNaN::NegativeInfinity(); - state.m_hasbndl[i]=false; - state.m_bnduoriginal[i]=CInfOrNaN::PositiveInfinity(); - state.m_hasbndu[i]=false; - state.m_soriginal[i]=1.0; - } -//--- function call - MinBLEICSetLC(state,c,ct,0); -//--- function call - MinBLEICSetInnerCond(state,0.0,0.0,0.0); -//--- function call - MinBLEICSetOuterCond(state,1.0E-6,1.0E-6); -//--- function call - MinBLEICSetMaxIts(state,0); -//--- function call - MinBLEICSetXRep(state,false); -//--- function call - MinBLEICSetStpMax(state,0.0); -//--- function call - MinBLEICSetPrecDefault(state); -//--- function call - MinBLEICRestartFrom(state,x); - } -//+------------------------------------------------------------------+ -//| NOTES: | -//| 1. This function has two different implementations: one which | -//| uses exact (analytical) user-supplied gradient, and one which | -//| uses function value only and numerically differentiates | -//| function in order to obtain gradient. | -//| Depending on the specific function used to create optimizer | -//| object (either MinBLEICCreate() for analytical gradient or | -//| MinBLEICCreateF() for numerical differentiation) you should | -//| choose appropriate variant of MinBLEICOptimize() - one which | -//| accepts function AND gradient or one which accepts function | -//| ONLY. | -//| Be careful to choose variant of MinBLEICOptimize() which | -//| corresponds to your optimization scheme! Table below lists | -//| different combinations of callback (function/gradient) passed | -//| to MinBLEICOptimize() and specific function used to create | -//| optimizer. | -//| | USER PASSED TO MinBLEICOptimize() | -//| CREATED WITH | function only | function and gradient | -//| ------------------------------------------------------------ | -//| MinBLEICCreateF() | work FAIL | -//| MinBLEICCreate() | FAIL work | -//| Here "FAIL" denotes inappropriate combinations of optimizer | -//| creation function and MinBLEICOptimize() version. Attemps to | -//| use such combination (for example, to create optimizer with | -//| MinBLEICCreateF() and to pass gradient information to | -//| MinCGOptimize()) will lead to exception being thrown. Either | -//| you did not pass gradient when it WAS needed or you passed | -//| gradient when it was NOT needed. | -//+------------------------------------------------------------------+ -static bool CMinBLEIC::MinBLEICIteration(CMinBLEICState &state) - { -//--- create variables - int nmain=0; - int nslack=0; - int m=0; - int i=0; - int j=0; - double v=0; - double vv=0; - bool b; - int i_=0; -//--- This code initializes locals by: -//--- * random values determined during code -//--- generation - on first subroutine call -//--- * values from previous call - on subsequent calls - if(state.m_rstate.stage>=0) - { - //--- initialization - nmain=state.m_rstate.ia[0]; - nslack=state.m_rstate.ia[1]; - m=state.m_rstate.ia[2]; - i=state.m_rstate.ia[3]; - j=state.m_rstate.ia[4]; - b=state.m_rstate.ba[0]; - v=state.m_rstate.ra[0]; - vv=state.m_rstate.ra[1]; - } - else - { - //--- initialization - nmain=-983; - nslack=-989; - m=-834; - i=900; - j=-287; - b=false; - v=214; - vv=-338; - } -//--- check - if(state.m_rstate.stage==0) - { - //--- change value - state.m_needfg=false; - //--- function call, return result - return(Func_lbl_14(state,nmain,nslack,m,i,j,b,v,vv)); - } -//--- check - if(state.m_rstate.stage==1) - { - //--- change value - state.m_needf=false; - //--- function call, return result - return(Func_lbl_14(state,nmain,nslack,m,i,j,b,v,vv)); - } -//--- check - if(state.m_rstate.stage==2) - { - //--- change value - state.m_needfg=false; - //--- function call, return result - return(Func_lbl_22(state,nmain,nslack,m,i,j,b,v,vv)); - } -//--- check - if(state.m_rstate.stage==3) - { - //--- change values - state.m_fbase=state.m_f; - i=0; - //--- function call, return result - return(Func_lbl_23(state,nmain,nslack,m,i,j,b,v,vv)); - } -//--- check - if(state.m_rstate.stage==4) - { - //--- change values - state.m_fm2=state.m_f; - state.m_x[i]=v-0.5*state.m_diffstep*state.m_soriginal[i]; - state.m_rstate.stage=5; - //--- Saving state - Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv); - //--- return result - return(true); - } -//--- check - if(state.m_rstate.stage==5) - { - //--- change values - state.m_fm1=state.m_f; - state.m_x[i]=v+0.5*state.m_diffstep*state.m_soriginal[i]; - state.m_rstate.stage=6; - //--- Saving state - Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv); - //--- return result - return(true); - } -//--- check - if(state.m_rstate.stage==6) - { - //--- change values - state.m_fp1=state.m_f; - state.m_x[i]=v+state.m_diffstep*state.m_soriginal[i]; - state.m_rstate.stage=7; - //--- Saving state - Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv); - //--- return result - return(true); - } -//--- check - if(state.m_rstate.stage==7) - { - //--- change values - state.m_fp2=state.m_f; - state.m_g[i]=(8*(state.m_fp1-state.m_fm1)-(state.m_fp2-state.m_fm2))/(6*state.m_diffstep*state.m_soriginal[i]); - state.m_x[i]=v; - i=i+1; - //--- function call, return result - return(Func_lbl_23(state,nmain,nslack,m,i,j,b,v,vv)); - } -//--- check - if(state.m_rstate.stage==8) - { - //--- change values - state.m_fm1=state.m_f; - state.m_xp1=MathMin(v+state.m_diffstep*state.m_soriginal[i],state.m_bnduoriginal[i]); - state.m_x[i]=state.m_xp1; - state.m_rstate.stage=9; - //--- Saving state - Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv); - //--- return result - return(true); - } -//--- check - if(state.m_rstate.stage==9) - { - //--- change values - state.m_fp1=state.m_f; - state.m_g[i]=(state.m_fp1-state.m_fm1)/(state.m_xp1-state.m_xm1); - state.m_x[i]=v; - i=i+1; - //--- function call, return result - return(Func_lbl_23(state,nmain,nslack,m,i,j,b,v,vv)); - } -//--- check - if(state.m_rstate.stage==10) - { - //--- change value - state.m_xupdated=false; - //--- function call, return result - return(Func_lbl_17(state,nmain,nslack,m,i,j,b,v,vv)); - } -//--- check - if(state.m_rstate.stage==11) - { - //--- change value - state.m_needfg=false; - //--- function call, return result - return(Func_lbl_31(state,nmain,nslack,m,i,j,b,v,vv)); - } -//--- check - if(state.m_rstate.stage==12) - { - //--- change value - state.m_needf=false; - //--- function call, return result - return(Func_lbl_31(state,nmain,nslack,m,i,j,b,v,vv)); - } -//--- Routine body -//--- Prepare: -//--- * calculate number of slack variables -//--- * initialize locals -//--- * initialize debug fields -//--- * make quick check - nmain=state.m_nmain; - nslack=0; - for(i=0;i<=state.m_cecnt-1;i++) - { - //--- check - if(state.m_ct[i]!=0) - nslack=nslack+1; - } -//--- change values - state.m_nslack=nslack; - state.m_repterminationtype=0; - state.m_repinneriterationscount=0; - state.m_repouteriterationscount=0; - state.m_repnfev=0; - state.m_repdebugeqerr=0.0; - state.m_repdebugfs=CInfOrNaN::NaN(); - state.m_repdebugff=CInfOrNaN::NaN(); - state.m_repdebugdx=CInfOrNaN::NaN(); -//--- check - if(state.m_stpmax!=0.0 && state.m_prectype!=0) - { - state.m_repterminationtype=-10; - //--- return result - return(false); - } -//--- allocate - CApServ::RVectorSetLengthAtLeast(state.m_r,nmain+nslack); - CApServ::RVectorSetLengthAtLeast(state.m_diagh,nmain+nslack); - CApServ::RVectorSetLengthAtLeast(state.m_tmp0,nmain+nslack); - CApServ::RVectorSetLengthAtLeast(state.m_tmp1,nmain+nslack); - CApServ::RVectorSetLengthAtLeast(state.m_tmp2,nmain+nslack); - CApServ::RMatrixSetLengthAtLeast(state.m_cecurrent,state.m_cecnt,nmain+nslack+1); - CApServ::BVectorSetLengthAtLeast(state.m_activeconstraints,nmain+nslack); - CApServ::RVectorSetLengthAtLeast(state.m_constrainedvalues,nmain+nslack); - CApServ::RVectorSetLengthAtLeast(state.m_lastg,nmain+nslack); - CApServ::RVectorSetLengthAtLeast(state.m_xe,nmain+nslack); - CApServ::RVectorSetLengthAtLeast(state.m_xcur,nmain+nslack); - CApServ::RVectorSetLengthAtLeast(state.m_xprev,nmain+nslack); - CApServ::RVectorSetLengthAtLeast(state.m_xend,nmain); -//--- Create/restart optimizer. -//--- State.OptDim is used to determine current state of optimizer. - if(state.m_optdim!=nmain+nslack) - { - for(i=0;i<=nmain+nslack-1;i++) - state.m_tmp1[i]=0.0; - //--- function call - CMinCG::MinCGCreate(nmain+nslack,state.m_tmp1,state.m_cgstate); - state.m_optdim=nmain+nslack; - } -//--- Prepare transformation. -//--- MinBLEIC's handling of preconditioner matrix is somewhat unusual - -//--- instead of incorporating it into algorithm and making implicit -//--- scaling (as most optimizers do) BLEIC optimizer uses explicit -//--- scaling - it solves problem in the scaled parameters space S, -//--- making transition between scaled (S) and unscaled (X) variables -//--- every time we ask for function value. -//--- Following fields are calculated here: -//--- * TransformS X[i]=TransformS[i]*S[i],array[NMain] -//--- * SEffective "effective" scale of the variables after -//--- transformation,array[NMain+NSlack] - CApServ::RVectorSetLengthAtLeast(state.m_transforms,nmain); - for(i=0;i<=nmain-1;i++) - { - //--- check - if(state.m_prectype==2) - { - state.m_transforms[i]=1/MathSqrt(state.m_diaghoriginal[i]); - continue; - } - //--- check - if(state.m_prectype==3) - { - state.m_transforms[i]=state.m_soriginal[i]; - continue; - } - state.m_transforms[i]=1; - } -//--- function call - CApServ::RVectorSetLengthAtLeast(state.m_seffective,nmain+nslack); - for(i=0;i<=nmain-1;i++) - state.m_seffective[i]=state.m_soriginal[i]/state.m_transforms[i]; - for(i=0;i<=nslack-1;i++) - state.m_seffective[nmain+i]=1; -//--- function call - CMinCG::MinCGSetScale(state.m_cgstate,state.m_seffective); -//--- Pre-process constraints -//--- * check consistency of bound constraints -//--- * add slack vars,convert problem to the bound/equality -//--- constrained one -//--- We calculate here: -//--- * BndLEffective - lower bounds after transformation of variables (see above) -//--- * BndUEffective - upper bounds after transformation of variables (see above) -//--- * CEEffective - matrix of equality constraints for transformed variables - for(i=0;i<=nmain-1;i++) - { - //--- check - if(state.m_hasbndl[i]) - state.m_bndleffective[i]=state.m_bndloriginal[i]/state.m_transforms[i]; - //--- check - if(state.m_hasbndu[i]) - state.m_bndueffective[i]=state.m_bnduoriginal[i]/state.m_transforms[i]; - } - for(i=0;i<=nmain-1;i++) - { - //--- check - if(state.m_hasbndl[i] && state.m_hasbndu[i]) - { - //--- check - if(state.m_bndleffective[i]>state.m_bndueffective[i]) - { - state.m_repterminationtype=-3; - //--- return result - return(false); - } - } - } -//--- function call - CApServ::RMatrixSetLengthAtLeast(state.m_ceeffective,state.m_cecnt,nmain+nslack+1); -//--- change value - m=0; -//--- calculation - for(i=0;i<=state.m_cecnt-1;i++) - { - //--- NOTE: when we add slack variable,we use V=max(abs(CE[i,...])) as - //--- coefficient before it in order to make linear equations better - //--- conditioned. - v=0; - for(j=0;j<=nmain-1;j++) - { - state.m_ceeffective[i].Set(j,state.m_ceoriginal[i][j]*state.m_transforms[j]); - v=MathMax(v,MathAbs(state.m_ceeffective[i][j])); - } - //--- check - if(v==0.0) - v=1; - for(j=0;j<=nslack-1;j++) - state.m_ceeffective[i].Set(nmain+j,0.0); - state.m_ceeffective[i].Set(nmain+nslack,state.m_ceoriginal[i][nmain]); - //--- check - if(state.m_ct[i]<0) - { - state.m_ceeffective[i].Set(nmain+m,v); - m=m+1; - } - //--- check - if(state.m_ct[i]>0) - { - state.m_ceeffective[i].Set(nmain+m,-v); - m=m+1; - } - } -//--- Find feasible point. -//--- 0. Convert from unscaled values (as stored in XStart) to scaled -//--- ones -//--- 1. calculate values of slack variables such that starting -//--- point satisfies inequality constraints (after conversion to -//--- equality ones) as much as possible. -//--- 2. use PrepareConstraintMatrix() function,which forces X -//--- to be strictly feasible. - for(i=0;i<=nmain-1;i++) - state.m_tmp0[i]=state.m_xstart[i]/state.m_transforms[i]; -//--- change value - m=0; -//--- calculation - for(i=0;i<=state.m_cecnt-1;i++) - { - v=0.0; - for(i_=0;i_<=nmain-1;i_++) - v+=state.m_ceeffective[i][i_]*state.m_tmp0[i_]; - //--- check - if(state.m_ct[i]<0) - { - state.m_tmp0[nmain+m]=state.m_ceeffective[i][nmain+nslack]-v; - m=m+1; - } - //--- check - if(state.m_ct[i]>0) - { - state.m_tmp0[nmain+m]=v-state.m_ceeffective[i][nmain+nslack]; - m=m+1; - } - } -//--- change values - for(i=0;i<=nmain+nslack-1;i++) - state.m_tmp1[i]=0; - for(i=0;i<=nmain+nslack-1;i++) - state.m_activeconstraints[i]=false; -//--- function call - b=PrepareConstraintMatrix(state,state.m_tmp0,state.m_tmp1,state.m_xcur,state.m_tmp2); - state.m_repdebugeqerr=0.0; -//--- calculation - for(i=0;i<=state.m_cecnt-1;i++) - { - v=0.0; - for(i_=0;i_<=nmain+nslack-1;i_++) - v+=state.m_ceeffective[i][i_]*state.m_xcur[i_]; - state.m_repdebugeqerr=state.m_repdebugeqerr+CMath::Sqr(v-state.m_ceeffective[i][nmain+nslack]); - } - state.m_repdebugeqerr=MathSqrt(state.m_repdebugeqerr); -//--- check - if(!b) - { - state.m_repterminationtype=-3; - //--- return result - return(false); - } -//--- Initialize RepDebugFS with function value at initial point - UnscalePoint(state,state.m_xcur,state.m_x); - ClearRequestFields(state); -//--- check - if(state.m_diffstep!=0.0) - { - state.m_needf=true; - state.m_rstate.stage=1; - //--- Saving state - Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv); - //--- return result - return(true); - } -//--- change values - state.m_needfg=true; - state.m_rstate.stage=0; -//--- Saving state - Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinBLEICIteration. Is a product to get rid| -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static void CMinBLEIC::Func_lbl_rcomm(CMinBLEICState &state,int nmain, - int nslack,int m,int i,int j, - bool b,double v,double vv) - { -//--- save - state.m_rstate.ia[0]=nmain; - state.m_rstate.ia[1]=nslack; - state.m_rstate.ia[2]=m; - state.m_rstate.ia[3]=i; - state.m_rstate.ia[4]=j; - state.m_rstate.ba[0]=b; - state.m_rstate.ra[0]=v; - state.m_rstate.ra[1]=vv; - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinBLEICIteration. Is a product to get rid| -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinBLEIC::Func_lbl_14(CMinBLEICState &state,int &nmain, - int &nslack,int &m,int &i,int &j, - bool &b,double &v,double &vv) - { -//--- function call - COptServ::TrimPrepare(state.m_f,state.m_trimthreshold); - state.m_repnfev=state.m_repnfev+1; - state.m_repdebugfs=state.m_f; -//--- Outer cycle - state.m_itsleft=state.m_maxits; -//--- copy - for(int i_=0;i_<=nmain+nslack-1;i_++) - state.m_xprev[i_]=state.m_xcur[i_]; -//--- function call, return result - return(Func_lbl_15(state,nmain,nslack,m,i,j,b,v,vv)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinBLEICIteration. Is a product to get rid| -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinBLEIC::Func_lbl_15(CMinBLEICState &state,int &nmain, - int &nslack,int &m,int &i,int &j, - bool &b,double &v,double &vv) - { -//--- check - if(!CAp::Assert(state.m_prectype==0 || state.m_stpmax==0.0,"MinBLEIC: internal error (-10)")) - return(false); -//--- Inner cycle: CG with projections and penalty functions - for(int i_=0;i_<=nmain+nslack-1;i_++) - state.m_tmp0[i_]=state.m_xcur[i_]; - for(i=0;i<=nmain+nslack-1;i++) - { - state.m_tmp1[i]=0; - state.m_activeconstraints[i]=false; - } -//--- check - if(!PrepareConstraintMatrix(state,state.m_tmp0,state.m_tmp1,state.m_xcur,state.m_tmp2)) - { - state.m_repterminationtype=-3; - //--- return result - return(false); - } - for(i=0;i<=nmain+nslack-1;i++) - state.m_activeconstraints[i]=false; - RebuildCEXE(state); -//--- function call - CMinCG::MinCGRestartFrom(state.m_cgstate,state.m_xcur); -//--- function call - CMinCG::MinCGSetCond(state.m_cgstate,state.m_innerepsg,state.m_innerepsf,state.m_innerepsx,state.m_itsleft); -//--- function call - CMinCG::MinCGSetXRep(state.m_cgstate,state.m_xrep); -//--- function call - CMinCG::MinCGSetDRep(state.m_cgstate,true); -//--- function call - CMinCG::MinCGSetStpMax(state.m_cgstate,state.m_stpmax); -//--- function call, return result - return(Func_lbl_17(state,nmain,nslack,m,i,j,b,v,vv)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinBLEICIteration. Is a product to get rid| -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinBLEIC::Func_lbl_16(CMinBLEICState &state,int &nmain, - int &nslack,int &m,int &i,int &j, - bool &b,double &v,double &vv) - { -//--- We've stopped,fill debug information - state.m_repdebugeqerr=0.0; - for(i=0;i<=state.m_cecnt-1;i++) - { - //--- change value - v=0.0; - for(int i_=0;i_<=nmain+nslack-1;i_++) - v+=state.m_ceeffective[i][i_]*state.m_xcur[i_]; - state.m_repdebugeqerr=state.m_repdebugeqerr+CMath::Sqr(v-state.m_ceeffective[i][nmain+nslack]); - } -//--- change values - state.m_repdebugeqerr=MathSqrt(state.m_repdebugeqerr); - state.m_repdebugdx=0; - for(i=0;i<=nmain-1;i++) - state.m_repdebugdx=state.m_repdebugdx+CMath::Sqr(state.m_xcur[i]-state.m_xstart[i]); - state.m_repdebugdx=MathSqrt(state.m_repdebugdx); -//--- return result - return(false); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinBLEICIteration. Is a product to get rid| -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinBLEIC::Func_lbl_17(CMinBLEICState &state,int &nmain, - int &nslack,int &m,int &i,int &j, - bool &b,double &v,double &vv) - { -//--- check - if(!CMinCG::MinCGIteration(state.m_cgstate)) - return(Func_lbl_18(state,nmain,nslack,m,i,j,b,v,vv)); -//--- process different requests/reports of inner optimizer - if(state.m_cgstate.m_algpowerup) - { - for(i=0;i<=nmain+nslack-1;i++) - state.m_activeconstraints[i]=false; - //--- cycle - do - { - //--- function call - RebuildCEXE(state); - for(int i_=0;i_<=nmain+nslack-1;i_++) - state.m_tmp1[i_]=state.m_cgstate.m_g[i_]; - //--- function call - MakeGradientProjection(state,state.m_tmp1); - b=false; - for(i=0;i<=nmain-1;i++) - { - //--- check - if(!state.m_activeconstraints[i]) - { - //--- check - if(state.m_hasbndl[i]) - { - //--- check - if(state.m_cgstate.m_x[i]==state.m_bndleffective[i] && state.m_tmp1[i]>=0.0) - { - //--- change values - state.m_activeconstraints[i]=true; - state.m_constrainedvalues[i]=state.m_bndleffective[i]; - b=true; - } - } - //--- check - if(state.m_hasbndu[i]) - { - //--- check - if(state.m_cgstate.m_x[i]==state.m_bndueffective[i] && state.m_tmp1[i]<=0.0) - { - //--- change values - state.m_activeconstraints[i]=true; - state.m_constrainedvalues[i]=state.m_bndueffective[i]; - b=true; - } - } - } - } - for(i=0;i<=nslack-1;i++) - { - //--- check - if(!state.m_activeconstraints[nmain+i]) - { - //--- check - if(state.m_cgstate.m_x[nmain+i]==0.0 && state.m_tmp1[nmain+i]>=0.0) - { - //--- change values - state.m_activeconstraints[nmain+i]=true; - state.m_constrainedvalues[nmain+i]=0; - b=true; - } - } - } - } - while(b); - //--- copy - for(int i_=0;i_<=nmain+nslack-1;i_++) - state.m_cgstate.m_g[i_]=state.m_tmp1[i_]; - //--- function call, return result - return(Func_lbl_17(state,nmain,nslack,m,i,j,b,v,vv)); - } -//--- check - if(state.m_cgstate.m_lsstart) - { - //--- Beginning of the line search: set upper limit on step size - //--- to prevent algo from leaving feasible area. - state.m_variabletofreeze=-1; - //--- check - if((double)(state.m_cgstate.m_curstpmax)==0.0) - state.m_cgstate.m_curstpmax=1.0E50; - for(i=0;i<=nmain-1;i++) - { - //--- check - if(state.m_hasbndl[i] && state.m_cgstate.m_d[i]<0.0) - { - //--- change values - v=state.m_cgstate.m_curstpmax; - vv=state.m_cgstate.m_x[i]-state.m_bndleffective[i]; - //--- check - if(vv<0.0) - vv=0; - state.m_cgstate.m_curstpmax=CApServ::SafeMinPosRV(vv,-state.m_cgstate.m_d[i],state.m_cgstate.m_curstpmax); - //--- check - if(state.m_cgstate.m_curstpmax0.0) - { - //--- change values - v=state.m_cgstate.m_curstpmax; - vv=state.m_bndueffective[i]-state.m_cgstate.m_x[i]; - //--- check - if(vv<0.0) - vv=0; - state.m_cgstate.m_curstpmax=CApServ::SafeMinPosRV(vv,state.m_cgstate.m_d[i],state.m_cgstate.m_curstpmax); - //--- check - if(state.m_cgstate.m_curstpmax=state.m_cgstate.m_curstpmax && state.m_variabletofreeze>=0; - //--- check - if(b) - { - state.m_activeconstraints[state.m_variabletofreeze]=true; - state.m_constrainedvalues[state.m_variabletofreeze]=state.m_valuetofreeze; - } - //--- Additional activation of constraints - b=b || AdditionalCheckForConstraints(state,state.m_cgstate.m_x); - //--- If at least one constraint was activated we have to rebuild constraint matrices - if(b) - { - //--- copy - for(int i_=0;i_<=nmain+nslack-1;i_++) - state.m_tmp0[i_]=state.m_cgstate.m_x[i_]; - for(int i_=0;i_<=nmain+nslack-1;i_++) - state.m_tmp1[i_]=state.m_lastg[i_]; - //--- check - if(!PrepareConstraintMatrix(state,state.m_tmp0,state.m_tmp1,state.m_cgstate.m_x,state.m_cgstate.m_g)) - { - state.m_repterminationtype=-3; - //--- return result - return(false); - } - state.m_cgstate.m_innerresetneeded=true; - } - //--- function call, return result - return(Func_lbl_17(state,nmain,nslack,m,i,j,b,v,vv)); - } -//--- check - if(!state.m_cgstate.m_needfg) - return(Func_lbl_19(state,nmain,nslack,m,i,j,b,v,vv)); -//--- copy - for(int i_=0;i_<=nmain+nslack-1;i_++) - state.m_tmp1[i_]=state.m_cgstate.m_x[i_]; -//--- function call - ProjectPointAndUnscale(state,state.m_tmp1,state.m_x,state.m_r,vv); -//--- function call - ClearRequestFields(state); -//--- check - if(state.m_diffstep!=0.0) - { - //--- change values - state.m_needf=true; - state.m_rstate.stage=3; - //--- Saving state - Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv); - //--- return result - return(true); - } -//--- change values - state.m_needfg=true; - state.m_rstate.stage=2; -//--- Saving state - Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinBLEICIteration. Is a product to get rid| -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinBLEIC::Func_lbl_18(CMinBLEICState &state,int &nmain, - int &nslack,int &m,int &i,int &j, - bool &b,double &v,double &vv) - { -//--- function call - CMinCG::MinCGResults(state.m_cgstate,state.m_xcur,state.m_cgrep); -//--- function call - UnscalePoint(state,state.m_xcur,state.m_xend); -//--- change values - state.m_repinneriterationscount=state.m_repinneriterationscount+state.m_cgrep.m_iterationscount; - state.m_repouteriterationscount=state.m_repouteriterationscount+1; - state.m_repnfev=state.m_repnfev+state.m_cgrep.m_nfev; -//--- Update RepDebugFF with function value at current point - UnscalePoint(state,state.m_xcur,state.m_x); - ClearRequestFields(state); -//--- check - if(state.m_diffstep!=0.0) - { - //--- change values - state.m_needf=true; - state.m_rstate.stage=12; - //--- Saving state - Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv); - //--- return result - return(true); - } -//--- change values - state.m_needfg=true; - state.m_rstate.stage=11; -//--- Saving state - Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinBLEICIteration. Is a product to get rid| -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinBLEIC::Func_lbl_19(CMinBLEICState &state,int &nmain, - int &nslack,int &m,int &i,int &j, - bool &b,double &v,double &vv) - { -//--- check - if(!state.m_cgstate.m_xupdated) - return(Func_lbl_17(state,nmain,nslack,m,i,j,b,v,vv)); -//--- Report - UnscalePoint(state,state.m_cgstate.m_x,state.m_x); - state.m_f=state.m_cgstate.m_f; -//--- function call - ClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_rstate.stage=10; -//--- Saving state - Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinBLEICIteration. Is a product to get rid| -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinBLEIC::Func_lbl_22(CMinBLEICState &state,int &nmain, - int &nslack,int &m,int &i,int &j, - bool &b,double &v,double &vv) - { -//--- check - if(state.m_fnmain-1) - { - //--- change values - state.m_f=state.m_fbase; - state.m_needf=false; - //--- function call, return result - return(Func_lbl_22(state,nmain,nslack,m,i,j,b,v,vv)); - } -//--- change values - v=state.m_x[i]; - b=false; -//--- check - if(state.m_hasbndl[i]) - b=b || v-state.m_diffstep*state.m_soriginal[i]state.m_bnduoriginal[i]; -//--- check - if(b) - { - //--- change values - state.m_xm1=MathMax(v-state.m_diffstep*state.m_soriginal[i],state.m_bndloriginal[i]); - state.m_x[i]=state.m_xm1; - state.m_rstate.stage=8; - //--- Saving state - Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv); - //--- return result - return(true); - } -//--- change values - state.m_x[i]=v-state.m_diffstep*state.m_soriginal[i]; - state.m_rstate.stage=4; -//--- Saving state - Func_lbl_rcomm(state,nmain,nslack,m,i,j,b,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinBLEICIteration. Is a product to get rid| -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinBLEIC::Func_lbl_31(CMinBLEICState &state,int &nmain, - int &nslack,int &m,int &i,int &j, - bool &b,double &v,double &vv) - { -//--- change values - state.m_repnfev=state.m_repnfev+1; - state.m_repdebugff=state.m_f; -//--- Check for stopping: -//--- * "normal",outer step size is small enough,infeasibility is within bounds -//--- * "inconsistent", if Lagrange multipliers increased beyond threshold given by MaxLagrangeMul -//--- * "too stringent",in other cases - v=0; - for(i=0;i<=nmain-1;i++) - v=v+CMath::Sqr((state.m_xcur[i]-state.m_xprev[i])/state.m_seffective[i]); - v=MathSqrt(v); -//--- check - if(v<=(double)(state.m_outerepsx)) - { - state.m_repterminationtype=4; - //--- function call, return result - return(Func_lbl_16(state,nmain,nslack,m,i,j,b,v,vv)); - } -//--- check - if(state.m_maxits>0) - { - state.m_itsleft=state.m_itsleft-state.m_cgrep.m_iterationscount; - //--- check - if(state.m_itsleft<=0) - { - state.m_repterminationtype=5; - //--- function call, return result - return(Func_lbl_16(state,nmain,nslack,m,i,j,b,v,vv)); - } - } -//--- check - if(state.m_repouteriterationscount>=m_maxouterits) - { - state.m_repterminationtype=5; - //--- function call, return result - return(Func_lbl_16(state,nmain,nslack,m,i,j,b,v,vv)); - } -//--- Next iteration - for(int i_=0;i_<=nmain+nslack-1;i_++) - state.m_xprev[i_]=state.m_xcur[i_]; -//--- function call, return result - return(Func_lbl_15(state,nmain,nslack,m,i,j,b,v,vv)); - } -//+------------------------------------------------------------------+ -//| Auxiliary class for CMinLBFGS | -//+------------------------------------------------------------------+ -class CMinLBFGSState - { -public: - //--- variables - int m_n; - int m_m; - double m_epsg; - double m_epsf; - double m_epsx; - int m_maxits; - bool m_xrep; - double m_stpmax; - double m_diffstep; - int m_nfev; - int m_mcstage; - int m_k; - int m_q; - int m_p; - double m_stp; - double m_fold; - double m_trimthreshold; - int m_prectype; - double m_gammak; - double m_fbase; - double m_fm2; - double m_fm1; - double m_fp1; - double m_fp2; - double m_f; - bool m_needf; - bool m_needfg; - bool m_xupdated; - RCommState m_rstate; - int m_repiterationscount; - int m_repnfev; - int m_repterminationtype; - CLinMinState m_lstate; - //--- arrays - double m_s[]; - double m_rho[]; - double m_theta[]; - double m_d[]; - double m_work[]; - double m_diagh[]; - double m_autobuf[]; - double m_x[]; - double m_g[]; - //--- matrix - CMatrixDouble m_yk; - CMatrixDouble m_sk; - CMatrixDouble m_denseh; - //--- constructor, destructor - CMinLBFGSState(void); - ~CMinLBFGSState(void); - //--- copy - void Copy(CMinLBFGSState &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinLBFGSState::CMinLBFGSState(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinLBFGSState::~CMinLBFGSState(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CMinLBFGSState::Copy(CMinLBFGSState &obj) - { -//--- copy variables - m_n=obj.m_n; - m_m=obj.m_m; - m_epsg=obj.m_epsg; - m_epsf=obj.m_epsf; - m_epsx=obj.m_epsx; - m_maxits=obj.m_maxits; - m_xrep=obj.m_xrep; - m_stpmax=obj.m_stpmax; - m_diffstep=obj.m_diffstep; - m_nfev=obj.m_nfev; - m_mcstage=obj.m_mcstage; - m_k=obj.m_k; - m_q=obj.m_q; - m_p=obj.m_p; - m_stp=obj.m_stp; - m_fold=obj.m_fold; - m_trimthreshold=obj.m_trimthreshold; - m_prectype=obj.m_prectype; - m_gammak=obj.m_gammak; - m_fbase=obj.m_fbase; - m_fm2=obj.m_fm2; - m_fm1=obj.m_fm1; - m_fp1=obj.m_fp1; - m_fp2=obj.m_fp2; - m_f=obj.m_f; - m_needf=obj.m_needf; - m_needfg=obj.m_needfg; - m_xupdated=obj.m_xupdated; - m_repiterationscount=obj.m_repiterationscount; - m_repnfev=obj.m_repnfev; - m_repterminationtype=obj.m_repterminationtype; - m_rstate.Copy(obj.m_rstate); - m_lstate.Copy(obj.m_lstate); -//--- copy arrays - ArrayCopy(m_s,obj.m_s); - ArrayCopy(m_rho,obj.m_rho); - ArrayCopy(m_theta,obj.m_theta); - ArrayCopy(m_d,obj.m_d); - ArrayCopy(m_work,obj.m_work); - ArrayCopy(m_diagh,obj.m_diagh); - ArrayCopy(m_autobuf,obj.m_autobuf); - ArrayCopy(m_x,obj.m_x); - ArrayCopy(m_g,obj.m_g); -//--- copy matrix - m_yk=obj.m_yk; - m_sk=obj.m_sk; - m_denseh=obj.m_denseh; - } -//+------------------------------------------------------------------+ -//| This class is a shell for class CMinLBFGSState | -//+------------------------------------------------------------------+ -class CMinLBFGSStateShell - { -private: - CMinLBFGSState m_innerobj; -public: - //--- constructors, destructor - CMinLBFGSStateShell(void); - CMinLBFGSStateShell(CMinLBFGSState &obj); - ~CMinLBFGSStateShell(void); - //--- methods - bool GetNeedF(void); - void SetNeedF(const bool b); - bool GetNeedFG(void); - void SetNeedFG(const bool b); - bool GetXUpdated(void); - void SetXUpdated(const bool b); - double GetF(void); - void SetF(const double d); - CMinLBFGSState *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinLBFGSStateShell::CMinLBFGSStateShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CMinLBFGSStateShell::CMinLBFGSStateShell(CMinLBFGSState &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinLBFGSStateShell::~CMinLBFGSStateShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable needf | -//+------------------------------------------------------------------+ -bool CMinLBFGSStateShell::GetNeedF(void) - { -//--- return result - return(m_innerobj.m_needf); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable needf | -//+------------------------------------------------------------------+ -void CMinLBFGSStateShell::SetNeedF(const bool b) - { -//--- change value - m_innerobj.m_needf=b; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable needfg | -//+------------------------------------------------------------------+ -bool CMinLBFGSStateShell::GetNeedFG(void) - { -//--- return result - return(m_innerobj.m_needfg); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable needfg | -//+------------------------------------------------------------------+ -void CMinLBFGSStateShell::SetNeedFG(const bool b) - { -//--- change value - m_innerobj.m_needfg=b; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable xupdated | -//+------------------------------------------------------------------+ -bool CMinLBFGSStateShell::GetXUpdated(void) - { -//--- return result - return(m_innerobj.m_xupdated); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable xupdated | -//+------------------------------------------------------------------+ -void CMinLBFGSStateShell::SetXUpdated(const bool b) - { -//--- change value - m_innerobj.m_xupdated=b; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable f | -//+------------------------------------------------------------------+ -double CMinLBFGSStateShell::GetF(void) - { -//--- return result - return(m_innerobj.m_f); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable f | -//+------------------------------------------------------------------+ -void CMinLBFGSStateShell::SetF(const double d) - { -//--- change value - m_innerobj.m_f=d; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CMinLBFGSState *CMinLBFGSStateShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Auxiliary class for CMinLFBFGS | -//+------------------------------------------------------------------+ -class CMinLBFGSReport - { -public: - //--- variables - int m_iterationscount; - int m_nfev; - int m_terminationtype; - //--- constructor, destructor - CMinLBFGSReport(void); - ~CMinLBFGSReport(void); - //--- copy - void Copy(CMinLBFGSReport &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinLBFGSReport::CMinLBFGSReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinLBFGSReport::~CMinLBFGSReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CMinLBFGSReport::Copy(CMinLBFGSReport &obj) - { -//--- copy variables - m_iterationscount=obj.m_iterationscount; - m_nfev=obj.m_nfev; - m_terminationtype=obj.m_terminationtype; - } -//+------------------------------------------------------------------+ -//| This class is a shell for class CMinLBFGSReport | -//+------------------------------------------------------------------+ -class CMinLBFGSReportShell - { -private: - CMinLBFGSReport m_innerobj; -public: - //--- constructors, destructor - CMinLBFGSReportShell(void); - CMinLBFGSReportShell(CMinLBFGSReport &obj); - ~CMinLBFGSReportShell(void); - //--- methods - int GetIterationsCount(void); - void SetIterationsCount(const int i); - int GetNFev(void); - void SetNFev(const int i); - int GetTerminationType(void); - void SetTerminationType(const int i); - CMinLBFGSReport *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinLBFGSReportShell::CMinLBFGSReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CMinLBFGSReportShell::CMinLBFGSReportShell(CMinLBFGSReport &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinLBFGSReportShell::~CMinLBFGSReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable iterationscount | -//+------------------------------------------------------------------+ -int CMinLBFGSReportShell::GetIterationsCount(void) - { -//--- return result - return(m_innerobj.m_iterationscount); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable iterationscount | -//+------------------------------------------------------------------+ -void CMinLBFGSReportShell::SetIterationsCount(const int i) - { -//--- change value - m_innerobj.m_iterationscount=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable nfev | -//+------------------------------------------------------------------+ -int CMinLBFGSReportShell::GetNFev(void) - { -//--- return result - return(m_innerobj.m_nfev); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable nfev | -//+------------------------------------------------------------------+ -void CMinLBFGSReportShell::SetNFev(const int i) - { -//--- change value - m_innerobj.m_nfev=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable terminationtype | -//+------------------------------------------------------------------+ -int CMinLBFGSReportShell::GetTerminationType(void) - { -//--- return result - return(m_innerobj.m_terminationtype); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable terminationtype | -//+------------------------------------------------------------------+ -void CMinLBFGSReportShell::SetTerminationType(const int i) - { -//--- change value - m_innerobj.m_terminationtype=i; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CMinLBFGSReport *CMinLBFGSReportShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Limited memory BFGS method for large scale optimization | -//+------------------------------------------------------------------+ -class CMinLBFGS - { -private: - //--- private method - static void ClearRequestFields(CMinLBFGSState &state); - //--- auxiliary functions for MinLBFGSiteration - static void Func_lbl_rcomm(CMinLBFGSState &state,int n,int m,int i,int j,int ic,int mcinfo,double v,double vv); - static bool Func_lbl_16(CMinLBFGSState &state,int &n,int &m,int &i,int &j,int &ic,int &mcinfo,double &v,double &vv); - static bool Func_lbl_19(CMinLBFGSState &state,int &n,int &m,int &i,int &j,int &ic,int &mcinfo,double &v,double &vv); - static bool Func_lbl_21(CMinLBFGSState &state,int &n,int &m,int &i,int &j,int &ic,int &mcinfo,double &v,double &vv); - static bool Func_lbl_23(CMinLBFGSState &state,int &n,int &m,int &i,int &j,int &ic,int &mcinfo,double &v,double &vv); - static bool Func_lbl_27(CMinLBFGSState &state,int &n,int &m,int &i,int &j,int &ic,int &mcinfo,double &v,double &vv); - static bool Func_lbl_30(CMinLBFGSState &state,int &n,int &m,int &i,int &j,int &ic,int &mcinfo,double &v,double &vv); -public: - //--- constant - static const double m_gtol; - //--- constructor, destructor - CMinLBFGS(void); - ~CMinLBFGS(void); - //--- public methods - static void MinLBFGSCreate(const int n,const int m,double &x[],CMinLBFGSState &state); - static void MinLBFGSCreateF(const int n,const int m,double &x[],const double diffstep,CMinLBFGSState &state); - static void MinLBFGSSetCond(CMinLBFGSState &state,const double epsg,const double epsf,double epsx,const int maxits); - static void MinLBFGSSetXRep(CMinLBFGSState &state,const bool needxrep); - static void MinLBFGSSetStpMax(CMinLBFGSState &state,const double stpmax); - static void MinLBFGSSetScale(CMinLBFGSState &state,double &s[]); - static void MinLBFGSCreateX(const int n,const int m,double &x[],int flags,const double diffstep,CMinLBFGSState &state); - static void MinLBFGSSetPrecDefault(CMinLBFGSState &state); - static void MinLBFGSSetPrecCholesky(CMinLBFGSState &state,CMatrixDouble &p,const bool isupper); - static void MinLBFGSSetPrecDiag(CMinLBFGSState &state,double &d[]); - static void MinLBFGSSetPrecScale(CMinLBFGSState &state); - static void MinLBFGSResults(CMinLBFGSState &state,double &x[],CMinLBFGSReport &rep); - static void MinLBFGSresultsbuf(CMinLBFGSState &state,double &x[],CMinLBFGSReport &rep); - static void MinLBFGSRestartFrom(CMinLBFGSState &state,double &x[]); - static bool MinLBFGSIteration(CMinLBFGSState &state); - }; -//+------------------------------------------------------------------+ -//| Initialize constants | -//+------------------------------------------------------------------+ -const double CMinLBFGS::m_gtol=0.4; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinLBFGS::CMinLBFGS(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinLBFGS::~CMinLBFGS(void) - { - - } -//+------------------------------------------------------------------+ -//| LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION | -//| DESCRIPTION: | -//| The subroutine minimizes function F(x) of N arguments by using a | -//| quasi - Newton method (LBFGS scheme) which is optimized to use a | -//| minimum amount of memory. | -//| The subroutine generates the approximation of an inverse Hessian | -//| matrix by using information about the last M steps of the | -//| algorithm (instead of N). It lessens a required amount of memory | -//| from a value of order N^2 to a value of order 2*N*M. | -//| REQUIREMENTS: | -//| Algorithm will request following information during its | -//| operation: | -//| * function value F and its gradient G (simultaneously) at given | -//| point X | -//| USAGE: | -//| 1. User initializes algorithm state with MinLBFGSCreate() call | -//| 2. User tunes solver parameters with MinLBFGSSetCond() | -//| MinLBFGSSetStpMax() and other functions | -//| 3. User calls MinLBFGSOptimize() function which takes algorithm | -//| state and pointer (delegate, etc.) to callback function which | -//| calculates F/G. | -//| 4. User calls MinLBFGSResults() to get solution | -//| 5. Optionally user may call MinLBFGSRestartFrom() to solve | -//| another problem with same N/M but another starting point | -//| and/or another function. MinLBFGSRestartFrom() allows to reuse| -//| already initialized structure. | -//| INPUT PARAMETERS: | -//| N - problem dimension. N>0 | -//| M - number of corrections in the BFGS scheme of | -//| Hessian approximation update. Recommended value: | -//| 3<=M<=7. The smaller value causes worse | -//| convergence, the bigger will not cause a | -//| considerably better convergence, but will cause | -//| a fall in the performance. M<=N. | -//| X - initial solution approximation, array[0..N-1]. | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTES: | -//| 1. you may tune stopping conditions with MinLBFGSSetCond() | -//| function | -//| 2. if target function contains exp() or other fast growing | -//| functions, and optimization algorithm makes too large steps | -//| which leads to overflow, use MinLBFGSSetStpMax() function to | -//| bound algorithm's steps. However, L-BFGS rarely needs such a | -//| tuning. | -//+------------------------------------------------------------------+ -static void CMinLBFGS::MinLBFGSCreate(const int n,const int m,double &x[], - CMinLBFGSState &state) - { -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(m>=1,__FUNCTION__+": M<1")) - return; -//--- check - if(!CAp::Assert(m<=n,__FUNCTION__+": M>N")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)0: | -//| * if given, only leading N elements of X are used| -//| * if not given, automatically determined from | -//| size of X | -//| M - number of corrections in the BFGS scheme of | -//| Hessian approximation update. Recommended value: | -//| 3<=M<=7. The smaller value causes worse | -//| convergence, the bigger will not cause a | -//| considerably better convergence, but will cause a| -//| fall in the performance. M<=N. | -//| X - starting point, array[0..N-1]. | -//| DiffStep- differentiation step, >0 | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTES: | -//| 1. algorithm uses 4-point central formula for differentiation. | -//| 2. differentiation step along I-th axis is equal to DiffStep*S[I]| -//| where S[] is scaling vector which can be set by | -//| MinLBFGSSetScale() call. | -//| 3. we recommend you to use moderate values of differentiation | -//| step. Too large step will result in too large truncation | -//| errors, while too small step will result in too large | -//| numerical errors. 1.0E-6 can be good value to start with. | -//| 4. Numerical differentiation is very inefficient - one gradient | -//| calculation needs 4*N function evaluations. This function will| -//| work for any N - either small (1...10), moderate (10...100) or| -//| large (100...). However, performance penalty will be too | -//| severe for any N's except for small ones. | -//| We should also say that code which relies on numerical | -//| differentiation is less robust and precise. LBFGS needs exact | -//| gradient values. Imprecise gradient may slow down convergence,| -//| especially on highly nonlinear problems. | -//| Thus we recommend to use this function for fast prototyping on| -//| small- dimensional problems only, and to implement analytical | -//| gradient as soon as possible. | -//+------------------------------------------------------------------+ -static void CMinLBFGS::MinLBFGSCreateF(const int n,const int m,double &x[], - const double diffstep,CMinLBFGSState &state) - { -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N too small!")) - return; -//--- check - if(!CAp::Assert(m>=1,__FUNCTION__+": M<1")) - return; -//--- check - if(!CAp::Assert(m<=n,__FUNCTION__+": M>N")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)0.0,__FUNCTION__+": DiffStep is non-positive!")) - return; -//--- function call - MinLBFGSCreateX(n,m,x,0,diffstep,state); - } -//+------------------------------------------------------------------+ -//| This function sets stopping conditions for L-BFGS optimization | -//| algorithm. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| EpsG - >=0 | -//| The subroutine finishes its work if the condition| -//| |v|=0 | -//| The subroutine finishes its work if on k+1-th | -//| iteration the condition |F(k+1)-F(k)| <= | -//| <= EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. | -//| EpsX - >=0 | -//| The subroutine finishes its work if on k+1-th | -//| iteration the condition |v|<=EpsX is fulfilled, | -//| where: | -//| * |.| means Euclidian norm | -//| * v - scaled step vector, v[i]=dx[i]/s[i] | -//| * dx - ste pvector, dx=X(k+1)-X(k) | -//| * s - scaling coefficients set by | -//| MinLBFGSSetScale() | -//| MaxIts - maximum number of iterations. If MaxIts=0, the | -//| number of iterations is unlimited. | -//| Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will| -//| lead to automatic stopping criterion selection (small EpsX). | -//+------------------------------------------------------------------+ -static void CMinLBFGS::MinLBFGSSetCond(CMinLBFGSState &state,const double epsg, - const double epsf,double epsx, - const int maxits) - { -//--- check - if(!CAp::Assert(CMath::IsFinite(epsg),__FUNCTION__+": EpsG is not finite number!")) - return; -//--- check - if(!CAp::Assert(epsg>=0.0,__FUNCTION__+": negative EpsG!")) - return; -//--- check - if(!CAp::Assert(CMath::IsFinite(epsf),__FUNCTION__+": EpsF is not finite number!")) - return; -//--- check - if(!CAp::Assert(epsf>=0.0,__FUNCTION__+": negative EpsF!")) - return; -//--- check - if(!CAp::Assert(CMath::IsFinite(epsx),__FUNCTION__+": EpsX is not finite number!")) - return; -//--- check - if(!CAp::Assert(epsx>=0.0,__FUNCTION__+": negative EpsX!")) - return; -//--- check - if(!CAp::Assert(maxits>=0,__FUNCTION__+": negative MaxIts!")) - return; -//--- check - if(((epsg==0.0 && epsf==0.0) && epsx==0.0) && maxits==0) - epsx=1.0E-6; -//--- change values - state.m_epsg=epsg; - state.m_epsf=epsf; - state.m_epsx=epsx; - state.m_maxits=maxits; - } -//+------------------------------------------------------------------+ -//| This function turns on/off reporting. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NeedXRep- whether iteration reports are needed or not | -//| If NeedXRep is True, algorithm will call rep() callback function | -//| if it is provided to MinLBFGSOptimize(). | -//+------------------------------------------------------------------+ -static void CMinLBFGS::MinLBFGSSetXRep(CMinLBFGSState &state,const bool needxrep) - { -//--- change value - state.m_xrep=needxrep; - } -//+------------------------------------------------------------------+ -//| This function sets maximum step length | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| StpMax - maximum step length, >=0. Set StpMax to 0.0 | -//| (default), if you don't want to limit step | -//| length. | -//| Use this subroutine when you optimize target function which | -//| contains exp() or other fast growing functions, and optimization | -//| algorithm makes too large steps which leads to overflow. This | -//| function allows us to reject steps that are too large (and | -//| therefore expose us to the possible overflow) without actually | -//| calculating function value at the x+stp*d. | -//+------------------------------------------------------------------+ -static void CMinLBFGS::MinLBFGSSetStpMax(CMinLBFGSState &state, - const double stpmax) - { -//--- check - if(!CAp::Assert(CMath::IsFinite(stpmax),__FUNCTION__+": StpMax is not finite!")) - return; -//--- check - if(!CAp::Assert(stpmax>=0.0,__FUNCTION__+": StpMax<0!")) - return; -//--- change value - state.m_stpmax=stpmax; - } -//+------------------------------------------------------------------+ -//| This function sets scaling coefficients for LBFGS optimizer. | -//| ALGLIB optimizers use scaling matrices to test stopping | -//| conditions (step size and gradient are scaled before comparison | -//| with tolerances). Scale of the I-th variable is a translation | -//| invariant measure of: | -//| a) "how large" the variable is | -//| b) how large the step should be to make significant changes in | -//| the function | -//| Scaling is also used by finite difference variant of the | -//| optimizer - step along I-th axis is equal to DiffStep*S[I]. | -//| In most optimizers (and in the LBFGS too) scaling is NOT a form | -//| of preconditioning. It just affects stopping conditions. You | -//| should set preconditioner by separate call to one of the | -//| MinLBFGSSetPrec...() functions. | -//| There is special preconditioning mode, however, which uses | -//| scaling coefficients to form diagonal preconditioning matrix. | -//| You can turn this mode on, if you want. But you should | -//| understand that scaling is not the same thing as | -//| preconditioning - these are two different, although related | -//| forms of tuning solver. | -//| INPUT PARAMETERS: | -//| State - structure stores algorithm state | -//| S - array[N], non-zero scaling coefficients | -//| S[i] may be negative, sign doesn't matter. | -//+------------------------------------------------------------------+ -static void CMinLBFGS::MinLBFGSSetScale(CMinLBFGSState &state,double &s[]) - { -//--- create a variable - int i=0; -//--- check - if(!CAp::Assert(CAp::Len(s)>=state.m_n,__FUNCTION__+": Length(S)=1,__FUNCTION__+": N too small!")) - return; -//--- check - if(!CAp::Assert(m>=1,__FUNCTION__+": M too small!")) - return; -//--- check - if(!CAp::Assert(m<=n,__FUNCTION__+": M too large!")) - return; -//--- Initialize - state.m_diffstep=diffstep; - state.m_n=n; - state.m_m=m; - allocatemem=flags%2==0; - flags=flags/2; -//--- check - if(allocatemem) - { - //--- allocation - ArrayResizeAL(state.m_rho,m); - ArrayResizeAL(state.m_theta,m); - state.m_yk.Resize(m,n); - state.m_sk.Resize(m,n); - ArrayResizeAL(state.m_d,n); - ArrayResizeAL(state.m_x,n); - ArrayResizeAL(state.m_s,n); - ArrayResizeAL(state.m_g,n); - ArrayResizeAL(state.m_work,n); - } -//--- function call - MinLBFGSSetCond(state,0,0,0,0); -//--- function call - MinLBFGSSetXRep(state,false); -//--- function call - MinLBFGSSetStpMax(state,0); -//--- function call - MinLBFGSRestartFrom(state,x); -//--- change values - for(i=0;i<=n-1;i++) - state.m_s[i]=1.0; - state.m_prectype=0; - } -//+------------------------------------------------------------------+ -//| Modification of the preconditioner: default preconditioner | -//| (simple scaling, same for all elements of X) is used. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTE: you can change preconditioner "on the fly", during | -//| algorithm iterations. | -//+------------------------------------------------------------------+ -static void CMinLBFGS::MinLBFGSSetPrecDefault(CMinLBFGSState &state) - { -//--- change value - state.m_prectype=0; - } -//+------------------------------------------------------------------+ -//| Modification of the preconditioner: Cholesky factorization of | -//| approximate Hessian is used. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| P - triangular preconditioner, Cholesky factorization| -//| of the approximate Hessian. array[0..N-1,0..N-1],| -//| (if larger, only leading N elements are used). | -//| IsUpper - whether upper or lower triangle of P is given | -//| (other triangle is not referenced) | -//| After call to this function preconditioner is changed to P (P is | -//| copied into the internal buffer). | -//| NOTE: you can change preconditioner "on the fly", during | -//| algorithm iterations. | -//| NOTE 2: P should be nonsingular. Exception will be thrown | -//| otherwise. | -//+------------------------------------------------------------------+ -static void CMinLBFGS::MinLBFGSSetPrecCholesky(CMinLBFGSState &state, - CMatrixDouble &p, - const bool isupper) - { -//--- create variables - int i=0; - double mx=0; -//--- check - if(!CAp::Assert(CApServ::IsFiniteRTrMatrix(p,state.m_n,isupper),__FUNCTION__+": P contains infinite or NAN values!")) - return; -//--- initialization - mx=0; - for(i=0;i<=state.m_n-1;i++) - mx=MathMax(mx,MathAbs(p[i][i])); -//--- check - if(!CAp::Assert((double)(mx)>0.0,__FUNCTION__+": P is strictly singular!")) - return; -//--- check - if(CAp::Rows(state.m_denseh)=state.m_n,__FUNCTION__+": D is too short")) - return; - for(i=0;i<=state.m_n-1;i++) - { - //--- check - if(!CAp::Assert(CMath::IsFinite(d[i]),__FUNCTION__+": D contains infinite or NAN elements")) - return; - //--- check - if(!CAp::Assert((double)(d[i])>0.0,__FUNCTION__+": D contains non-positive elements")) - return; - } -//--- function call - CApServ::RVectorSetLengthAtLeast(state.m_diagh,state.m_n); -//--- change values - state.m_prectype=2; - for(i=0;i<=state.m_n-1;i++) - state.m_diagh[i]=d[i]; - } -//+------------------------------------------------------------------+ -//| Modification of the preconditioner: scale-based diagonal | -//| preconditioning. | -//| This preconditioning mode can be useful when you don't have | -//| approximate diagonal of Hessian, but you know that your variables| -//| are badly scaled (for example, one variable is in [1,10], and | -//| another in [1000,100000]), and most part of the ill-conditioning | -//| comes from different scales of vars. | -//| In this case simple scale-based preconditioner, with H[i] = | -//| = 1/(s[i]^2), can greatly improve convergence. | -//| IMPRTANT: you should set scale of your variables with | -//| MinLBFGSSetScale() call (before or after MinLBFGSSetPrecScale() | -//| call). Without knowledge of the scale of your variables | -//| scale-based preconditioner will be just unit matrix. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//+------------------------------------------------------------------+ -static void CMinLBFGS::MinLBFGSSetPrecScale(CMinLBFGSState &state) - { -//--- change values - state.m_prectype=3; - } -//+------------------------------------------------------------------+ -//| L-BFGS algorithm results | -//| INPUT PARAMETERS: | -//| State - algorithm state | -//| OUTPUT PARAMETERS: | -//| X - array[0..N-1], solution | -//| Rep - optimization report: | -//| * Rep.TerminationType completetion code: | -//| * -2 rounding errors prevent further | -//| improvement. X contains best point | -//| found. | -//| * -1 incorrect parameters were specified | -//| * 1 relative function improvement is no | -//| more than EpsF. | -//| * 2 relative step is no more than EpsX. | -//| * 4 gradient norm is no more than EpsG | -//| * 5 MaxIts steps was taken | -//| * 7 stopping conditions are too | -//| stringent, further improvement is | -//| impossible | -//| * Rep.IterationsCount contains iterations count | -//| * NFEV countains number of function calculations | -//+------------------------------------------------------------------+ -static void CMinLBFGS::MinLBFGSResults(CMinLBFGSState &state,double &x[], - CMinLBFGSReport &rep) - { -//--- reset memory - ArrayResizeAL(x,0); -//--- function call - MinLBFGSresultsbuf(state,x,rep); - } -//+------------------------------------------------------------------+ -//| L-BFGS algorithm results | -//| Buffered implementation of MinLBFGSResults which uses | -//| pre-allocated buffer to store X[]. If buffer size is too small, | -//| it resizes buffer. It is intended to be used in the inner cycles | -//| of performance critical algorithms where array reallocation | -//| penalty is too large to be ignored. | -//+------------------------------------------------------------------+ -static void CMinLBFGS::MinLBFGSresultsbuf(CMinLBFGSState &state,double &x[], - CMinLBFGSReport &rep) - { -//--- create a variable - int i_=0; -//--- check - if(CAp::Len(x)=state.m_n,__FUNCTION__+": Length(X)=0) - { - //--- initialization - n=state.m_rstate.ia[0]; - m=state.m_rstate.ia[1]; - i=state.m_rstate.ia[2]; - j=state.m_rstate.ia[3]; - ic=state.m_rstate.ia[4]; - mcinfo=state.m_rstate.ia[5]; - v=state.m_rstate.ra[0]; - vv=state.m_rstate.ra[1]; - } - else - { - //--- initialization - n=-983; - m=-989; - i=-834; - j=900; - ic=-287; - mcinfo=364; - v=214; - vv=-338; - } -//--- check - if(state.m_rstate.stage==0) - { - //--- change value - state.m_needfg=false; - //--- function call - COptServ::TrimPrepare(state.m_f,state.m_trimthreshold); - //--- check - if(!state.m_xrep) - return(Func_lbl_19(state,n,m,i,j,ic,mcinfo,v,vv)); - //--- function call - ClearRequestFields(state); - //--- change values - state.m_xupdated=true; - state.m_rstate.stage=6; - //--- Saving state - Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv); - //--- return result - return(true); - } -//--- check - if(state.m_rstate.stage==1) - { - //--- change values - state.m_fbase=state.m_f; - i=0; - //--- function call, return result - return(Func_lbl_16(state,n,m,i,j,ic,mcinfo,v,vv)); - } -//--- check - if(state.m_rstate.stage==2) - { - //--- change values - state.m_fm2=state.m_f; - state.m_x[i]=v-0.5*state.m_diffstep*state.m_s[i]; - state.m_rstate.stage=3; - //--- Saving state - Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv); - //--- return result - return(true); - } -//--- check - if(state.m_rstate.stage==3) - { - //--- change values - state.m_fm1=state.m_f; - state.m_x[i]=v+0.5*state.m_diffstep*state.m_s[i]; - state.m_rstate.stage=4; - //--- Saving state - Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv); - //--- return result - return(true); - } -//--- check - if(state.m_rstate.stage==4) - { - //--- change values - state.m_fp1=state.m_f; - state.m_x[i]=v+state.m_diffstep*state.m_s[i]; - state.m_rstate.stage=5; - //--- Saving state - Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv); - //--- return result - return(true); - } -//--- check - if(state.m_rstate.stage==5) - { - //--- change values - state.m_fp2=state.m_f; - state.m_x[i]=v; - state.m_g[i]=(8*(state.m_fp1-state.m_fm1)-(state.m_fp2-state.m_fm2))/(6*state.m_diffstep*state.m_s[i]); - i=i+1; - //--- function call, return result - return(Func_lbl_16(state,n,m,i,j,ic,mcinfo,v,vv)); - } -//--- check - if(state.m_rstate.stage==6) - { - //--- change value - state.m_xupdated=false; - //--- function call, return result - return(Func_lbl_19(state,n,m,i,j,ic,mcinfo,v,vv)); - } -//--- check - if(state.m_rstate.stage==7) - { - //--- change value - state.m_needfg=false; - //--- function call - COptServ::TrimFunction(state.m_f,state.m_g,n,state.m_trimthreshold); - //--- function call - CLinMin::MCSrch(n,state.m_x,state.m_f,state.m_g,state.m_d,state.m_stp,state.m_stpmax,m_gtol,mcinfo,state.m_nfev,state.m_work,state.m_lstate,state.m_mcstage); - //--- function call, return result - return(Func_lbl_23(state,n,m,i,j,ic,mcinfo,v,vv)); - } -//--- check - if(state.m_rstate.stage==8) - { - //--- change values - state.m_fbase=state.m_f; - i=0; - //--- function call, return result - return(Func_lbl_27(state,n,m,i,j,ic,mcinfo,v,vv)); - } -//--- check - if(state.m_rstate.stage==9) - { - //--- change values - state.m_fm2=state.m_f; - state.m_x[i]=v-0.5*state.m_diffstep*state.m_s[i]; - state.m_rstate.stage=10; - //--- Saving state - Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv); - //--- return result - return(true); - } -//--- check - if(state.m_rstate.stage==10) - { - //--- change values - state.m_fm1=state.m_f; - state.m_x[i]=v+0.5*state.m_diffstep*state.m_s[i]; - state.m_rstate.stage=11; - //--- Saving state - Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv); - //--- return result - return(true); - } -//--- check - if(state.m_rstate.stage==11) - { - //--- change values - state.m_fp1=state.m_f; - state.m_x[i]=v+state.m_diffstep*state.m_s[i]; - state.m_rstate.stage=12; - //--- Saving state - Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv); - //--- return result - return(true); - } -//--- check - if(state.m_rstate.stage==12) - { - //--- change values - state.m_fp2=state.m_f; - state.m_x[i]=v; - state.m_g[i]=(8*(state.m_fp1-state.m_fm1)-(state.m_fp2-state.m_fm2))/(6*state.m_diffstep*state.m_s[i]); - i=i+1; - //--- function call, return result - return(Func_lbl_27(state,n,m,i,j,ic,mcinfo,v,vv)); - } -//--- check - if(state.m_rstate.stage==13) - { - //--- change value - state.m_xupdated=false; - //--- function call, return result - return(Func_lbl_30(state,n,m,i,j,ic,mcinfo,v,vv)); - } -//--- Routine body -//--- Unload frequently used variables from State structure -//--- (just for typing convinience) - n=state.m_n; - m=state.m_m; - state.m_repterminationtype=0; - state.m_repiterationscount=0; - state.m_repnfev=0; -//--- Calculate F/G at the initial point - ClearRequestFields(state); -//--- check - if(state.m_diffstep!=0.0) - { - //--- change values - state.m_needf=true; - state.m_rstate.stage=1; - //--- Saving state - Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv); - //--- return result - return(true); - } -//--- change values - state.m_needfg=true; - state.m_rstate.stage=0; -//--- Saving state - Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLBFGSIteration. Is a product to get | -//| rid of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static void CMinLBFGS::Func_lbl_rcomm(CMinLBFGSState &state,int n,int m, - int i,int j,int ic,int mcinfo, - double v,double vv) - { -//--- save - state.m_rstate.ia[0]=n; - state.m_rstate.ia[1]=m; - state.m_rstate.ia[2]=i; - state.m_rstate.ia[3]=j; - state.m_rstate.ia[4]=ic; - state.m_rstate.ia[5]=mcinfo; - state.m_rstate.ra[0]=v; - state.m_rstate.ra[1]=vv; - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLBFGSIteration. Is a product to get | -//| rid of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinLBFGS::Func_lbl_16(CMinLBFGSState &state,int &n,int &m, - int &i,int &j,int &ic,int &mcinfo, - double &v,double &vv) - { -//--- check - if(i>n-1) - { - //--- change values - state.m_f=state.m_fbase; - state.m_needf=false; - //--- function call - COptServ::TrimPrepare(state.m_f,state.m_trimthreshold); - //--- check - if(!state.m_xrep) - return(Func_lbl_19(state,n,m,i,j,ic,mcinfo,v,vv)); - //--- function call - ClearRequestFields(state); - //--- change values - state.m_xupdated=true; - state.m_rstate.stage=6; - //--- Saving state - Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv); - //--- return result - return(true); - } -//--- change values - v=state.m_x[i]; - state.m_x[i]=v-state.m_diffstep*state.m_s[i]; - state.m_rstate.stage=2; -//--- Saving state - Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLBFGSIteration. Is a product to get | -//| rid of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinLBFGS::Func_lbl_19(CMinLBFGSState &state,int &n,int &m, - int &i,int &j,int &ic,int &mcinfo, - double &v,double &vv) - { -//--- change values - state.m_repnfev=1; - state.m_fold=state.m_f; -//--- calculation - v=0; - for(i=0;i<=n-1;i++) - v=v+CMath::Sqr(state.m_g[i]*state.m_s[i]); -//--- check - if(MathSqrt(v)<=state.m_epsg) - { - state.m_repterminationtype=4; - //--- return result - return(false); - } -//--- Choose initial step and direction. -//--- Apply preconditioner, if we have something other than default. - for(int i_=0;i_<=n-1;i_++) - state.m_d[i_]=-state.m_g[i_]; -//--- check - if(state.m_prectype==0) - { - //--- Default preconditioner is used, but we can't use it before iterations will start - v=0.0; - for(int i_=0;i_<=n-1;i_++) - v+=state.m_g[i_]*state.m_g[i_]; - v=MathSqrt(v); - //--- check - if(state.m_stpmax==0.0) - state.m_stp=MathMin(1.0/v,1); - else - state.m_stp=MathMin(1.0/v,state.m_stpmax); - } -//--- check - if(state.m_prectype==1) - { - //--- Cholesky preconditioner is used - CFbls::FblsCholeskySolve(state.m_denseh,1.0,n,true,state.m_d,state.m_autobuf); - state.m_stp=1; - } -//--- check - if(state.m_prectype==2) - { - //--- diagonal approximation is used - for(i=0;i<=n-1;i++) - state.m_d[i]=state.m_d[i]/state.m_diagh[i]; - state.m_stp=1; - } -//--- check - if(state.m_prectype==3) - { - //--- scale-based preconditioner is used - for(i=0;i<=n-1;i++) - state.m_d[i]=state.m_d[i]*state.m_s[i]*state.m_s[i]; - state.m_stp=1; - } -//--- Main cycle - state.m_k=0; -//--- function call, return result - return(Func_lbl_21(state,n,m,i,j,ic,mcinfo,v,vv)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLBFGSIteration. Is a product to get | -//| rid of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinLBFGS::Func_lbl_21(CMinLBFGSState &state,int &n,int &m, - int &i,int &j,int &ic,int &mcinfo, - double &v,double &vv) - { -//--- Main cycle: prepare to 1-D line search - state.m_p=state.m_k % m; - state.m_q=MathMin(state.m_k, m-1); -//--- Store X[k], G[k] - for(int i_=0;i_<=n-1;i_++) - state.m_sk[state.m_p].Set(i_,-state.m_x[i_]); - for(int i_=0;i_<=n-1;i_++) - state.m_yk[state.m_p].Set(i_,-state.m_g[i_]); -//--- Minimize F(x+alpha*d) -//--- Calculate S[k], Y[k] - state.m_mcstage=0; -//--- check - if(state.m_k!=0) - state.m_stp=1.0; -//--- function call - CLinMin::LinMinNormalized(state.m_d,state.m_stp,n); -//--- function call - CLinMin::MCSrch(n,state.m_x,state.m_f,state.m_g,state.m_d,state.m_stp,state.m_stpmax,m_gtol,mcinfo,state.m_nfev,state.m_work,state.m_lstate,state.m_mcstage); -//--- function call, return result - return(Func_lbl_23(state,n,m,i,j,ic,mcinfo,v,vv)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLBFGSIteration. Is a product to get | -//| rid of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinLBFGS::Func_lbl_23(CMinLBFGSState &state,int &n,int &m, - int &i,int &j,int &ic,int &mcinfo, - double &v,double &vv) - { -//--- check - if(state.m_mcstage==0) - { - //--- check - if(!state.m_xrep) - return(Func_lbl_30(state,n,m,i,j,ic,mcinfo,v,vv)); - //--- report - ClearRequestFields(state); - //--- change values - state.m_xupdated=true; - state.m_rstate.stage=13; - //--- Saving state - Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv); - //--- return result - return(true); - } -//--- function call - ClearRequestFields(state); -//--- check - if((double)(state.m_diffstep)!=0.0) - { - //--- change values - state.m_needf=true; - state.m_rstate.stage=8; - //--- Saving state - Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv); - //--- return result - return(true); - } -//--- change values - state.m_needfg=true; - state.m_rstate.stage=7; -//--- Saving state - Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLBFGSIteration. Is a product to get | -//| rid of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinLBFGS::Func_lbl_27(CMinLBFGSState &state,int &n,int &m, - int &i,int &j,int &ic,int &mcinfo, - double &v,double &vv) - { -//--- check - if(i>n-1) - { - //--- change values - state.m_f=state.m_fbase; - state.m_needf=false; - //--- function call - COptServ::TrimFunction(state.m_f,state.m_g,n,state.m_trimthreshold); - //--- function call - CLinMin::MCSrch(n,state.m_x,state.m_f,state.m_g,state.m_d,state.m_stp,state.m_stpmax,m_gtol,mcinfo,state.m_nfev,state.m_work,state.m_lstate,state.m_mcstage); - //--- function call, return result - return(Func_lbl_23(state,n,m,i,j,ic,mcinfo,v,vv)); - } -//--- change values - v=state.m_x[i]; - state.m_x[i]=v-state.m_diffstep*state.m_s[i]; - state.m_rstate.stage=9; -//--- Saving state - Func_lbl_rcomm(state,n,m,i,j,ic,mcinfo,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLBFGSIteration. Is a product to get | -//| rid of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinLBFGS::Func_lbl_30(CMinLBFGSState &state,int &n,int &m, - int &i,int &j,int &ic,int &mcinfo, - double &v,double &vv) - { -//--- change values - state.m_repnfev=state.m_repnfev+state.m_nfev; - state.m_repiterationscount=state.m_repiterationscount+1; -//--- calculation - for(int i_=0;i_<=n-1;i_++) - state.m_sk[state.m_p].Set(i_,state.m_sk[state.m_p][i_]+state.m_x[i_]); - for(int i_=0;i_<=n-1;i_++) - state.m_yk[state.m_p].Set(i_,state.m_yk[state.m_p][i_]+state.m_g[i_]); -//--- Stopping conditions - if(state.m_repiterationscount>=state.m_maxits&&state.m_maxits>0) - { - //--- Too many iterations - state.m_repterminationtype=5; - //--- return result - return(false); - } -//--- change value - v=0; - for(i=0;i<=n-1;i++) - v=v+CMath::Sqr(state.m_g[i]*state.m_s[i]); -//--- check - if(MathSqrt(v)<=state.m_epsg) - { - //--- Gradient is small enough - state.m_repterminationtype=4; - //--- return result - return(false); - } -//--- check - if(state.m_fold-state.m_f<=state.m_epsf*MathMax(MathAbs(state.m_fold),MathMax(MathAbs(state.m_f),1.0))) - { - //--- F(k+1)-F(k) is small enough - state.m_repterminationtype=1; - //--- return result - return(false); - } -//--- change value - v=0; - for(i=0;i<=n-1;i++) - v=v+CMath::Sqr(state.m_sk[state.m_p][i]/state.m_s[i]); -//--- check - if((double)(MathSqrt(v))<=(double)(state.m_epsx)) - { - //--- X(k+1)-X(k) is small enough - state.m_repterminationtype=2; - //--- return result - return(false); - } -//--- If Wolfe conditions are satisfied, we can update -//--- limited memory model. -//--- However, if conditions are not satisfied (NFEV limit is met, -//--- function is too wild, ...), we'll skip L-BFGS update - if(mcinfo!=1) - { - //--- Skip update. - //--- In such cases we'll initialize search direction by - //--- antigradient vector, because it leads to more - //--- transparent code with less number of special cases - state.m_fold=state.m_f; - for(int i_=0;i_<=n-1;i_++) - state.m_d[i_]=-state.m_g[i_]; - } - else - { - //--- Calculate Rho[k], GammaK - v=0.0; - for(int i_=0;i_<=n-1;i_++) - v+=state.m_yk[state.m_p][i_]*state.m_sk[state.m_p][i_]; - //--- change value - vv=0.0; - for(int i_=0;i_<=n-1;i_++) - vv+=state.m_yk[state.m_p][i_]*state.m_yk[state.m_p][i_]; - //--- check - if(v==0.0 || vv==0.0) - { - //--- Rounding errors make further iterations impossible. - state.m_repterminationtype=-2; - //--- return result - return(false); - } - //--- change values - state.m_rho[state.m_p]=1/v; - state.m_gammak=v/vv; - //--- Calculate d(k+1)=-H(k+1)*g(k+1) - //--- for I:=K downto K-Q do - //--- V=s(i)^T * work(iteration:I) - //--- theta(i)=V - //--- work(iteration:I+1)=work(iteration:I)-V*Rho(i)*y(i) - //--- work(last iteration)=H0*work(last iteration)-preconditioner - //--- for I:=K-Q to K do - //--- V=y(i)^T*work(iteration:I) - //--- work(iteration:I+1)=work(iteration:I) +(-V+theta(i))*Rho(i)*s(i) - //--- NOW WORK CONTAINS d(k+1) - for(int i_=0;i_<=n-1;i_++) - state.m_work[i_]=state.m_g[i_]; - for(i=state.m_k;i>=state.m_k-state.m_q;i--) - { - ic=i%m; - v=0.0; - for(int i_=0;i_<=n-1;i_++) - v+=state.m_sk[ic][i_]*state.m_work[i_]; - //--- change values - state.m_theta[ic]=v; - vv=v*state.m_rho[ic]; - for(int i_=0;i_<=n-1;i_++) - state.m_work[i_]=state.m_work[i_]-vv*state.m_yk[ic][i_]; - } - //--- check - if(state.m_prectype==0) - { - //--- Simple preconditioner is used - v=state.m_gammak; - for(int i_=0;i_<=n-1;i_++) - state.m_work[i_]=v*state.m_work[i_]; - } - //--- check - if(state.m_prectype==1) - { - //--- Cholesky preconditioner is used - CFbls::FblsCholeskySolve(state.m_denseh,1,n,true,state.m_work,state.m_autobuf); - } - //--- check - if(state.m_prectype==2) - { - //--- diagonal approximation is used - for(i=0;i<=n-1;i++) - { - state.m_work[i]=state.m_work[i]/state.m_diagh[i]; - } - } - //--- check - if(state.m_prectype==3) - { - //--- scale-based preconditioner is used - for(i=0;i<=n-1;i++) - state.m_work[i]=state.m_work[i]*state.m_s[i]*state.m_s[i]; - } - //--- calculation - for(i=state.m_k-state.m_q;i<=state.m_k;i++) - { - ic=i%m; - v=0.0; - for(int i_=0;i_<=n-1;i_++) - v+=state.m_yk[ic][i_]*state.m_work[i_]; - //--- change value - vv=state.m_rho[ic]*(-v+state.m_theta[ic]); - for(int i_=0;i_<=n-1;i_++) - { - state.m_work[i_]=state.m_work[i_]+vv*state.m_sk[ic][i_]; - } - } - for(int i_=0;i_<=n-1;i_++) - state.m_d[i_]=-state.m_work[i_]; - //--- Next step - state.m_fold=state.m_f; - state.m_k=state.m_k+1; - } -//--- function call, return result - return(Func_lbl_21(state,n,m,i,j,ic,mcinfo,v,vv)); - } -//+------------------------------------------------------------------+ -//| This object stores nonlinear optimizer state. | -//| You should use functions provided by MinQP subpackage to work | -//| with this object | -//+------------------------------------------------------------------+ -class CMinQPState - { -public: - //--- variables - int m_n; - int m_algokind; - int m_akind; - bool m_havex; - double m_constterm; - int m_repinneriterationscount; - int m_repouteriterationscount; - int m_repncholesky; - int m_repnmv; - int m_repterminationtype; - CApBuff m_buf; - //--- arrays - double m_diaga[]; - double m_b[]; - double m_bndl[]; - double m_bndu[]; - bool m_havebndl[]; - bool m_havebndu[]; - double m_xorigin[]; - double m_startx[]; - double m_xc[]; - double m_gc[]; - int m_activeconstraints[]; - int m_prevactiveconstraints[]; - double m_workbndl[]; - double m_workbndu[]; - double m_tmp0[]; - double m_tmp1[]; - int m_itmp0[]; - int m_p2[]; - double m_bufb[]; - double m_bufx[]; - //--- matrix - CMatrixDouble m_densea; - CMatrixDouble m_bufa; - //--- constructor, destructor - CMinQPState(void); - ~CMinQPState(void); - //--- copy - void Copy(CMinQPState &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinQPState::CMinQPState(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinQPState::~CMinQPState(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CMinQPState::Copy(CMinQPState &obj) - { -//--- copy variables - m_n=obj.m_n; - m_algokind=obj.m_algokind; - m_akind=obj.m_akind; - m_havex=obj.m_havex; - m_constterm=obj.m_constterm; - m_repinneriterationscount=obj.m_repinneriterationscount; - m_repouteriterationscount=obj.m_repouteriterationscount; - m_repncholesky=obj.m_repncholesky; - m_repnmv=obj.m_repnmv; - m_repterminationtype=obj.m_repterminationtype; - m_buf.Copy(obj.m_buf); -//--- copy arrays - ArrayCopy(m_diaga,obj.m_diaga); - ArrayCopy(m_b,obj.m_b); - ArrayCopy(m_bndl,obj.m_bndl); - ArrayCopy(m_bndu,obj.m_bndu); - ArrayCopy(m_havebndl,obj.m_havebndl); - ArrayCopy(m_havebndu,obj.m_havebndu); - ArrayCopy(m_xorigin,obj.m_xorigin); - ArrayCopy(m_startx,obj.m_startx); - ArrayCopy(m_xc,obj.m_xc); - ArrayCopy(m_gc,obj.m_gc); - ArrayCopy(m_activeconstraints,obj.m_activeconstraints); - ArrayCopy(m_prevactiveconstraints,obj.m_prevactiveconstraints); - ArrayCopy(m_workbndl,obj.m_workbndl); - ArrayCopy(m_workbndu,obj.m_workbndu); - ArrayCopy(m_tmp0,obj.m_tmp0); - ArrayCopy(m_tmp1,obj.m_tmp1); - ArrayCopy(m_itmp0,obj.m_itmp0); - ArrayCopy(m_p2,obj.m_p2); - ArrayCopy(m_bufb,obj.m_bufb); - ArrayCopy(m_bufx,obj.m_bufx); -//--- copy matrix - m_densea=obj.m_densea; - m_bufa=obj.m_bufa; - } -//+------------------------------------------------------------------+ -//| This object stores nonlinear optimizer state. | -//| You should use functions provided by MinQP subpackage to work | -//| with this object | -//+------------------------------------------------------------------+ -class CMinQPStateShell - { -private: - CMinQPState m_innerobj; -public: - //--- constructors, destructor - CMinQPStateShell(void); - CMinQPStateShell(CMinQPState &obj); - ~CMinQPStateShell(void); - //--- method - CMinQPState *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinQPStateShell::CMinQPStateShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CMinQPStateShell::CMinQPStateShell(CMinQPState &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinQPStateShell::~CMinQPStateShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CMinQPState *CMinQPStateShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| This structure stores optimization report: | -//| * InnerIterationsCount number of inner iterations | -//| * OuterIterationsCount number of outer iterations | -//| * NCholesky number of Cholesky decomposition | -//| * NMV number of matrix-vector products | -//| (only products calculated as part of | -//| iterative process are counted) | -//| * TerminationType completion code (see below) | -//| Completion codes: | -//| * -5 inappropriate solver was used: | -//| * Cholesky solver for semidefinite or indefinite problems| -//| * Cholesky solver for problems with non-boundary | -//| constraints | -//| * -3 inconsistent constraints (or, maybe, feasible point is | -//| too hard to find). If you are sure that constraints are | -//| feasible, try to restart optimizer with better initial | -//| approximation. | -//| * 4 successful completion | -//| * 5 MaxIts steps was taken | -//| * 7 stopping conditions are too stringent, | -//| further improvement is impossible, | -//| X contains best point found so far. | -//+------------------------------------------------------------------+ -class CMinQPReport - { -public: - //--- variables - int m_inneriterationscount; - int m_outeriterationscount; - int m_nmv; - int m_ncholesky; - int m_terminationtype; - //--- constructor, destructor - CMinQPReport(void); - ~CMinQPReport(void); - //--- copy - void Copy(CMinQPReport &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinQPReport::CMinQPReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinQPReport::~CMinQPReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CMinQPReport::Copy(CMinQPReport &obj) - { -//--- copy variables - m_inneriterationscount=obj.m_inneriterationscount; - m_outeriterationscount=obj.m_outeriterationscount; - m_nmv=obj.m_nmv; - m_ncholesky=obj.m_ncholesky; - m_terminationtype=obj.m_terminationtype; - } -//+------------------------------------------------------------------+ -//| This structure stores optimization report: | -//| * InnerIterationsCount number of inner iterations | -//| * OuterIterationsCount number of outer iterations | -//| * NCholesky number of Cholesky decomposition | -//| * NMV number of matrix-vector products | -//| (only products calculated as part of | -//| iterative process are counted) | -//| * TerminationType completion code (see below) | -//| Completion codes: | -//| * -5 inappropriate solver was used: | -//| * Cholesky solver for semidefinite or indefinite problems| -//| * Cholesky solver for problems with non-boundary | -//| constraints | -//| * -3 inconsistent constraints (or, maybe, feasible point is | -//| too hard to find). If you are sure that constraints are | -//| feasible, try to restart optimizer with better initial | -//| approximation. | -//| * 4 successful completion | -//| * 5 MaxIts steps was taken | -//| * 7 stopping conditions are too stringent, | -//| further improvement is impossible, | -//| X contains best point found so far. | -//+------------------------------------------------------------------+ -class CMinQPReportShell - { -private: - CMinQPReport m_innerobj; -public: - //--- constructors, destructor - CMinQPReportShell(void); - CMinQPReportShell(CMinQPReport &obj); - ~CMinQPReportShell(void); - //--- methods - int GetInnerIterationsCount(void); - void SetInnerIterationsCount(const int i); - int GetOuterIterationsCount(void); - void SetOuterIterationsCount(const int i); - int GetNMV(void); - void SetNMV(const int i); - int GetNCholesky(void); - void SetNCholesky(const int i); - int GetTerminationType(void); - void SetTerminationType(const int i); - CMinQPReport *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinQPReportShell::CMinQPReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CMinQPReportShell::CMinQPReportShell(CMinQPReport &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinQPReportShell::~CMinQPReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable inneriterationscount | -//+------------------------------------------------------------------+ -int CMinQPReportShell::GetInnerIterationsCount(void) - { -//--- return result - return(m_innerobj.m_inneriterationscount); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable inneriterationscount | -//+------------------------------------------------------------------+ -void CMinQPReportShell::SetInnerIterationsCount(const int i) - { -//--- change value - m_innerobj.m_inneriterationscount=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable outeriterationscount | -//+------------------------------------------------------------------+ -int CMinQPReportShell::GetOuterIterationsCount(void) - { -//--- return result - return(m_innerobj.m_outeriterationscount); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable outeriterationscount | -//+------------------------------------------------------------------+ -void CMinQPReportShell::SetOuterIterationsCount(const int i) - { -//--- change value - m_innerobj.m_outeriterationscount=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable nmv | -//+------------------------------------------------------------------+ -int CMinQPReportShell::GetNMV(void) - { -//--- return result - return(m_innerobj.m_nmv); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable nmv | -//+------------------------------------------------------------------+ -void CMinQPReportShell::SetNMV(const int i) - { -//--- change value - m_innerobj.m_nmv=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable ncholesky | -//+------------------------------------------------------------------+ -int CMinQPReportShell::GetNCholesky(void) - { -//--- return result - return(m_innerobj.m_ncholesky); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable ncholesky | -//+------------------------------------------------------------------+ -void CMinQPReportShell::SetNCholesky(const int i) - { -//--- change value - m_innerobj.m_ncholesky=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable terminationtype | -//+------------------------------------------------------------------+ -int CMinQPReportShell::GetTerminationType(void) - { -//--- return result - return(m_innerobj.m_terminationtype); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable terminationtype | -//+------------------------------------------------------------------+ -void CMinQPReportShell::SetTerminationType(const int i) - { -//--- change value - m_innerobj.m_terminationtype=i; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CMinQPReport *CMinQPReportShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Constrained quadratic programming | -//+------------------------------------------------------------------+ -class CMinQP - { -private: - //--- private methods - static void MinQPGrad(CMinQPState &state); - static double MinQPXTAX(CMinQPState &state,double &x[]); -public: - //--- constructor, destructor - CMinQP(void); - ~CMinQP(void); - //--- public methods - static void MinQPCreate(const int n,CMinQPState &state); - static void MinQPSetLinearTerm(CMinQPState &state,double &b[]); - static void MinQPSetQuadraticTerm(CMinQPState &state,CMatrixDouble &a,const bool isupper); - static void MinQPSetStartingPoint(CMinQPState &state,double &x[]); - static void MinQPSetOrigin(CMinQPState &state,double &xorigin[]); - static void MinQPSetAlgoCholesky(CMinQPState &state); - static void MinQPSetBC(CMinQPState &state,double &bndl[],double &bndu[]); - static void MinQPOptimize(CMinQPState &state); - static void MinQPResults(CMinQPState &state,double &x[],CMinQPReport &rep); - static void MinQPResultsBuf(CMinQPState &state,double &x[],CMinQPReport &rep); - static void MinQPSetLinearTermFast(CMinQPState &state,double &b[]); - static void MinQPSetQuadraticTermFast(CMinQPState &state,CMatrixDouble &a,const bool isupper,const double s); - static void MinQPRewriteDiagonal(CMinQPState &state,double &s[]); - static void MinQPSetStartingPointFast(CMinQPState &state,double &x[]); - static void MinQPSetOriginFast(CMinQPState &state,double &xorigin[]); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinQP::CMinQP(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinQP::~CMinQP(void) - { - - } -//+------------------------------------------------------------------+ -//| CONSTRAINED QUADRATIC PROGRAMMING | -//| The subroutine creates QP optimizer. After initial creation, it | -//| contains default optimization problem with zero quadratic and | -//| linear terms and no constraints. You should set quadratic/linear | -//| terms with calls to functions provided by MinQP subpackage. | -//| INPUT PARAMETERS: | -//| N - problem size | -//| OUTPUT PARAMETERS: | -//| State - optimizer with zero quadratic/linear terms | -//| and no constraints | -//+------------------------------------------------------------------+ -static void CMinQP::MinQPCreate(const int n,CMinQPState &state) - { -//--- create a variable - int i=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1")) - return; -//--- initialize QP solver - state.m_n=n; - state.m_akind=-1; - state.m_repterminationtype=0; -//--- allocation - ArrayResizeAL(state.m_b,n); - ArrayResizeAL(state.m_bndl,n); - ArrayResizeAL(state.m_bndu,n); - ArrayResizeAL(state.m_workbndl,n); - ArrayResizeAL(state.m_workbndu,n); - ArrayResizeAL(state.m_havebndl,n); - ArrayResizeAL(state.m_havebndu,n); - ArrayResizeAL(state.m_startx,n); - ArrayResizeAL(state.m_xorigin,n); - ArrayResizeAL(state.m_xc,n); - ArrayResizeAL(state.m_gc,n); -//--- initialization - for(i=0;i<=n-1;i++) - { - state.m_b[i]=0.0; - state.m_workbndl[i]=CInfOrNaN::NegativeInfinity(); - state.m_workbndu[i]=CInfOrNaN::PositiveInfinity(); - state.m_havebndl[i]=false; - state.m_havebndu[i]=false; - state.m_startx[i]=0.0; - state.m_xorigin[i]=0.0; - } - state.m_havex=false; -//--- function call - MinQPSetAlgoCholesky(state); - } -//+------------------------------------------------------------------+ -//| This function sets linear term for QP solver. | -//| By default, linear term is zero. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| B - linear term, array[N]. | -//+------------------------------------------------------------------+ -static void CMinQP::MinQPSetLinearTerm(CMinQPState &state,double &b[]) - { -//--- create a variable - int n=0; -//--- initialization - n=state.m_n; -//--- check - if(!CAp::Assert(CAp::Len(b)>=n,__FUNCTION__+": Length(B)=n,__FUNCTION__+": Rows(A)=n,__FUNCTION__+": Cols(A)=n,__FUNCTION__+": Length(B)=n,__FUNCTION__+": Length(B)=n,__FUNCTION__+": Length(BndL)=n,__FUNCTION__+": Length(BndU)state.m_bndu[i]) - { - state.m_repterminationtype=-3; - return; - } - } - } -//--- count number of bound and linear constraints - nbc=0; - nlc=0; - for(i=0;i<=n-1;i++) - { - //--- check - if(state.m_havebndl[i]) - nbc=nbc+1; - //--- check - if(state.m_havebndu[i]) - nbc=nbc+1; - } -//--- Our formulation of quadratic problem includes origin point, -//--- i.m_e. we have F(x-x_origin) which is minimized subject to -//--- constraints on x,instead of having simply F(x). -//--- Here we make transition from non-zero origin to zero one. -//--- In order to make such transition we have to: -//--- 1. subtract x_origin from x_start -//--- 2. modify constraints -//--- 3. solve problem -//--- 4. add x_origin to solution -//--- There is alternate solution - to modify quadratic function -//--- by expansion of multipliers containing (x-x_origin),but -//--- we prefer to modify constraints,because it is a) more precise -//--- and b) easier to to. -//--- Parts (1)-(2) are done here. After this block is over, -//--- we have: -//--- * XC,which stores shifted XStart (if we don't have XStart, -//--- value of XC will be ignored later) -//--- * WorkBndL,WorkBndU,which store modified boundary constraints. - for(i=0;i<=n-1;i++) - { - state.m_xc[i]=state.m_startx[i]-state.m_xorigin[i]; - //--- check - if(state.m_havebndl[i]) - state.m_workbndl[i]=state.m_bndl[i]-state.m_xorigin[i]; - //--- check - if(state.m_havebndu[i]) - state.m_workbndu[i]=state.m_bndu[i]-state.m_xorigin[i]; - } -//--- modify starting point XC according to boundary constraints - if(state.m_havex) - { - //--- We have starting point in XC,so we just have to bound it - for(i=0;i<=n-1;i++) - { - //--- check - if(state.m_havebndl[i]) - { - //--- check - if(state.m_xc[i]state.m_workbndu[i]) - state.m_xc[i]=state.m_workbndu[i]; - } - } - } - else - { - //--- We don't have starting point,so we deduce it from - //--- constraints (if they are present). - //--- NOTE: XC contains some meaningless values from previous block - //--- which are ignored by code below. - for(i=0;i<=n-1;i++) - { - //--- check - if(state.m_havebndl[i] && state.m_havebndu[i]) - { - state.m_xc[i]=0.5*(state.m_workbndl[i]+state.m_workbndu[i]); - //--- check - if(state.m_xc[i]state.m_workbndu[i]) - state.m_xc[i]=state.m_workbndu[i]; - //--- continue iteration - continue; - } - //--- check - if(state.m_havebndl[i]) - { - state.m_xc[i]=state.m_workbndl[i]; - continue; - } - //--- check - if(state.m_havebndu[i]) - { - state.m_xc[i]=state.m_workbndu[i]; - continue; - } - state.m_xc[i]=0; - } - } -//--- Select algo - if(state.m_algokind==1 && state.m_akind==0) - { - //--- Cholesky-based algorithm for dense bound constrained problems. - //--- This algorithm exists in two variants: - //--- * unconstrained one,which can solve problem using only one NxN - //--- double matrix - //--- * bound constrained one,which needs two NxN matrices - //--- We will try to solve problem using unconstrained algorithm, - //--- and will use bound constrained version only when constraints - //--- are actually present - if(nbc==0 && nlc==0) - { - //--- "Simple" unconstrained version - CApServ::RVectorSetLengthAtLeast(state.m_tmp0,n); - //--- function call - CApServ::RVectorSetLengthAtLeast(state.m_bufb,n); - //--- calculation - state.m_densea[0].Set(0,state.m_diaga[0]); - for(k=1;k<=n-1;k++) - { - for(i_=0;i_<=k-1;i_++) - state.m_densea[i_].Set(k,state.m_densea[k][i_]); - state.m_densea[k].Set(k,state.m_diaga[k]); - } - //--- change values - for(i_=0;i_<=n-1;i_++) - state.m_bufb[i_]=state.m_b[i_]; - state.m_repncholesky=1; - //--- check - if(!CTrFac::SPDMatrixCholeskyRec(state.m_densea,0,n,true,state.m_tmp0)) - { - state.m_repterminationtype=-5; - return; - } - //--- function call - CFbls::FblsCholeskySolve(state.m_densea,1.0,n,true,state.m_bufb,state.m_tmp0); - for(i_=0;i_<=n-1;i_++) - state.m_xc[i_]=-state.m_bufb[i_]; - for(i_=0;i_<=n-1;i_++) - state.m_xc[i_]=state.m_xc[i_]+state.m_xorigin[i_]; - //--- change values - state.m_repouteriterationscount=1; - state.m_repterminationtype=4; - //--- exit the function - return; - } - //--- General bound constrained algo - CApServ::RMatrixSetLengthAtLeast(state.m_bufa,n,n); - //--- function call - CApServ::RVectorSetLengthAtLeast(state.m_bufb,n); - //--- function call - CApServ::RVectorSetLengthAtLeast(state.m_bufx,n); - //--- function call - CApServ::IVectorSetLengthAtLeast(state.m_activeconstraints,n); - //--- function call - CApServ::IVectorSetLengthAtLeast(state.m_prevactiveconstraints,n); - //--- function call - CApServ::RVectorSetLengthAtLeast(state.m_tmp0,n); - //--- Prepare constraints vectors: - //--- * ActiveConstraints - constraints active at current step - //--- * PrevActiveConstraints - constraints which were active at previous step - //--- Elements of constraints vectors can be: - //--- * 0 - inactive - //--- * 1 - active - //--- * -1 - undefined (used to initialize PrevActiveConstraints before first iteration) - for(i=0;i<=n-1;i++) - state.m_prevactiveconstraints[i]=-1; - //--- Main cycle - fprev=CMath::m_maxrealnumber; - while(true) - { - //--- * calculate gradient at XC - //--- * determine active constraints - //--- * break if there is no free variables or - //--- there were no changes in the list of active constraints - MinQPGrad(state); - nactive=0; - for(i=0;i<=n-1;i++) - { - state.m_activeconstraints[i]=0; - //--- check - if(state.m_havebndl[i]) - { - //--- check - if(state.m_xc[i]<=state.m_workbndl[i] && state.m_gc[i]>=0.0) - state.m_activeconstraints[i]=1; - } - //--- check - if(state.m_havebndu[i]) - { - //--- check - if(state.m_xc[i]>=state.m_workbndu[i] && state.m_gc[i]<=0.0) - state.m_activeconstraints[i]=1; - } - //--- check - if(state.m_havebndl[i] && state.m_havebndu[i]) - { - //--- check - if(state.m_workbndl[i]==state.m_workbndu[i]) - state.m_activeconstraints[i]=1; - } - //--- check - if(state.m_activeconstraints[i]>0) - nactive=nactive+1; - } - nfree=n-nactive; - //--- check - if(nfree==0) - break; - b=false; - for(i=0;i<=n-1;i++) - { - //--- check - if(state.m_activeconstraints[i]!=state.m_prevactiveconstraints[i]) - b=true; - } - //--- check - if(!b) - break; - //--- * copy A,B and X to buffer - //--- * rearrange BufA,BufB and BufX,in such way that active variables come first, - //--- inactive are moved to the tail. We use sorting subroutine - //--- to solve this problem. - state.m_bufa[0].Set(0,state.m_diaga[0]); - for(k=1;k<=n-1;k++) - { - for(i_=0;i_<=k-1;i_++) - state.m_bufa[k].Set(i_,state.m_densea[k][i_]); - for(i_=0;i_<=k-1;i_++) - state.m_bufa[i_].Set(k,state.m_densea[k][i_]); - state.m_bufa[k].Set(k,state.m_diaga[k]); - } - //--- change values - for(i_=0;i_<=n-1;i_++) - state.m_bufb[i_]=state.m_b[i_]; - for(i_=0;i_<=n-1;i_++) - state.m_bufx[i_]=state.m_xc[i_]; - for(i=0;i<=n-1;i++) - state.m_tmp0[i]=state.m_activeconstraints[i]; - //--- function call - CTSort::TagSortBuf(state.m_tmp0,n,state.m_itmp0,state.m_p2,state.m_buf); - for(k=0;k<=n-1;k++) - { - //--- check - if(state.m_p2[k]!=k) - { - //--- swap - v=state.m_bufb[k]; - state.m_bufb[k]=state.m_bufb[state.m_p2[k]]; - state.m_bufb[state.m_p2[k]]=v; - v=state.m_bufx[k]; - state.m_bufx[k]=state.m_bufx[state.m_p2[k]]; - state.m_bufx[state.m_p2[k]]=v; - } - } - for(i=0;i<=n-1;i++) - { - for(i_=0;i_<=n-1;i_++) - state.m_tmp0[i_]=state.m_bufa[i][i_]; - for(k=0;k<=n-1;k++) - { - //--- check - if(state.m_p2[k]!=k) - { - //--- swap - v=state.m_tmp0[k]; - state.m_tmp0[k]=state.m_tmp0[state.m_p2[k]]; - state.m_tmp0[state.m_p2[k]]=v; - } - } - for(i_=0;i_<=n-1;i_++) - state.m_bufa[i].Set(i_,state.m_tmp0[i_]); - } - for(i=0;i<=n-1;i++) - { - //--- check - if(state.m_p2[i]!=i) - { - for(i_=0;i_<=n-1;i_++) - state.m_tmp0[i_]=state.m_bufa[i][i_]; - for(i_=0;i_<=n-1;i_++) - state.m_bufa[i].Set(i_,state.m_bufa[state.m_p2[i]][i_]); - for(i_=0;i_<=n-1;i_++) - state.m_bufa[state.m_p2[i]].Set(i_,state.m_tmp0[i_]); - } - } - //--- Now we have A and B in BufA and BufB,variables are rearranged - //--- into two groups: Xf - free variables,Xc - active (fixed) variables, - //--- and our quadratic problem can be written as - //--- ( Af Ac ) ( Xf ) ( Xf ) - //--- F(X)=0.5* ( Xf' Xc' ) * ( ) * ( ) + ( Bf' Bc' ) * ( ) - //--- ( Ac' Acc ) ( Xc ) ( Xc ) - //--- we want to convert to the optimization with respect to Xf, - //--- treating Xc as constant term. After expansion of expression above - //--- we get - //--- F(Xf)=0.5*Xf'*Af*Xf + (Bf+Ac*Xc)'*Xf + 0.5*Xc'*Acc*Xc - //--- We will update BufB using this expression and calculate - //--- constant term. - CAblas::RMatrixMVect(nfree,nactive,state.m_bufa,0,nfree,0,state.m_bufx,nfree,state.m_tmp0,0); - for(i_=0;i_<=nfree-1;i_++) - state.m_bufb[i_]=state.m_bufb[i_]+state.m_tmp0[i_]; - state.m_constterm=0.0; - for(i=nfree;i<=n-1;i++) - { - state.m_constterm=state.m_constterm+0.5*state.m_bufx[i]*state.m_bufa[i][i]*state.m_bufx[i]; - for(j=i+1;j<=n-1;j++) - state.m_constterm=state.m_constterm+state.m_bufx[i]*state.m_bufa[i][j]*state.m_bufx[j]; - } - //--- Now we are ready to minimize F(Xf)... - state.m_repncholesky=state.m_repncholesky+1; - //--- check - if(!CTrFac::SPDMatrixCholeskyRec(state.m_bufa,0,nfree,true,state.m_tmp0)) - { - state.m_repterminationtype=-5; - return; - } - //--- function call - CFbls::FblsCholeskySolve(state.m_bufa,1.0,nfree,true,state.m_bufb,state.m_tmp0); - for(i_=0;i_<=nfree-1;i_++) - state.m_bufx[i_]=-state.m_bufb[i_]; - //--- ...m_and to copy results back to XC. - //--- It is done in several steps: - //--- * original order of variables is restored - //--- * result is copied back to XC - //--- * XC is bounded with respect to bound constraints - for(k=n-1;k>=0;k--) - { - //--- check - if(state.m_p2[k]!=k) - { - v=state.m_bufx[k]; - state.m_bufx[k]=state.m_bufx[state.m_p2[k]]; - state.m_bufx[state.m_p2[k]]=v; - } - } - for(i_=0;i_<=n-1;i_++) - state.m_xc[i_]=state.m_bufx[i_]; - for(i=0;i<=n-1;i++) - { - //--- check - if(state.m_havebndl[i]) - { - //--- check - if(state.m_xc[i]state.m_workbndu[i]) - state.m_xc[i]=state.m_workbndu[i]; - } - } - //--- Calculate F,compare it with FPrev. - //--- Break if F>=FPrev - //--- (sometimes possible at extremum due to numerical noise). - f=0.0; - for(i_=0;i_<=n-1;i_++) - f+=state.m_b[i_]*state.m_xc[i_]; - f=f+MinQPXTAX(state,state.m_xc); - //--- check - if(f>=fprev) - break; - fprev=f; - //--- Update PrevActiveConstraints - for(i=0;i<=n-1;i++) - state.m_prevactiveconstraints[i]=state.m_activeconstraints[i]; - //--- Update report-related fields - state.m_repouteriterationscount=state.m_repouteriterationscount+1; - } - //--- change values - state.m_repterminationtype=4; - for(i_=0;i_<=n-1;i_++) - state.m_xc[i_]=state.m_xc[i_]+state.m_xorigin[i_]; - //--- exit the function - return; - } - } -//+------------------------------------------------------------------+ -//| QP solver results | -//| INPUT PARAMETERS: | -//| State - algorithm state | -//| OUTPUT PARAMETERS: | -//| X - array[0..N-1], solution | -//| Rep - optimization report. You should check Rep. | -//| TerminationType, which contains completion code, | -//| and you may check another fields which contain | -//| another information about algorithm functioning. | -//+------------------------------------------------------------------+ -static void CMinQP::MinQPResults(CMinQPState &state,double &x[],CMinQPReport &rep) - { -//--- reset memory - ArrayResizeAL(x,0); -//--- function call - MinQPResultsBuf(state,x,rep); - } -//+------------------------------------------------------------------+ -//| QP results | -//| Buffered implementation of MinQPResults() which uses | -//| pre-allocated buffer to store X[]. If buffer size is too small, | -//| it resizes buffer. It is intended to be used in the inner cycles | -//| of performance critical algorithms where array reallocation | -//| penalty is too large to be ignored. | -//+------------------------------------------------------------------+ -static void CMinQP::MinQPResultsBuf(CMinQPState &state,double &x[], - CMinQPReport &rep) - { -//--- create a variable - int i_=0; -//--- check - if(CAp::Len(x)0)")) - return; -//--- initialization - n=state.m_n; - for(k=0;k<=n-1;k++) - state.m_diaga[k]=s[k]; - } -//+------------------------------------------------------------------+ -//| Fast version of MinQPSetStartingPoint(), which doesn't check its | -//| arguments. For internal use only. | -//+------------------------------------------------------------------+ -static void CMinQP::MinQPSetStartingPointFast(CMinQPState &state,double &x[]) - { -//--- create variables - int n=0; - int i_=0; -//--- initialization - n=state.m_n; - for(i_=0;i_<=n-1;i_++) - state.m_startx[i_]=x[i_]; - state.m_havex=true; - } -//+------------------------------------------------------------------+ -//| Fast version of MinQPSetOrigin(), which doesn't check its | -//| arguments. For internal use only. | -//+------------------------------------------------------------------+ -static void CMinQP::MinQPSetOriginFast(CMinQPState &state,double &xorigin[]) - { -//--- create variables - int n=0; - int i_=0; -//--- initialization - n=state.m_n; - for(i_=0;i_<=n-1;i_++) - state.m_xorigin[i_]=xorigin[i_]; - } -//+------------------------------------------------------------------+ -//| This function calculates gradient of quadratic function at XC and| -//| stores it in the GC. | -//+------------------------------------------------------------------+ -static void CMinQP::MinQPGrad(CMinQPState &state) - { -//--- create variables - int n=0; - int i=0; - double v=0; - int i_=0; -//--- initialization - n=state.m_n; -//--- check - if(!CAp::Assert(state.m_akind==-1||state.m_akind==0,__FUNCTION__+": internal error")) - return; -//--- zero A - if(state.m_akind==-1) - { - for(i_=0;i_<=n-1;i_++) - state.m_gc[i_]=state.m_b[i_]; - //--- exit the function - return; - } -//--- dense A - if(state.m_akind==0) - { - for(i_=0;i_<=n-1;i_++) - state.m_gc[i_]=state.m_b[i_]; - state.m_gc[0]=state.m_gc[0]+state.m_diaga[0]*state.m_xc[0]; - //--- calculation - for(i=1;i<=n-1;i++) - { - v=0.0; - for(i_=0;i_<=i-1;i_++) - v+=state.m_densea[i][i_]*state.m_xc[i_]; - state.m_gc[i]=state.m_gc[i]+v+state.m_diaga[i]*state.m_xc[i]; - v=state.m_xc[i]; - //--- change values - for(i_=0;i_<=i-1;i_++) - state.m_gc[i_]=state.m_gc[i_]+v*state.m_densea[i][i_]; - } - //--- exit the function - return; - } - } -//+------------------------------------------------------------------+ -//| This function calculates x'*A*x for given X. | -//+------------------------------------------------------------------+ -static double CMinQP::MinQPXTAX(CMinQPState &state,double &x[]) - { -//--- create variables - double result=0; - int n=0; - int i=0; - int j=0; -//--- initialization - n=state.m_n; -//--- check - if(!CAp::Assert(state.m_akind==-1 || state.m_akind==0,__FUNCTION__+": internal error")) - return(EMPTY_VALUE); - result=0; -//--- zero A - if(state.m_akind==-1) - return(0.0); -//--- dense A - if(state.m_akind==0) - { - result=0; - for(i=0;i<=n-1;i++) - { - for(j=0;j<=i-1;j++) - result=result+state.m_densea[i][j]*x[i]*x[j]; - //--- get result - result=result+0.5*state.m_diaga[i]*CMath::Sqr(x[i]); - } - //--- return result - return(result); - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Levenberg-Marquardt optimizer. | -//| This structure should be created using one of the | -//| MinLMCreate() functions. You should not access its fields | -//| directly; use ALGLIB functions to work with it. | -//+------------------------------------------------------------------+ -class CMinLMState - { -public: - //--- variables - int m_n; - int m_m; - double m_diffstep; - double m_epsg; - double m_epsf; - double m_epsx; - int m_maxits; - bool m_xrep; - double m_stpmax; - int m_maxmodelage; - bool m_makeadditers; - double m_f; - bool m_needf; - bool m_needfg; - bool m_needfgh; - bool m_needfij; - bool m_needfi; - bool m_xupdated; - int m_algomode; - bool m_hasf; - bool m_hasfi; - bool m_hasg; - double m_fbase; - double m_lambdav; - double m_nu; - int m_modelage; - bool m_deltaxready; - bool m_deltafready; - int m_repiterationscount; - int m_repterminationtype; - int m_repnfunc; - int m_repnjac; - int m_repngrad; - int m_repnhess; - int m_repncholesky; - RCommState m_rstate; - double m_actualdecrease; - double m_predicteddecrease; - double m_xm1; - double m_xp1; - CMinLBFGSState m_internalstate; - CMinLBFGSReport m_internalrep; - CMinQPState m_qpstate; - CMinQPReport m_qprep; - //--- arrays - double m_x[]; - double m_fi[]; - double m_g[]; - double m_xbase[]; - double m_fibase[]; - double m_gbase[]; - double m_bndl[]; - double m_bndu[]; - bool m_havebndl[]; - bool m_havebndu[]; - double m_s[]; - double m_xdir[]; - double m_deltax[]; - double m_deltaf[]; - double m_choleskybuf[]; - double m_tmp0[]; - double m_fm1[]; - double m_fp1[]; - //--- matrix - CMatrixDouble m_j; - CMatrixDouble m_h; - CMatrixDouble m_quadraticmodel; - //--- constructor, destructor - CMinLMState(void); - ~CMinLMState(void); - //--- copy - void Copy(CMinLMState &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinLMState::CMinLMState(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinLMState::~CMinLMState(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CMinLMState::Copy(CMinLMState &obj) - { -//--- copy variables - m_n=obj.m_n; - m_m=obj.m_m; - m_diffstep=obj.m_diffstep; - m_epsg=obj.m_epsg; - m_epsf=obj.m_epsf; - m_epsx=obj.m_epsx; - m_maxits=obj.m_maxits; - m_xrep=obj.m_xrep; - m_stpmax=obj.m_stpmax; - m_maxmodelage=obj.m_maxmodelage; - m_makeadditers=obj.m_makeadditers; - m_f=obj.m_f; - m_needf=obj.m_needf; - m_needfg=obj.m_needfg; - m_needfgh=obj.m_needfgh; - m_needfij=obj.m_needfij; - m_needfi=obj.m_needfi; - m_xupdated=obj.m_xupdated; - m_algomode=obj.m_algomode; - m_hasf=obj.m_hasf; - m_hasfi=obj.m_hasfi; - m_hasg=obj.m_hasg; - m_fbase=obj.m_fbase; - m_lambdav=obj.m_lambdav; - m_nu=obj.m_nu; - m_modelage=obj.m_modelage; - m_deltaxready=obj.m_deltaxready; - m_deltafready=obj.m_deltafready; - m_repiterationscount=obj.m_repiterationscount; - m_repterminationtype=obj.m_repterminationtype; - m_repnfunc=obj.m_repnfunc; - m_repnjac=obj.m_repnjac; - m_repngrad=obj.m_repngrad; - m_repnhess=obj.m_repnhess; - m_repncholesky=obj.m_repncholesky; - m_actualdecrease=obj.m_actualdecrease; - m_predicteddecrease=obj.m_predicteddecrease; - m_xm1=obj.m_xm1; - m_xp1=obj.m_xp1; - m_rstate.Copy(obj.m_rstate); - m_internalstate.Copy(obj.m_internalstate); - m_internalrep.Copy(obj.m_internalrep); - m_qpstate.Copy(obj.m_qpstate); - m_qprep.Copy(obj.m_qprep); -//--- copy arrays - ArrayCopy(m_x,obj.m_x); - ArrayCopy(m_fi,obj.m_fi); - ArrayCopy(m_g,obj.m_g); - ArrayCopy(m_xbase,obj.m_xbase); - ArrayCopy(m_fibase,obj.m_fibase); - ArrayCopy(m_gbase,obj.m_gbase); - ArrayCopy(m_bndl,obj.m_bndl); - ArrayCopy(m_bndu,obj.m_bndu); - ArrayCopy(m_havebndl,obj.m_havebndl); - ArrayCopy(m_havebndu,obj.m_havebndu); - ArrayCopy(m_s,obj.m_s); - ArrayCopy(m_xdir,obj.m_xdir); - ArrayCopy(m_deltax,obj.m_deltax); - ArrayCopy(m_deltaf,obj.m_deltaf); - ArrayCopy(m_choleskybuf,obj.m_choleskybuf); - ArrayCopy(m_tmp0,obj.m_tmp0); - ArrayCopy(m_fm1,obj.m_fm1); - ArrayCopy(m_fp1,obj.m_fp1); -//--- copy matrix - m_j=obj.m_j; - m_h=obj.m_h; - m_quadraticmodel=obj.m_quadraticmodel; - } -//+------------------------------------------------------------------+ -//| Levenberg-Marquardt optimizer. | -//| This structure should be created using one of the | -//| MinLMCreate() functions. You should not access its fields | -//| directly; use ALGLIB functions to work with it. | -//+------------------------------------------------------------------+ -class CMinLMStateShell - { -private: - CMinLMState m_innerobj; -public: - //--- constructors, destructor - CMinLMStateShell(void); - CMinLMStateShell(CMinLMState &obj); - ~CMinLMStateShell(void); - //--- methods - bool GetNeedF(void); - void SetNeedF(const bool b); - bool GetNeedFG(void); - void SetNeedFG(const bool b); - bool GetNeedFGH(void); - void SetNeedFGH(const bool b); - bool GetNeedFI(void); - void SetNeedFI(const bool b); - bool GetNeedFIJ(void); - void SetNeedFIJ(const bool b); - bool GetXUpdated(void); - void SetXUpdated(const bool b); - double GetF(void); - void SetF(const double d); - CMinLMState *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinLMStateShell::CMinLMStateShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CMinLMStateShell::CMinLMStateShell(CMinLMState &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinLMStateShell::~CMinLMStateShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable needf | -//+------------------------------------------------------------------+ -bool CMinLMStateShell::GetNeedF(void) - { -//--- return result - return(m_innerobj.m_needf); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable needf | -//+------------------------------------------------------------------+ -void CMinLMStateShell::SetNeedF(const bool b) - { -//--- change value - m_innerobj.m_needf=b; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable needfg | -//+------------------------------------------------------------------+ -bool CMinLMStateShell::GetNeedFG(void) - { -//--- return result - return(m_innerobj.m_needfg); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable needfg | -//+------------------------------------------------------------------+ -void CMinLMStateShell::SetNeedFG(const bool b) - { -//--- change value - m_innerobj.m_needfg=b; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable needfgh | -//+------------------------------------------------------------------+ -bool CMinLMStateShell::GetNeedFGH(void) - { -//--- return result - return(m_innerobj.m_needfgh); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable needfgh | -//+------------------------------------------------------------------+ -void CMinLMStateShell::SetNeedFGH(const bool b) - { -//--- change value - m_innerobj.m_needfgh=b; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable needfi | -//+------------------------------------------------------------------+ -bool CMinLMStateShell::GetNeedFI(void) - { -//--- return result - return(m_innerobj.m_needfi); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable needfi | -//+------------------------------------------------------------------+ -void CMinLMStateShell::SetNeedFI(const bool b) - { -//--- change value - m_innerobj.m_needfi=b; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable needfij | -//+------------------------------------------------------------------+ -bool CMinLMStateShell::GetNeedFIJ(void) - { -//--- return result - return(m_innerobj.m_needfij); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable needfij | -//+------------------------------------------------------------------+ -void CMinLMStateShell::SetNeedFIJ(const bool b) - { -//--- change value - m_innerobj.m_needfij=b; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable xupdated | -//+------------------------------------------------------------------+ -bool CMinLMStateShell::GetXUpdated(void) - { -//--- return result - return(m_innerobj.m_xupdated); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable xupdated | -//+------------------------------------------------------------------+ -void CMinLMStateShell::SetXUpdated(const bool b) - { -//--- change value - m_innerobj.m_xupdated=b; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable f | -//+------------------------------------------------------------------+ -double CMinLMStateShell::GetF(void) - { -//--- return result - return(m_innerobj.m_f); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable f | -//+------------------------------------------------------------------+ -void CMinLMStateShell::SetF(const double d) - { -//--- change value - m_innerobj.m_f=d; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CMinLMState *CMinLMStateShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Optimization report, filled by MinLMResults() function | -//| FIELDS: | -//| * TerminationType, completetion code: | -//| * -9 derivative correctness check failed; | -//| see Rep.WrongNum, Rep.WrongI, Rep.WrongJ for | -//| more information. | -//| * 1 relative function improvement is no more than | -//| EpsF. | -//| * 2 relative step is no more than EpsX. | -//| * 4 gradient is no more than EpsG. | -//| * 5 MaxIts steps was taken | -//| * 7 stopping conditions are too stringent, | -//| further improvement is impossible | -//| * IterationsCount, contains iterations count | -//| * NFunc, number of function calculations | -//| * NJac, number of Jacobi matrix calculations | -//| * NGrad, number of gradient calculations | -//| * NHess, number of Hessian calculations | -//| * NCholesky, number of Cholesky decomposition calculations | -//+------------------------------------------------------------------+ -class CMinLMReport - { -public: - //--- variables - int m_iterationscount; - int m_terminationtype; - int m_nfunc; - int m_njac; - int m_ngrad; - int m_nhess; - int m_ncholesky; - //--- constructor, destructor - CMinLMReport(void); - ~CMinLMReport(void); - //--- copy - void Copy(CMinLMReport &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinLMReport::CMinLMReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinLMReport::~CMinLMReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CMinLMReport::Copy(CMinLMReport &obj) - { -//--- copy variables - m_iterationscount=obj.m_iterationscount; - m_terminationtype=obj.m_terminationtype; - m_nfunc=obj.m_nfunc; - m_njac=obj.m_njac; - m_ngrad=obj.m_ngrad; - m_nhess=obj.m_nhess; - m_ncholesky=obj.m_ncholesky; - } -//+------------------------------------------------------------------+ -//| Optimization report, filled by MinLMResults() function | -//| FIELDS: | -//| * TerminationType, completetion code: | -//| * -9 derivative correctness check failed; | -//| see Rep.WrongNum, Rep.WrongI, Rep.WrongJ for | -//| more information. | -//| * 1 relative function improvement is no more than | -//| EpsF. | -//| * 2 relative step is no more than EpsX. | -//| * 4 gradient is no more than EpsG. | -//| * 5 MaxIts steps was taken | -//| * 7 stopping conditions are too stringent, | -//| further improvement is impossible | -//| * IterationsCount, contains iterations count | -//| * NFunc, number of function calculations | -//| * NJac, number of Jacobi matrix calculations | -//| * NGrad, number of gradient calculations | -//| * NHess, number of Hessian calculations | -//| * NCholesky, number of Cholesky decomposition calculations | -//+------------------------------------------------------------------+ -class CMinLMReportShell - { -private: - CMinLMReport m_innerobj; -public: - //--- constructors, destructor - CMinLMReportShell(void); - CMinLMReportShell(CMinLMReport &obj); - ~CMinLMReportShell(void); - //--- methods - int GetIterationsCount(void); - void SetIterationsCount(const int i); - int GetTerminationType(void); - void SetTerminationType(const int i); - int GetNFunc(void); - void SetNFunc(const int i); - int GetNJAC(void); - void SetNJAC(const int i); - int GetNGrad(void); - void SetNGrad(const int i); - int GetNHess(void); - void SetNHess(const int i); - int GetNCholesky(void); - void SetNCholesky(const int i); - CMinLMReport *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinLMReportShell::CMinLMReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CMinLMReportShell::CMinLMReportShell(CMinLMReport &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinLMReportShell::~CMinLMReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable iterationscount | -//+------------------------------------------------------------------+ -int CMinLMReportShell::GetIterationsCount(void) - { -//--- return result - return(m_innerobj.m_iterationscount); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable iterationscount | -//+------------------------------------------------------------------+ -void CMinLMReportShell::SetIterationsCount(const int i) - { -//--- change value - m_innerobj.m_iterationscount=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable terminationtype | -//+------------------------------------------------------------------+ -int CMinLMReportShell::GetTerminationType(void) - { -//--- return result - return(m_innerobj.m_terminationtype); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable terminationtype | -//+------------------------------------------------------------------+ -void CMinLMReportShell::SetTerminationType(const int i) - { -//--- change value - m_innerobj.m_terminationtype=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable nfunc | -//+------------------------------------------------------------------+ -int CMinLMReportShell::GetNFunc(void) - { -//--- return result - return(m_innerobj.m_nfunc); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable nfunc | -//+------------------------------------------------------------------+ -void CMinLMReportShell::SetNFunc(const int i) - { -//--- change value - m_innerobj.m_nfunc=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable njac | -//+------------------------------------------------------------------+ -int CMinLMReportShell::GetNJAC(void) - { -//--- return result - return(m_innerobj.m_njac); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable njac | -//+------------------------------------------------------------------+ -void CMinLMReportShell::SetNJAC(const int i) - { -//--- change value - m_innerobj.m_njac=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable ngrad | -//+------------------------------------------------------------------+ -int CMinLMReportShell::GetNGrad(void) - { -//--- return result - return(m_innerobj.m_ngrad); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable ngrad | -//+------------------------------------------------------------------+ -void CMinLMReportShell::SetNGrad(const int i) - { -//--- change value - m_innerobj.m_ngrad=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable nhess | -//+------------------------------------------------------------------+ -int CMinLMReportShell::GetNHess(void) - { -//--- return result - return(m_innerobj.m_nhess); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable nhess | -//+------------------------------------------------------------------+ -void CMinLMReportShell::SetNHess(const int i) - { -//--- change value - m_innerobj.m_nhess=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable ncholesky | -//+------------------------------------------------------------------+ -int CMinLMReportShell::GetNCholesky(void) - { -//--- return result - return(m_innerobj.m_ncholesky); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable ncholesky | -//+------------------------------------------------------------------+ -void CMinLMReportShell::SetNCholesky(const int i) - { -//--- change value - m_innerobj.m_ncholesky=i; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CMinLMReport *CMinLMReportShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Levenberg-Marquardt method | -//+------------------------------------------------------------------+ -class CMinLM - { -private: - //--- private methods - static void LMPRepare(const int n,const int m,bool havegrad,CMinLMState &state); - static void ClearRequestFields(CMinLMState &state); - static bool IncreaseLambda(double &lambdav,double &nu); - static void DecreaseLambda(double &lambdav,double &nu); - static double BoundedScaledAntigradNorm(CMinLMState &state,double &x[],double &g[]); - //--- auxiliary functions for MinLMIteration - static void Func_lbl_rcomm(CMinLMState &state,int n,int m,int iflag,int i,int k,bool bflag,double v,double s,double t); - static bool Func_lbl_16(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t); - static bool Func_lbl_19(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t); - static bool Func_lbl_20(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t); - static bool Func_lbl_21(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t); - static bool Func_lbl_22(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t); - static bool Func_lbl_24(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t); - static bool Func_lbl_25(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t); - static bool Func_lbl_28(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t); - static bool Func_lbl_31(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t); - static bool Func_lbl_39(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t); - static bool Func_lbl_40(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t); - static bool Func_lbl_41(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t); - static bool Func_lbl_48(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t); - static bool Func_lbl_49(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t); - static bool Func_lbl_55(CMinLMState &state,int &n,int &m,int &iflag,int &i,int &k,bool &bflag,double &v,double &s,double &t); -public: - //--- class constants - static const int m_lmmodefj; - static const int m_lmmodefgj; - static const int m_lmmodefgh; - static const int m_lmflagnopreLBFGS; - static const int m_lmflagnointLBFGS; - static const int m_lmpreLBFGSm; - static const int m_lmintLBFGSits; - static const int m_lbfgsnorealloc; - static const double m_lambdaup; - static const double m_lambdadown; - static const double m_suspiciousnu; - static const int m_smallmodelage; - static const int m_additers; - //--- constructor, destructor - CMinLM(void); - ~CMinLM(void); - //--- public methods - static void MinLMCreateVJ(const int n,const int m,double &x[],CMinLMState &state); - static void MinLMCreateV(const int n,const int m,double &x[],const double diffstep,CMinLMState &state); - static void MinLMCreateFGH(const int n,double &x[],CMinLMState &state); - static void MinLMSetCond(CMinLMState &state,const double epsg,const double epsf,double epsx,const int maxits); - static void MinLMSetXRep(CMinLMState &state,const bool needxrep); - static void MinLMSetStpMax(CMinLMState &state,const double stpmax); - static void MinLMSetScale(CMinLMState &state,double &s[]); - static void MinLMSetBC(CMinLMState &state,double &bndl[],double &bndu[]); - static void MinLMSetAccType(CMinLMState &state,int acctype); - static void MinLMResults(CMinLMState &state,double &x[],CMinLMReport &rep); - static void MinLMResultsBuf(CMinLMState &state,double &x[],CMinLMReport &rep); - static void MinLMRestartFrom(CMinLMState &state,double &x[]); - static void MinLMCreateVGJ(const int n,const int m,double &x[],CMinLMState &state); - static void MinLMCreateFGJ(const int n,const int m,double &x[],CMinLMState &state); - static void MinLMCreateFJ(const int n,const int m,double &x[],CMinLMState &state); - static bool MinLMIteration(CMinLMState &state); - }; -//+------------------------------------------------------------------+ -//| Initialize constants | -//+------------------------------------------------------------------+ -const int CMinLM::m_lmmodefj=0; -const int CMinLM::m_lmmodefgj=1; -const int CMinLM::m_lmmodefgh=2; -const int CMinLM::m_lmflagnopreLBFGS=1; -const int CMinLM::m_lmflagnointLBFGS=2; -const int CMinLM::m_lmpreLBFGSm=5; -const int CMinLM::m_lmintLBFGSits=5; -const int CMinLM::m_lbfgsnorealloc=1; -const double CMinLM::m_lambdaup=2.0; -const double CMinLM::m_lambdadown=0.33; -const double CMinLM::m_suspiciousnu=16; -const int CMinLM::m_smallmodelage=3; -const int CMinLM::m_additers=5; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinLM::CMinLM(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinLM::~CMinLM(void) - { - - } -//+------------------------------------------------------------------+ -//| IMPROVED LEVENBERG-MARQUARDT METHOD FOR | -//| NON-LINEAR LEAST SQUARES OPTIMIZATION | -//| DESCRIPTION: | -//| This function is used to find minimum of function which is | -//| represented as sum of squares: | -//| F(x) = f[0]^2(x[0],...,x[n-1]) + ... + | -//| + f[m-1]^2(x[0],...,x[n-1]) | -//| using value of function vector f[] and Jacobian of f[]. | -//| REQUIREMENTS: | -//| This algorithm will request following information during its | -//| operation: | -//| * function vector f[] at given point X | -//| * function vector f[] and Jacobian of f[] (simultaneously) at | -//| given point | -//| There are several overloaded versions of MinLMOptimize() | -//| function which correspond to different LM-like optimization | -//| algorithms provided by this unit. You should choose version which| -//| accepts fvec() and jac() callbacks. First one is used to | -//| calculate f[] at given point, second one calculates f[] and | -//| Jacobian df[i]/dx[j]. | -//| You can try to initialize MinLMState structure with VJ function | -//| and then use incorrect version of MinLMOptimize() (for example,| -//| version which works with general form function and does not | -//| provide Jacobian), but it will lead to exception being thrown | -//| after first attempt to calculate Jacobian. | -//| USAGE: | -//| 1. User initializes algorithm state with MinLMCreateVJ() call | -//| 2. User tunes solver parameters with MinLMSetCond(), | -//| MinLMSetStpMax() and other functions | -//| 3. User calls MinLMOptimize() function which takes algorithm | -//| state and callback functions. | -//| 4. User calls MinLMResults() to get solution | -//| 5. Optionally, user may call MinLMRestartFrom() to solve another | -//| problem with same N/M but another starting point and/or | -//| another function. MinLMRestartFrom() allows to reuse already | -//| initialized structure. | -//| INPUT PARAMETERS: | -//| N - dimension, N>1 | -//| * if given, only leading N elements of X are | -//| used | -//| * if not given, automatically determined from | -//| size of X | -//| M - number of functions f[i] | -//| X - initial solution, array[0..N-1] | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTES: | -//| 1. you may tune stopping conditions with MinLMSetCond() function | -//| 2. if target function contains exp() or other fast growing | -//| functions, and optimization algorithm makes too large steps | -//| which leads to overflow, use MinLMSetStpMax() function to | -//| bound algorithm's steps. | -//+------------------------------------------------------------------+ -static void CMinLM::MinLMCreateVJ(const int n,const int m,double &x[], - CMinLMState &state) - { -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(m>=1,__FUNCTION__+": M<1!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)1 | -//| * if given, only leading N elements of X are | -//| used | -//| * if not given, automatically determined from | -//| size of X | -//| M - number of functions f[i] | -//| X - initial solution, array[0..N-1] | -//| DiffStep- differentiation step, >0 | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| See also MinLMIteration, MinLMResults. | -//| NOTES: | -//| 1. you may tune stopping conditions with MinLMSetCond() function | -//| 2. if target function contains exp() or other fast growing | -//| functions, and optimization algorithm makes too large steps | -//| which leads to overflow, use MinLMSetStpMax() function to | -//| bound algorithm's steps. | -//+------------------------------------------------------------------+ -static void CMinLM::MinLMCreateV(const int n,const int m,double &x[], - const double diffstep,CMinLMState &state) - { -//--- check - if(!CAp::Assert(CMath::IsFinite(diffstep),__FUNCTION__+": DiffStep is not finite!")) - return; -//--- check - if(!CAp::Assert(diffstep>0.0,__FUNCTION__+": DiffStep<=0!")) - return; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(m>=1,__FUNCTION__+": M<1!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)1 | -//| * if given, only leading N elements of X are | -//| used | -//| * if not given, automatically determined from | -//| size of X | -//| X - initial solution, array[0..N-1] | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTES: | -//| 1. you may tune stopping conditions with MinLMSetCond() function | -//| 2. if target function contains exp() or other fast growing | -//| functions, and optimization algorithm makes too large steps | -//| which leads to overflow, use MinLMSetStpMax() function to | -//| bound algorithm's steps. | -//+------------------------------------------------------------------+ -static void CMinLM::MinLMCreateFGH(const int n,double &x[],CMinLMState &state) - { -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=0 | -//| The subroutine finishes its work if the | -//| condition |v|=0 | -//| The subroutine finishes its work if on k+1-th | -//| iteration the condition |F(k+1)-F(k)| <= | -//| <= EpsF*max{|F(k)|,|F(k+1)|,1} is satisfied. | -//| EpsX - >=0 | -//| The subroutine finishes its work if on k+1-th | -//| iteration the condition |v|<=EpsX is fulfilled, | -//| where: | -//| * |.| means Euclidian norm | -//| * v - scaled step vector, v[i]=dx[i]/s[i] | -//| * dx - ste pvector, dx=X(k+1)-X(k) | -//| * s - scaling coefficients set by MinLMSetScale()| -//| MaxIts - maximum number of iterations. If MaxIts=0, the | -//| number of iterations is unlimited. Only | -//| Levenberg-Marquardt iterations are counted | -//| (L-BFGS/CG iterations are NOT counted because | -//| their cost is very low compared to that of LM). | -//| Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will| -//| lead to automatic stopping criterion selection (small EpsX). | -//+------------------------------------------------------------------+ -static void CMinLM::MinLMSetCond(CMinLMState &state,const double epsg, - const double epsf,double epsx, - const int maxits) - { -//--- check - if(!CAp::Assert(CMath::IsFinite(epsg),__FUNCTION__+": EpsG is not finite number!")) - return; -//--- check - if(!CAp::Assert(epsg>=0.0,__FUNCTION__+": negative EpsG!")) - return; -//--- check - if(!CAp::Assert(CMath::IsFinite(epsf),__FUNCTION__+": EpsF is not finite number!")) - return; -//--- check - if(!CAp::Assert(epsf>=0.0,__FUNCTION__+": negative EpsF!")) - return; -//--- check - if(!CAp::Assert(CMath::IsFinite(epsx),__FUNCTION__+": EpsX is not finite number!")) - return; -//--- check - if(!CAp::Assert(epsx>=0.0,__FUNCTION__+": negative EpsX!")) - return; -//--- check - if(!CAp::Assert(maxits>=0,__FUNCTION__+": negative MaxIts!")) - return; -//--- check - if(((epsg==0.0 && epsf==0.0) && epsx==0.0) && maxits==0) - epsx=1.0E-6; -//--- change values - state.m_epsg=epsg; - state.m_epsf=epsf; - state.m_epsx=epsx; - state.m_maxits=maxits; - } -//+------------------------------------------------------------------+ -//| This function turns on/off reporting. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NeedXRep- whether iteration reports are needed or not | -//| If NeedXRep is True, algorithm will call rep() callback function | -//| if it is provided to MinLMOptimize(). Both Levenberg-Marquardt | -//| and internal L-BFGS iterations are reported. | -//+------------------------------------------------------------------+ -static void CMinLM::MinLMSetXRep(CMinLMState &state,const bool needxrep) - { -//--- change value - state.m_xrep=needxrep; - } -//+------------------------------------------------------------------+ -//| This function sets maximum step length | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| StpMax - maximum step length, >=0. Set StpMax to 0.0, if | -//| you don't want to limit step length. | -//| Use this subroutine when you optimize target function which | -//| contains exp() or other fast growing functions, and optimization | -//| algorithm makes too large steps which leads to overflow. This | -//| function allows us to reject steps that are too large (and | -//| therefore expose us to the possible overflow) without actually | -//| calculating function value at the x+stp*d. | -//| NOTE: non-zero StpMax leads to moderate performance degradation | -//| because intermediate step of preconditioned L-BFGS optimization | -//| is incompatible with limits on step size. | -//+------------------------------------------------------------------+ -static void CMinLM::MinLMSetStpMax(CMinLMState &state,const double stpmax) - { -//--- check - if(!CAp::Assert(CMath::IsFinite(stpmax),__FUNCTION__+": StpMax is not finite!")) - return; -//--- check - if(!CAp::Assert(stpmax>=0.0,__FUNCTION__+": StpMax<0!")) - return; -//--- change value - state.m_stpmax=stpmax; - } -//+------------------------------------------------------------------+ -//| This function sets scaling coefficients for LM optimizer. | -//| ALGLIB optimizers use scaling matrices to test stopping | -//| conditions (step size and gradient are scaled before comparison | -//| with tolerances). Scale of the I-th variable is a translation | -//| invariant measure of: | -//| a) "how large" the variable is | -//| b) how large the step should be to make significant changes in | -//| the function | -//| Generally, scale is NOT considered to be a form of | -//| preconditioner. But LM optimizer is unique in that it uses | -//| scaling matrix both in the stopping condition tests and as | -//| Marquardt damping factor. | -//| Proper scaling is very important for the algorithm performance. | -//| It is less important for the quality of results, but still has | -//| some influence (it is easier to converge when variables are | -//| properly scaled, so premature stopping is possible when very | -//| badly scalled variables are combined with relaxed stopping | -//| conditions). | -//| INPUT PARAMETERS: | -//| State - structure stores algorithm state | -//| S - array[N], non-zero scaling coefficients | -//| S[i] may be negative, sign doesn't matter. | -//+------------------------------------------------------------------+ -static void CMinLM::MinLMSetScale(CMinLMState &state,double &s[]) - { -//--- create a variable - int i=0; -//--- check - if(!CAp::Assert(CAp::Len(s)>=state.m_n,__FUNCTION__+": Length(S)=n,__FUNCTION__+": Length(BndL)=n,__FUNCTION__+": Length(BndU)=state.m_n,__FUNCTION__+": Length(X)=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(m>=1,__FUNCTION__+": M<1!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)0.25*lnmax) - { - //--- return result - return(result); - } -//--- check - if(lnnu+MathLog(2)>lnmax) - return(result); -//--- change values - lambdav=lambdav*m_lambdaup*nu; - nu=nu*2; - result=true; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Decreases lambda, but leaves it unchanged when there is danger of| -//| underflow. | -//+------------------------------------------------------------------+ -static void CMinLM::DecreaseLambda(double &lambdav,double &nu) - { -//--- initialization - nu=1; -//--- check - if(MathLog(lambdav)+MathLog(m_lambdadown)0)and(x[i]=bndu[i])) | -//| v[i]=-g[i]*s[i] otherwise, where s[i] is a scale for I-th | -//| variable | -//| This function may be used to check a stopping criterion. | -//+------------------------------------------------------------------+ -static double CMinLM::BoundedScaledAntigradNorm(CMinLMState &state, - double &x[],double &g[]) - { -//--- create variables - double result=0; - int n=0; - int i=0; - double v=0; -//--- initialization - result=0; - n=state.m_n; - for(i=0;i<=n-1;i++) - { - v=-(g[i]*state.m_s[i]); - //--- check - if(state.m_havebndl[i]) - { - //--- check - if(x[i]<=state.m_bndl[i] && (double)(-g[i])<0.0) - v=0; - } - //--- check - if(state.m_havebndu[i]) - { - //--- check - if(x[i]>=state.m_bndu[i] && (double)(-g[i])>0.0) - v=0; - } - result=result+CMath::Sqr(v); - } -//--- return result - return(MathSqrt(result)); - } -//+------------------------------------------------------------------+ -//| NOTES: | -//| 1. Depending on function used to create state structure, this | -//| algorithm may accept Jacobian and/or Hessian and/or gradient. | -//| According to the said above, there ase several versions of | -//| this function, which accept different sets of callbacks. | -//| This flexibility opens way to subtle errors - you may create | -//| state with MinLMCreateFGH() (optimization using Hessian), but | -//| call function which does not accept Hessian. So when | -//| algorithm will request Hessian, there will be no callback to | -//| call. In this case exception will be thrown. | -//| Be careful to avoid such errors because there is no way to | -//| find them at compile time - you can see them at runtime only. | -//+------------------------------------------------------------------+ -static bool CMinLM::MinLMIteration(CMinLMState &state) - { -//--- create variables - int n=0; - int m=0; - bool bflag; - int iflag=0; - double v=0; - double s=0; - double t=0; - int i=0; - int k=0; - int i_=0; -//--- This code initializes locals by: -//--- * random values determined during code -//--- generation - on first subroutine call -//--- * values from previous call - on subsequent calls - if(state.m_rstate.stage>=0) - { - //--- initialization - n=state.m_rstate.ia[0]; - m=state.m_rstate.ia[1]; - iflag=state.m_rstate.ia[2]; - i=state.m_rstate.ia[3]; - k=state.m_rstate.ia[4]; - bflag=state.m_rstate.ba[0]; - v=state.m_rstate.ra[0]; - s=state.m_rstate.ra[1]; - t=state.m_rstate.ra[2]; - } - else - { - //--- initialization - n=-983; - m=-989; - iflag=-834; - i=900; - k=-287; - bflag=false; - v=214; - s=-338; - t=-686; - } -//--- check - if(state.m_rstate.stage==0) - { - //--- change value - state.m_needf=false; - //--- function call, return result - return(Func_lbl_19(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//--- check - if(state.m_rstate.stage==1) - { - //--- change values - state.m_needfi=false; - v=0.0; - for(i_=0;i_<=m-1;i_++) - v+=state.m_fi[i_]*state.m_fi[i_]; - state.m_f=v; - //--- function call, return result - return(Func_lbl_19(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//--- check - if(state.m_rstate.stage==2) - { - //--- change value - state.m_xupdated=false; - //--- function call, return result - return(Func_lbl_16(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//--- check - if(state.m_rstate.stage==3) - { - //--- change value - state.m_repnfunc=state.m_repnfunc+1; - //--- copy - for(i_=0;i_<=m-1;i_++) - state.m_fm1[i_]=state.m_fi[i_]; - for(i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xbase[i_]; - state.m_x[k]=state.m_x[k]+state.m_s[k]*state.m_diffstep; - //--- check - if(state.m_havebndl[k]) - state.m_x[k]=MathMax(state.m_x[k],state.m_bndl[k]); - //--- check - if(state.m_havebndu[k]) - state.m_x[k]=MathMin(state.m_x[k],state.m_bndu[k]); - state.m_xp1=state.m_x[k]; - //--- function call - ClearRequestFields(state); - state.m_needfi=true; - state.m_rstate.stage=4; - //--- Saving state - Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t); - //--- return result - return(true); - } -//--- check - if(state.m_rstate.stage==4) - { - //--- change value - state.m_repnfunc=state.m_repnfunc+1; - //--- copy - for(i_=0;i_<=m-1;i_++) - state.m_fp1[i_]=state.m_fi[i_]; - v=state.m_xp1-state.m_xm1; - //--- check - if(v!=0.0) - { - v=1/v; - for(i_=0;i_<=m-1;i_++) - state.m_j[i_].Set(k,v*state.m_fp1[i_]); - for(i_=0;i_<=m-1;i_++) - state.m_j[i_].Set(k,state.m_j[i_][k]-v*state.m_fm1[i_]); - } - else - { - for(i=0;i<=m-1;i++) - state.m_j[i].Set(k,0); - } - k=k+1; - //--- function call, return result - return(Func_lbl_28(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//--- check - if(state.m_rstate.stage==5) - { - //--- change values - state.m_needfi=false; - state.m_repnfunc=state.m_repnfunc+1; - state.m_repnjac=state.m_repnjac+1; - //--- New model - state.m_modelage=0; - //--- function call, return result - return(Func_lbl_25(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//--- check - if(state.m_rstate.stage==6) - { - //--- change values - state.m_needfij=false; - state.m_repnfunc=state.m_repnfunc+1; - state.m_repnjac=state.m_repnjac+1; - //--- New model - state.m_modelage=0; - //--- function call, return result - return(Func_lbl_25(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//--- check - if(state.m_rstate.stage==7) - { - //--- change values - state.m_needfgh=false; - state.m_repnfunc=state.m_repnfunc+1; - state.m_repngrad=state.m_repngrad+1; - state.m_repnhess=state.m_repnhess+1; - //--- function call - CAblas::RMatrixCopy(n,n,state.m_h,0,0,state.m_quadraticmodel,0,0); - for(i_=0;i_<=n-1;i_++) - state.m_gbase[i_]=state.m_g[i_]; - state.m_fbase=state.m_f; - //--- set control variables - bflag=true; - state.m_modelage=0; - //--- function call, return result - return(Func_lbl_31(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//--- check - if(state.m_rstate.stage==8) - { - //--- change value - state.m_xupdated=false; - //--- return result - return(false); - } -//--- check - if(state.m_rstate.stage==9) - { - //--- change value - state.m_xupdated=false; - //--- return result - return(false); - } -//--- check - if(state.m_rstate.stage==10) - { - //--- change values - state.m_needfi=false; - v=0.0; - for(i_=0;i_<=m-1;i_++) - v+=state.m_fi[i_]*state.m_fi[i_]; - state.m_f=v; - //--- copy - for(i_=0;i_<=m-1;i_++) - state.m_deltaf[i_]=state.m_fi[i_]; - for(i_=0;i_<=m-1;i_++) - state.m_deltaf[i_]=state.m_deltaf[i_]-state.m_fibase[i_]; - state.m_deltafready=true; - //--- function call, return result - return(Func_lbl_48(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//--- check - if(state.m_rstate.stage==11) - { - //--- change value - state.m_needf=false; - //--- function call, return result - return(Func_lbl_48(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//--- check - if(state.m_rstate.stage==12) - { - //--- change value - state.m_xupdated=false; - //--- return result - return(false); - } -//--- check - if(state.m_rstate.stage==13) - { - //--- change value - state.m_xupdated=false; - //--- function call, return result - return(Func_lbl_55(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//--- check - if(state.m_rstate.stage==14) - { - //--- change value - state.m_xupdated=false; - //--- return result - return(false); - } -//--- check - if(state.m_rstate.stage==15) - { - //--- change value - state.m_xupdated=false; - //--- return result - return(false); - } -//--- Routine body -//--- prepare - n=state.m_n; - m=state.m_m; - state.m_repiterationscount=0; - state.m_repterminationtype=0; - state.m_repnfunc=0; - state.m_repnjac=0; - state.m_repngrad=0; - state.m_repnhess=0; - state.m_repncholesky=0; -//--- check consistency of constraints -//--- set constraints - for(i=0;i<=n-1;i++) - { - //--- check - if(state.m_havebndl[i] && state.m_havebndu[i]) - { - //--- check - if(state.m_bndl[i]>state.m_bndu[i]) - { - state.m_repterminationtype=-3; - //--- return result - return(false); - } - } - } -//--- function call - CMinQP::MinQPSetBC(state.m_qpstate,state.m_bndl,state.m_bndu); -//--- Initial report of current point -//--- Note 1: we rewrite State.X twice because -//--- user may accidentally change it after first call. -//--- Note 2: we set NeedF or NeedFI depending on what -//--- information about function we have. - if(!state.m_xrep) - return(Func_lbl_16(state,n,m,iflag,i,k,bflag,v,s,t)); - for(i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xbase[i_]; -//--- function call - ClearRequestFields(state); -//--- check - if(!state.m_hasf) - { - //--- check - if(!CAp::Assert(state.m_hasfi,"MinLM: internal error 2!")) - return(false); - //--- change values - state.m_needfi=true; - state.m_rstate.stage=1; - //--- Saving state - Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t); - //--- return result - return(true); - } -//--- change values - state.m_needf=true; - state.m_rstate.stage=0; -//--- Saving state - Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLMIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static void CMinLM::Func_lbl_rcomm(CMinLMState &state,int n,int m,int iflag, - int i,int k,bool bflag,double v, - double s,double t) - { -//--- save - state.m_rstate.ia[0]=n; - state.m_rstate.ia[1]=m; - state.m_rstate.ia[2]=iflag; - state.m_rstate.ia[3]=i; - state.m_rstate.ia[4]=k; - state.m_rstate.ba[0]=bflag; - state.m_rstate.ra[0]=v; - state.m_rstate.ra[1]=s; - state.m_rstate.ra[2]=t; - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLMIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinLM::Func_lbl_16(CMinLMState &state,int &n,int &m,int &iflag, - int &i,int &k,bool &bflag,double &v, - double &s,double &t) - { -//--- Prepare control variables - state.m_nu=1; - state.m_lambdav=-CMath::m_maxrealnumber; - state.m_modelage=state.m_maxmodelage+1; - state.m_deltaxready=false; - state.m_deltafready=false; -//--- Main cycle. -//--- We move through it until either: -//--- * one of the stopping conditions is met -//--- * we decide that stopping conditions are too stringent -//--- and break from cycle - return(Func_lbl_20(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLMIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinLM::Func_lbl_19(CMinLMState &state,int &n,int &m,int &iflag, - int &i,int &k,bool &bflag,double &v, - double &s,double &t) - { -//--- change value - state.m_repnfunc=state.m_repnfunc+1; -//--- copy - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xbase[i_]; -//--- function call - ClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_rstate.stage=2; -//--- Saving state - Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLMIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinLM::Func_lbl_20(CMinLMState &state,int &n,int &m,int &iflag, - int &i,int &k,bool &bflag,double &v, - double &s,double &t) - { -//--- First,we have to prepare quadratic model for our function. -//--- We use BFlag to ensure that model is prepared; -//--- if it is false at the end of this block,something went wrong. -//--- We may either calculate brand new model or update old one. -//--- Before this block we have: -//--- * State.XBase - current position. -//--- * State.DeltaX - if DeltaXReady is True -//--- * State.DeltaF - if DeltaFReady is True -//--- After this block is over,we will have: -//--- * State.XBase - base point (unchanged) -//--- * State.FBase - F(XBase) -//--- * State.GBase - linear term -//--- * State.QuadraticModel - quadratic term -//--- * State.LambdaV - current estimate for lambda -//--- We also clear DeltaXReady/DeltaFReady flags -//--- after initialization is done. - bflag=false; - if(!(state.m_algomode==0 || state.m_algomode==1)) - return(Func_lbl_22(state,n,m,iflag,i,k,bflag,v,s,t)); -//--- Calculate f[] and Jacobian - if(!(state.m_modelage>state.m_maxmodelage||!(state.m_deltaxready &state.m_deltafready))) - return(Func_lbl_24(state,n,m,iflag,i,k,bflag,v,s,t)); -//--- Refresh model (using either finite differences or analytic Jacobian) - if(state.m_algomode!=0) - { - //--- Obtain f[] and Jacobian - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xbase[i_]; - //--- function call - ClearRequestFields(state); - //--- change values - state.m_needfij=true; - state.m_rstate.stage=6; - //--- Saving state - Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t); - //--- return result - return(true); - } -//--- Optimization using F values only. -//--- Use finite differences to estimate Jacobian. - if(!CAp::Assert(state.m_hasfi,"MinLMIteration: internal error when estimating Jacobian (no f[])")) - return(false); - k=0; -//--- function call, return result - return(Func_lbl_28(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLMIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinLM::Func_lbl_21(CMinLMState &state,int &n,int &m,int &iflag, - int &i,int &k,bool &bflag,double &v, - double &s,double &t) - { -//--- Lambda is too large,we have to break iterations. - state.m_repterminationtype=7; - if(!state.m_xrep) - return(false); - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xbase[i_]; - state.m_f=state.m_fbase; -//--- function call - ClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_rstate.stage=15; -//--- Saving state - Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLMIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinLM::Func_lbl_22(CMinLMState &state,int &n,int &m,int &iflag, - int &i,int &k,bool &bflag,double &v, - double &s,double &t) - { -//--- check - if(state.m_algomode!=2) - return(Func_lbl_31(state,n,m,iflag,i,k,bflag,v,s,t)); -//--- check - if(!CAp::Assert(!state.m_hasfi,"MinLMIteration: internal error (HasFI is True in Hessian-based mode)")) - return(false); -//--- Obtain F,G,H - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xbase[i_]; -//--- function call - ClearRequestFields(state); -//--- change values - state.m_needfgh=true; - state.m_rstate.stage=7; -//--- Saving state - Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLMIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinLM::Func_lbl_24(CMinLMState &state,int &n,int &m,int &iflag, - int &i,int &k,bool &bflag,double &v, - double &s,double &t) - { -//--- State.J contains Jacobian or its current approximation; -//--- refresh it using secant updates: -//--- f(x0+dx)=f(x0) + J*dx, -//--- J_new=J_old + u*h' -//--- h=x_new-x_old -//--- u=(f_new - f_old - J_old*h)/(h'h) -//--- We can explicitly generate h and u,but it is -//--- preferential to do in-place calculations. Only -//--- I-th row of J_old is needed to calculate u[I], -//--- so we can update J row by row in one pass. -//--- NOTE: we expect that State.XBase contains new point, -//--- State.FBase contains old point,State.DeltaX and -//--- State.DeltaY contain updates from last step. - if(!CAp::Assert(state.m_deltaxready && state.m_deltafready,"MinLMIteration: uninitialized DeltaX/DeltaF")) - return(false); - t=0.0; - for(int i_=0;i_<=n-1;i_++) - t+=state.m_deltax[i_]*state.m_deltax[i_]; -//--- check - if(!CAp::Assert(t!=0.0,"MinLM: internal error (T=0)")) - return(false); - for(i=0;i<=m-1;i++) - { - //--- change value - v=0.0; - for(int i_=0;i_<=n-1;i_++) - v+=state.m_j[i][i_]*state.m_deltax[i_]; - v=(state.m_deltaf[i]-v)/t; - for(int i_=0;i_<=n-1;i_++) - state.m_j[i].Set(i_,state.m_j[i][i_]+v*state.m_deltax[i_]); - } - for(int i_=0;i_<=m-1;i_++) - state.m_fi[i_]=state.m_fibase[i_]; - for(int i_=0;i_<=m-1;i_++) - state.m_fi[i_]=state.m_fi[i_]+state.m_deltaf[i_]; -//--- Increase model age - state.m_modelage=state.m_modelage+1; -//--- function call, return result - return(Func_lbl_25(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLMIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinLM::Func_lbl_25(CMinLMState &state,int &n,int &m,int &iflag, - int &i,int &k,bool &bflag,double &v, - double &s,double &t) - { -//--- Generate quadratic model: -//--- f(xbase+dx)= -//--- =(f0 + J*dx)'(f0 + J*dx) -//--- =f0^2 + dx'J'f0 + f0*J*dx + dx'J'J*dx -//--- =f0^2 + 2*f0*J*dx + dx'J'J*dx -//--- Note that we calculate 2*(J'J) instead of J'J because -//--- our quadratic model is based on Tailor decomposition, -//--- i.m_e. it has 0.5 before quadratic term. - CAblas::RMatrixGemm(n,n,m,2.0,state.m_j,0,0,1,state.m_j,0,0,0,0.0,state.m_quadraticmodel,0,0); - CAblas::RMatrixMVect(n,m,state.m_j,0,0,1,state.m_fi,0,state.m_gbase,0); - for(int i_=0;i_<=n-1;i_++) - state.m_gbase[i_]=2*state.m_gbase[i_]; -//--- change value - v=0.0; - for(int i_=0;i_<=m-1;i_++) - v+=state.m_fi[i_]*state.m_fi[i_]; - state.m_fbase=v; -//--- copy - for(int i_=0;i_<=m-1;i_++) - state.m_fibase[i_]=state.m_fi[i_]; -//--- set control variables - bflag=true; -//--- function call, return result - return(Func_lbl_22(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLMIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinLM::Func_lbl_28(CMinLMState &state,int &n,int &m,int &iflag, - int &i,int &k,bool &bflag,double &v, - double &s,double &t) - { -//--- check - if(k>n-1) - { - //--- Calculate F(XBase) - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xbase[i_]; - //--- function call - ClearRequestFields(state); - //--- change values - state.m_needfi=true; - state.m_rstate.stage=5; - //--- Saving state - Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t); - //--- return result - return(true); - } -//--- We guard X[k] from leaving [BndL,BndU]. -//--- In case BndL=BndU,we assume that derivative in this direction is zero. - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xbase[i_]; - state.m_x[k]=state.m_x[k]-state.m_s[k]*state.m_diffstep; -//--- check - if(state.m_havebndl[k]) - state.m_x[k]=MathMax(state.m_x[k],state.m_bndl[k]); -//--- check - if(state.m_havebndu[k]) - state.m_x[k]=MathMin(state.m_x[k],state.m_bndu[k]); - state.m_xm1=state.m_x[k]; -//--- function call - ClearRequestFields(state); -//--- change values - state.m_needfi=true; - state.m_rstate.stage=3; -//--- Saving state - Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLMIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinLM::Func_lbl_31(CMinLMState &state,int &n,int &m,int &iflag, - int &i,int &k,bool &bflag,double &v, - double &s,double &t) - { -//--- check - if(!CAp::Assert(bflag,"MinLM: internal integrity check failed!")) - return(false); -//--- change values - state.m_deltaxready=false; - state.m_deltafready=false; -//--- If Lambda is not initialized,initialize it using quadratic model - if(state.m_lambdav<0.0) - { - state.m_lambdav=0; - for(i=0;i<=n-1;i++) - state.m_lambdav=MathMax(state.m_lambdav,MathAbs(state.m_quadraticmodel[i][i])*CMath::Sqr(state.m_s[i])); - state.m_lambdav=0.001*state.m_lambdav; - //--- check - if(state.m_lambdav==0.0) - state.m_lambdav=1; - } -//--- Test stopping conditions for function gradient - if(BoundedScaledAntigradNorm(state,state.m_xbase,state.m_gbase)>state.m_epsg) - { - //--- Find value of Levenberg-Marquardt damping parameter which: - //--- * leads to positive definite damped model - //--- * within bounds specified by StpMax - //--- * generates step which decreases function value - //--- After this block IFlag is set to: - //--- * -3,if constraints are infeasible - //--- * -2,if model update is needed (either Lambda growth is too large - //--- or step is too short,but we can't rely on model and stop iterations) - //--- * -1,if model is fresh,Lambda have grown too large,termination is needed - //--- * 0,if everything is OK,continue iterations - //--- State.Nu can have any value on enter,but after exit it is set to 1.0 - iflag=-99; - //--- function call, return result - return(Func_lbl_39(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//--- check - if(state.m_modelage!=0) - { - //--- Model is not fresh,we should refresh it and test - //--- conditions once more - state.m_modelage=state.m_maxmodelage+1; - //--- function call, return result - return(Func_lbl_20(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//--- Model is fresh,we can rely on it and terminate algorithm - state.m_repterminationtype=4; -//--- check - if(!state.m_xrep) - return(false); - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xbase[i_]; - state.m_f=state.m_fbase; -//--- function call - ClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_rstate.stage=8; -//--- Saving state - Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLMIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinLM::Func_lbl_39(CMinLMState &state,int &n,int &m,int &iflag, - int &i,int &k,bool &bflag,double &v, - double &s,double &t) - { -//--- Do we need model update? - if(state.m_modelage>0 && state.m_nu>=m_suspiciousnu) - { - iflag=-2; - //--- function call, return result - return(Func_lbl_40(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//--- Setup quadratic solver and solve quadratic programming problem. -//--- After problem is solved we'll try to bound step by StpMax -//--- (Lambda will be increased if step size is too large). -//--- We use BFlag variable to indicate that we have to increase Lambda. -//--- If it is False,we will try to increase Lambda and move to new iteration. - bflag=true; -//--- function call - CMinQP::MinQPSetStartingPointFast(state.m_qpstate,state.m_xbase); -//--- function call - CMinQP::MinQPSetOriginFast(state.m_qpstate,state.m_xbase); -//--- function call - CMinQP::MinQPSetLinearTermFast(state.m_qpstate,state.m_gbase); -//--- function call - CMinQP::MinQPSetQuadraticTermFast(state.m_qpstate,state.m_quadraticmodel,true,0.0); - for(i=0;i<=n-1;i++) - state.m_tmp0[i]=state.m_quadraticmodel[i][i]+state.m_lambdav/CMath::Sqr(state.m_s[i]); -//--- function call - CMinQP::MinQPRewriteDiagonal(state.m_qpstate,state.m_tmp0); -//--- function call - CMinQP::MinQPOptimize(state.m_qpstate); -//--- function call - CMinQP::MinQPResultsBuf(state.m_qpstate,state.m_xdir,state.m_qprep); -//--- check - if(state.m_qprep.m_terminationtype>0) - { - //--- successful solution of QP problem - for(int i_=0;i_<=n-1;i_++) - state.m_xdir[i_]=state.m_xdir[i_]-state.m_xbase[i_]; - v=0.0; - for(int i_=0;i_<=n-1;i_++) - v+=state.m_xdir[i_]*state.m_xdir[i_]; - //--- check - if(CMath::IsFinite(v)) - { - v=MathSqrt(v); - //--- check - if((state.m_stpmax>0.0)&&(v>state.m_stpmax)) - bflag=false; - } - else - bflag=false; - } - else - { - //--- Either problem is non-convex (increase LambdaV) or constraints are inconsistent - if(!CAp::Assert(state.m_qprep.m_terminationtype==-3 || state.m_qprep.m_terminationtype==-5,"MinLM: unexpected completion code from QP solver")) - return(false); - //--- check - if(state.m_qprep.m_terminationtype==-3) - { - iflag=-3; - //--- function call, return result - return(Func_lbl_40(state,n,m,iflag,i,k,bflag,v,s,t)); - } - bflag=false; - } -//--- check - if(!bflag) - { - //--- Solution failed: - //--- try to increase lambda to make matrix positive definite and continue. - if(!IncreaseLambda(state.m_lambdav,state.m_nu)) - { - iflag=-1; - //--- function call, return result - return(Func_lbl_40(state,n,m,iflag,i,k,bflag,v,s,t)); - } - //--- function call, return result - return(Func_lbl_39(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//--- Step in State.XDir and it is bounded by StpMax. -//--- We should check stopping conditions on step size here. -//--- DeltaX,which is used for secant updates,is initialized here. -//--- This code is a bit tricky because sometimes XDir<>0,but -//--- it is so small that XDir+XBase==XBase (in finite precision -//--- arithmetics). So we set DeltaX to XBase,then -//--- add XDir,and then subtract XBase to get exact value of -//--- DeltaX. -//--- Step length is estimated using DeltaX. -//--- NOTE: stopping conditions are tested -//--- for fresh models only (ModelAge=0) - for(int i_=0;i_<=n-1;i_++) - state.m_deltax[i_]=state.m_xbase[i_]; - for(int i_=0;i_<=n-1;i_++) - state.m_deltax[i_]=state.m_deltax[i_]+state.m_xdir[i_]; - for(int i_=0;i_<=n-1;i_++) - state.m_deltax[i_]=state.m_deltax[i_]-state.m_xbase[i_]; - state.m_deltaxready=true; -//--- change value - v=0.0; - for(i=0;i<=n-1;i++) - v=v+CMath::Sqr(state.m_deltax[i]/state.m_s[i]); - v=MathSqrt(v); -//--- check - if(v>state.m_epsx) - return(Func_lbl_41(state,n,m,iflag,i,k,bflag,v,s,t)); -//--- check - if(state.m_modelage!=0) - { - //--- Step is suspiciously short,but model is not fresh - //--- and we can't rely on it. - iflag=-2; - //--- function call, return result - return(Func_lbl_40(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//--- Step is too short,model is fresh and we can rely on it. -//--- Terminating. - state.m_repterminationtype=2; - if(!state.m_xrep) - return(false); -//--- copy - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xbase[i_]; - state.m_f=state.m_fbase; -//--- function call - ClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_rstate.stage=9; -//--- Saving state - Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLMIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinLM::Func_lbl_40(CMinLMState &state,int &n,int &m,int &iflag, - int &i,int &k,bool &bflag,double &v, - double &s,double &t) - { - state.m_nu=1; -//--- check - if(!CAp::Assert(iflag>=-3 && iflag<=0,"MinLM: internal integrity check failed!")) - return(false); -//--- check - if(iflag==-3) - { - state.m_repterminationtype=-3; - //--- return result - return(false); - } -//--- check - if(iflag==-2) - { - state.m_modelage=state.m_maxmodelage+1; - //--- function call, return result - return(Func_lbl_20(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//--- check - if(iflag==-1) - return(Func_lbl_21(state,n,m,iflag,i,k,bflag,v,s,t)); -//--- Levenberg-Marquardt step is ready. -//--- Compare predicted vs. actual decrease and decide what to do with lambda. -//--- NOTE: we expect that State.DeltaX contains direction of step, -//--- State.F contains function value at new point. - if(!CAp::Assert(state.m_deltaxready,"MinLM: deltaX is not ready")) - return(false); - t=0; - for(i=0;i<=n-1;i++) - { - //--- change values - v=0.0; - for(int i_=0;i_<=n-1;i_++) - v+=state.m_quadraticmodel[i][i_]*state.m_deltax[i_]; - t=t+state.m_deltax[i]*state.m_gbase[i]+0.5*state.m_deltax[i]*v; - } -//--- change values - state.m_predicteddecrease=-t; - state.m_actualdecrease=-(state.m_f-state.m_fbase); -//--- check - if(state.m_predicteddecrease<=0.0) - return(Func_lbl_21(state,n,m,iflag,i,k,bflag,v,s,t)); - v=state.m_actualdecrease/state.m_predicteddecrease; -//--- check - if(v>=0.1) - return(Func_lbl_49(state,n,m,iflag,i,k,bflag,v,s,t)); -//--- check - if(IncreaseLambda(state.m_lambdav,state.m_nu)) - return(Func_lbl_49(state,n,m,iflag,i,k,bflag,v,s,t)); -//--- Lambda is too large,we have to break iterations. - state.m_repterminationtype=7; -//--- check - if(!state.m_xrep) - return(false); - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xbase[i_]; - state.m_f=state.m_fbase; -//--- function call - ClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_rstate.stage=12; -//--- Saving state - Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLMIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinLM::Func_lbl_41(CMinLMState &state,int &n,int &m,int &iflag, - int &i,int &k,bool &bflag,double &v, - double &s,double &t) - { -//--- Let's evaluate new step: -//--- a) if we have Fi vector,we evaluate it using rcomm,and -//--- then we manually calculate State.F as sum of squares of Fi[] -//--- b) if we have F value,we just evaluate it through rcomm interface -//--- We prefer (a) because we may need Fi vector for additional -//--- iterations - if(!CAp::Assert(state.m_hasfi|state.m_hasf,"MinLM: internal error 2!")) - return(false); - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xbase[i_]; - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_x[i_]+state.m_xdir[i_]; -//--- function call - ClearRequestFields(state); -//--- check - if(!state.m_hasfi) - { - //--- change values - state.m_needf=true; - state.m_rstate.stage=11; - //--- Saving state - Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t); - //--- return result - return(true); - } -//--- change values - state.m_needfi=true; - state.m_rstate.stage=10; -//--- Saving state - Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLMIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinLM::Func_lbl_48(CMinLMState &state,int &n,int &m,int &iflag, - int &i,int &k,bool &bflag,double &v, - double &s,double &t) - { - state.m_repnfunc=state.m_repnfunc+1; -//--- check - if(state.m_f>=state.m_fbase) - { - //--- Increase lambda and continue - if(!IncreaseLambda(state.m_lambdav,state.m_nu)) - { - iflag=-1; - //--- function call, return result - return(Func_lbl_40(state,n,m,iflag,i,k,bflag,v,s,t)); - } - //--- function call, return result - return(Func_lbl_39(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//--- We've found our step! - iflag=0; -//--- function call, return result - return(Func_lbl_40(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLMIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinLM::Func_lbl_49(CMinLMState &state,int &n,int &m,int &iflag, - int &i,int &k,bool &bflag,double &v, - double &s,double &t) - { -//--- check - if(v>0.5) - DecreaseLambda(state.m_lambdav,state.m_nu); -//--- Accept step,report it and -//--- test stopping conditions on iterations count and function decrease. -//--- NOTE: we expect that State.DeltaX contains direction of step, -//--- State.F contains function value at new point. -//--- NOTE2: we should update XBase ONLY. In the beginning of the next -//--- iteration we expect that State.FIBase is NOT updated and -//--- contains old value of a function vector. - for(int i_=0;i_<=n-1;i_++) - state.m_xbase[i_]=state.m_xbase[i_]+state.m_deltax[i_]; -//--- check - if(!state.m_xrep) - return(Func_lbl_55(state,n,m,iflag,i,k,bflag,v,s,t)); - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xbase[i_]; -//--- function call - ClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_rstate.stage=13; -//--- Saving state - Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinLMIteration. Is a product to get rid of| -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinLM::Func_lbl_55(CMinLMState &state,int &n,int &m,int &iflag, - int &i,int &k,bool &bflag,double &v, - double &s,double &t) - { - state.m_repiterationscount=state.m_repiterationscount+1; -//--- check - if(state.m_repiterationscount>=state.m_maxits&&state.m_maxits>0) - state.m_repterminationtype=5; -//--- check - if(state.m_modelage==0) - { - //--- check - if(MathAbs(state.m_f-state.m_fbase)<=state.m_epsf*MathMax(1,MathMax(MathAbs(state.m_f),MathAbs(state.m_fbase)))) - state.m_repterminationtype=1; - } -//--- check - if(state.m_repterminationtype<=0) - { - state.m_modelage=state.m_modelage+1; - //--- function call, return result - return(Func_lbl_20(state,n,m,iflag,i,k,bflag,v,s,t)); - } -//--- check - if(!state.m_xrep) - return(false); -//--- Report: XBase contains new point,F contains function value at new point - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xbase[i_]; -//--- function call - ClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_rstate.stage=14; -//--- Saving state - Func_lbl_rcomm(state,n,m,iflag,i,k,bflag,v,s,t); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary class for CMinComp | -//+------------------------------------------------------------------+ -class CMinASAState - { -public: - //--- variables - int m_n; - double m_epsg; - double m_epsf; - double m_epsx; - int m_maxits; - bool m_xrep; - double m_stpmax; - int m_cgtype; - int m_k; - int m_nfev; - int m_mcstage; - int m_curalgo; - int m_acount; - double m_mu; - double m_finit; - double m_dginit; - double m_fold; - double m_stp; - double m_laststep; - double m_f; - bool m_needfg; - bool m_xupdated; - RCommState m_rstate; - int m_repiterationscount; - int m_repnfev; - int m_repterminationtype; - int m_debugrestartscount; - CLinMinState m_lstate; - double m_betahs; - double m_betady; - //--- arrays - double m_bndl[]; - double m_bndu[]; - double m_ak[]; - double m_xk[]; - double m_dk[]; - double m_an[]; - double m_xn[]; - double m_dn[]; - double m_d[]; - double m_work[]; - double m_yk[]; - double m_gc[]; - double m_x[]; - double m_g[]; - //--- constructor, destructor - CMinASAState(void); - ~CMinASAState(void); - //--- copy - void Copy(CMinASAState &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinASAState::CMinASAState(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinASAState::~CMinASAState(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CMinASAState::Copy(CMinASAState &obj) - { -//--- copy variables - m_n=obj.m_n; - m_epsg=obj.m_epsg; - m_epsf=obj.m_epsf; - m_epsx=obj.m_epsx; - m_maxits=obj.m_maxits; - m_xrep=obj.m_xrep; - m_stpmax=obj.m_stpmax; - m_cgtype=obj.m_cgtype; - m_k=obj.m_k; - m_nfev=obj.m_nfev; - m_mcstage=obj.m_mcstage; - m_curalgo=obj.m_curalgo; - m_acount=obj.m_acount; - m_mu=obj.m_mu; - m_finit=obj.m_finit; - m_dginit=obj.m_dginit; - m_fold=obj.m_fold; - m_stp=obj.m_stp; - m_laststep=obj.m_laststep; - m_f=obj.m_f; - m_needfg=obj.m_needfg; - m_xupdated=obj.m_xupdated; - m_repiterationscount=obj.m_repiterationscount; - m_repnfev=obj.m_repnfev; - m_repterminationtype=obj.m_repterminationtype; - m_debugrestartscount=obj.m_debugrestartscount; - m_betahs=obj.m_betahs; - m_betady=obj.m_betady; - m_rstate.Copy(obj.m_rstate); - m_lstate.Copy(obj.m_lstate); -//--- copy arrays - ArrayCopy(m_bndl,obj.m_bndl); - ArrayCopy(m_bndu,obj.m_bndu); - ArrayCopy(m_ak,obj.m_ak); - ArrayCopy(m_xk,obj.m_xk); - ArrayCopy(m_dk,obj.m_dk); - ArrayCopy(m_an,obj.m_an); - ArrayCopy(m_xn,obj.m_xn); - ArrayCopy(m_dn,obj.m_dn); - ArrayCopy(m_d,obj.m_d); - ArrayCopy(m_work,obj.m_work); - ArrayCopy(m_yk,obj.m_yk); - ArrayCopy(m_gc,obj.m_gc); - ArrayCopy(m_x,obj.m_x); - ArrayCopy(m_g,obj.m_g); - } -//+------------------------------------------------------------------+ -//| This class is a shell for class CMinASAState | -//+------------------------------------------------------------------+ -class CMinASAStateShell - { -private: - CMinASAState m_innerobj; -public: - //--- constructors, destructor - CMinASAStateShell(void); - CMinASAStateShell(CMinASAState &obj); - ~CMinASAStateShell(void); - //--- methods - bool GetNeedFG(void); - void SetNeedFG(const bool b); - bool GetXUpdated(void); - void SetXUpdated(const bool b); - double GetF(void); - void SetF(const double d); - CMinASAState *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinASAStateShell::CMinASAStateShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CMinASAStateShell::CMinASAStateShell(CMinASAState &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinASAStateShell::~CMinASAStateShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable needfg | -//+------------------------------------------------------------------+ -bool CMinASAStateShell::GetNeedFG(void) - { -//--- return result - return(m_innerobj.m_needfg); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable needfg | -//+------------------------------------------------------------------+ -void CMinASAStateShell::SetNeedFG(const bool b) - { -//--- change value - m_innerobj.m_needfg=b; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable xupdated | -//+------------------------------------------------------------------+ -bool CMinASAStateShell::GetXUpdated(void) - { -//--- return result - return(m_innerobj.m_xupdated); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable xupdated | -//+------------------------------------------------------------------+ -void CMinASAStateShell::SetXUpdated(const bool b) - { -//--- change value - m_innerobj.m_xupdated=b; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable f | -//+------------------------------------------------------------------+ -double CMinASAStateShell::GetF(void) - { -//--- return result - return(m_innerobj.m_f); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable f | -//+------------------------------------------------------------------+ -void CMinASAStateShell::SetF(const double d) - { -//--- change value - m_innerobj.m_f=d; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CMinASAState *CMinASAStateShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Auxiliary class for CMinComp | -//+------------------------------------------------------------------+ -class CMinASAReport - { -public: - //--- variables - int m_iterationscount; - int m_nfev; - int m_terminationtype; - int m_activeconstraints; - //--- constructor, destructor - CMinASAReport(void); - ~CMinASAReport(void); - //--- copy - void Copy(CMinASAReport &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinASAReport::CMinASAReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinASAReport::~CMinASAReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CMinASAReport::Copy(CMinASAReport &obj) - { -//--- copy variables - m_iterationscount=obj.m_iterationscount; - m_nfev=obj.m_nfev; - m_terminationtype=obj.m_terminationtype; - m_activeconstraints=obj.m_activeconstraints; - } -//+------------------------------------------------------------------+ -//| This class is a shell for class CMinASAReport | -//+------------------------------------------------------------------+ -class CMinASAReportShell - { -private: - CMinASAReport m_innerobj; -public: - //--- constructors, destructor - CMinASAReportShell(void); - CMinASAReportShell(CMinASAReport &obj); - ~CMinASAReportShell(void); - //--- methods - int GetIterationsCount(void); - void SetIterationsCount(const int i); - int GetNFev(void); - void SetNFev(const int i); - int GetTerminationType(void); - void SetTerminationType(const int i); - int GetActiveConstraints(void); - void SetActiveConstraints(const int i); - CMinASAReport *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinASAReportShell::CMinASAReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CMinASAReportShell::CMinASAReportShell(CMinASAReport &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinASAReportShell::~CMinASAReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable iterationscount | -//+------------------------------------------------------------------+ -int CMinASAReportShell::GetIterationsCount(void) - { -//--- return result - return(m_innerobj.m_iterationscount); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable iterationscount | -//+------------------------------------------------------------------+ -void CMinASAReportShell::SetIterationsCount(const int i) - { -//--- change value - m_innerobj.m_iterationscount=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable nfev | -//+------------------------------------------------------------------+ -int CMinASAReportShell::GetNFev(void) - { -//--- return result - return(m_innerobj.m_nfev); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable nfev | -//+------------------------------------------------------------------+ -void CMinASAReportShell::SetNFev(const int i) - { -//--- change value - m_innerobj.m_nfev=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable terminationtype | -//+------------------------------------------------------------------+ -int CMinASAReportShell::GetTerminationType(void) - { -//--- return result - return(m_innerobj.m_terminationtype); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable terminationtype | -//+------------------------------------------------------------------+ -void CMinASAReportShell::SetTerminationType(const int i) - { -//--- change value - m_innerobj.m_terminationtype=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable activeconstraints | -//+------------------------------------------------------------------+ -int CMinASAReportShell::GetActiveConstraints(void) - { -//--- return result - return(m_innerobj.m_activeconstraints); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable activeconstraints | -//+------------------------------------------------------------------+ -void CMinASAReportShell::SetActiveConstraints(const int i) - { -//--- change value - m_innerobj.m_activeconstraints=i; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CMinASAReport *CMinASAReportShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Backward compatibility functions | -//+------------------------------------------------------------------+ -class CMinComp - { -private: - //--- private methods - static double ASABoundedAntigradNorm(CMinASAState &state); - static double ASAGINorm(CMinASAState &state); - static double ASAD1Norm(CMinASAState &state); - static bool ASAUIsEmpty(CMinASAState &state); - static void ClearRequestFields(CMinASAState &state); - //--- auxiliary functions for MinASAIteration - static void Func_lbl_rcomm(CMinASAState &state,int n,int i,int mcinfo,int diffcnt,bool b,bool stepfound,double betak,double v,double vv); - static bool Func_lbl_15(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv); - static bool Func_lbl_17(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv); - static bool Func_lbl_19(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv); - static bool Func_lbl_21(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv); - static bool Func_lbl_24(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv); - static bool Func_lbl_26(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv); - static bool Func_lbl_27(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv); - static bool Func_lbl_29(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv); - static bool Func_lbl_31(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv); - static bool Func_lbl_35(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv); - static bool Func_lbl_39(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv); - static bool Func_lbl_43(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv); - static bool Func_lbl_49(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv); - static bool Func_lbl_51(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv); - static bool Func_lbl_52(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv); - static bool Func_lbl_53(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv); - static bool Func_lbl_55(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv); - static bool Func_lbl_59(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv); - static bool Func_lbl_63(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv); - static bool Func_lbl_65(CMinASAState &state,int &n,int &i,int &mcinfo,int &diffcnt,bool &b,bool &stepfound,double &betak,double &v,double &vv); -public: - //--- class constants - static const int m_n1; - static const int m_n2; - static const double m_stpmin; - static const double m_gtol; - static const double m_gpaftol; - static const double m_gpadecay; - static const double m_asarho; - //--- constructor, destructor - CMinComp(void); - ~CMinComp(void); - //--- public methods - static void MinLBFGSSetDefaultPreconditioner(CMinLBFGSState &state); - static void MinLBFGSSetCholeskyPreconditioner(CMinLBFGSState &state,CMatrixDouble &p,const bool isupper); - static void MinBLEICSetBarrierWidth(CMinBLEICState &state,const double mu); - static void MinBLEICSetBarrierDecay(CMinBLEICState &state,const double mudecay); - static void MinASACreate(const int n,double &x[],double &bndl[],double &bndu[],CMinASAState &state); - static void MinASASetCond(CMinASAState &state,const double epsg,const double epsf,double epsx,const int maxits); - static void MinASASetXRep(CMinASAState &state,const bool needxrep); - static void MinASASetAlgorithm(CMinASAState &state,int algotype); - static void MinASASetStpMax(CMinASAState &state,const double stpmax); - static void MinASAResults(CMinASAState &state,double &x[],CMinASAReport &rep); - static void MinASAResultsBuf(CMinASAState &state,double &x[],CMinASAReport &rep); - static void MinASARestartFrom(CMinASAState &state,double &x[],double &bndl[],double &bndu[]); - static bool MinASAIteration(CMinASAState &state); - }; -//+------------------------------------------------------------------+ -//| Initialize constants | -//+------------------------------------------------------------------+ -const int CMinComp::m_n1=2; -const int CMinComp::m_n2=2; -const double CMinComp::m_stpmin=1.0E-300; -const double CMinComp::m_gtol=0.3; -const double CMinComp::m_gpaftol=0.0001; -const double CMinComp::m_gpadecay=0.5; -const double CMinComp::m_asarho=0.5; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMinComp::CMinComp(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMinComp::~CMinComp(void) - { - - } -//+------------------------------------------------------------------+ -//| Obsolete function, use MinLBFGSSetPrecDefault() instead. | -//+------------------------------------------------------------------+ -static void CMinComp::MinLBFGSSetDefaultPreconditioner(CMinLBFGSState &state) - { -//--- function call - CMinLBFGS::MinLBFGSSetPrecDefault(state); - } -//+------------------------------------------------------------------+ -//| Obsolete function, use MinLBFGSSetCholeskyPreconditioner() | -//| instead. | -//+------------------------------------------------------------------+ -static void CMinComp::MinLBFGSSetCholeskyPreconditioner(CMinLBFGSState &state, - CMatrixDouble &p, - const bool isupper) - { -//--- function call - CMinLBFGS::MinLBFGSSetPrecCholesky(state,p,isupper); - } -//+------------------------------------------------------------------+ -//| This is obsolete function which was used by previous version of | -//| the BLEIC optimizer. It does nothing in the current version of | -//| BLEIC. | -//+------------------------------------------------------------------+ -static void CMinComp::MinBLEICSetBarrierWidth(CMinBLEICState &state, - const double mu) - { - - } -//+------------------------------------------------------------------+ -//| This is obsolete function which was used by previous version of | -//| the BLEIC optimizer. It does nothing in the current version of | -//| BLEIC. | -//+------------------------------------------------------------------+ -static void CMinComp::MinBLEICSetBarrierDecay(CMinBLEICState &state, - const double mudecay) - { - - } -//+------------------------------------------------------------------+ -//| Obsolete optimization algorithm. | -//| Was replaced by MinBLEIC subpackage. | -//+------------------------------------------------------------------+ -static void CMinComp::MinASACreate(const int n,double &x[],double &bndl[], - double &bndu[],CMinASAState &state) - { -//--- create a variable - int i=0; -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N too small!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=n,__FUNCTION__+": Length(BndL)=n,__FUNCTION__+": Length(BndU)=0.0,__FUNCTION__+": negative EpsG!")) - return; -//--- check - if(!CAp::Assert(CMath::IsFinite(epsf),__FUNCTION__+": EpsF is not finite number!")) - return; -//--- check - if(!CAp::Assert(epsf>=0.0,__FUNCTION__+": negative EpsF!")) - return; -//--- check - if(!CAp::Assert(CMath::IsFinite(epsx),__FUNCTION__+": EpsX is not finite number!")) - return; -//--- check - if(!CAp::Assert(epsx>=0.0,__FUNCTION__+": negative EpsX!")) - return; -//--- check - if(!CAp::Assert(maxits>=0,__FUNCTION__+": negative MaxIts!")) - return; -//--- check - if(((epsg==0.0 && epsf==0.0) && epsx==0.0) && maxits==0) - epsx=1.0E-6; -//--- change values - state.m_epsg=epsg; - state.m_epsf=epsf; - state.m_epsx=epsx; - state.m_maxits=maxits; - } -//+------------------------------------------------------------------+ -//| Obsolete optimization algorithm. | -//| Was replaced by MinBLEIC subpackage. | -//+------------------------------------------------------------------+ -static void CMinComp::MinASASetXRep(CMinASAState &state,const bool needxrep) - { -//--- change value - state.m_xrep=needxrep; - } -//+------------------------------------------------------------------+ -//| Obsolete optimization algorithm. | -//| Was replaced by MinBLEIC subpackage. | -//+------------------------------------------------------------------+ -static void CMinComp::MinASASetAlgorithm(CMinASAState &state,int algotype) - { -//--- check - if(!CAp::Assert(algotype>=-1 && algotype<=1,__FUNCTION__+": incorrect AlgoType!")) - return; -//--- check - if(algotype==-1) - algotype=1; -//--- change value - state.m_cgtype=algotype; - } -//+------------------------------------------------------------------+ -//| Obsolete optimization algorithm. | -//| Was replaced by MinBLEIC subpackage. | -//+------------------------------------------------------------------+ -static void CMinComp::MinASASetStpMax(CMinASAState &state,const double stpmax) - { -//--- check - if(!CAp::Assert(CMath::IsFinite(stpmax),__FUNCTION__+": StpMax is not finite!")) - return; -//--- check - if(!CAp::Assert(stpmax>=0.0,__FUNCTION__+": StpMax<0!")) - return; -//--- change value - state.m_stpmax=stpmax; - } -//+------------------------------------------------------------------+ -//| Obsolete optimization algorithm. | -//| Was replaced by MinBLEIC subpackage. | -//+------------------------------------------------------------------+ -static void CMinComp::MinASAResults(CMinASAState &state,double &x[],CMinASAReport &rep) - { -//--- reset memory - ArrayResizeAL(x,0); -//--- function call - MinASAResultsBuf(state,x,rep); - } -//+------------------------------------------------------------------+ -//| Obsolete optimization algorithm. | -//| Was replaced by MinBLEIC subpackage. | -//+------------------------------------------------------------------+ -static void CMinComp::MinASAResultsBuf(CMinASAState &state,double &x[], - CMinASAReport &rep) - { -//--- create variables - int i=0; - int i_=0; -//--- check - if(CAp::Len(x)=state.m_n,__FUNCTION__+": Length(X)=state.m_n,__FUNCTION__+": Length(BndL)=state.m_n,__FUNCTION__+": Length(BndU)0)and(x[i]=bndu[i])) | -//| v[i]=-g[i] otherwise | -//| This function may be used to check a stopping criterion. | -//+------------------------------------------------------------------+ -static double CMinComp::ASABoundedAntigradNorm(CMinASAState &state) - { -//--- create variables - double result=0; - int i=0; - double v=0; -//--- initialization - result=0; - for(i=0;i<=state.m_n-1;i++) - { - v=-state.m_g[i]; - //--- check - if(state.m_x[i]==state.m_bndl[i] && -state.m_g[i]<0.0) - v=0; - //--- check - if(state.m_x[i]==state.m_bndu[i] && -state.m_g[i]>0.0) - v=0; - result=result+CMath::Sqr(v); - } -//--- return result - return(MathSqrt(result)); - } -//+------------------------------------------------------------------+ -//| Returns norm of GI(x). | -//| GI(x) is a gradient vector whose components associated with | -//| active constraints are zeroed. It differs from bounded | -//| anti-gradient because components of GI(x) are zeroed | -//| independently of sign(g[i]), and anti-gradient's components are | -//| zeroed with respect to both constraint and sign. | -//+------------------------------------------------------------------+ -static double CMinComp::ASAGINorm(CMinASAState &state) - { -//--- create variables - double result=0; - int i=0; -//--- initialization - result=0; - for(i=0;i<=state.m_n-1;i++) - { - //--- check - if(state.m_x[i]!=state.m_bndl[i] && state.m_x[i]!=state.m_bndu[i]) - result=result+CMath::Sqr(state.m_g[i]); - } -//--- return result - return(MathSqrt(result)); - } -//+------------------------------------------------------------------+ -//| Returns norm(D1(State.X)) | -//| For a meaning of D1 see 'NEW ACTIVE SET ALGORITHM FOR BOX | -//| CONSTRAINED OPTIMIZATION' by WILLIAM W. HAGER AND HONGCHAO ZHANG.| -//+------------------------------------------------------------------+ -static double CMinComp::ASAD1Norm(CMinASAState &state) - { -//--- create variables - double result=0; - int i=0; -//--- initialization - result=0; - for(i=0;i<=state.m_n-1;i++) - result=result+CMath::Sqr(CApServ::BoundVal(state.m_x[i]-state.m_g[i],state.m_bndl[i],state.m_bndu[i])-state.m_x[i]); -//--- return result - return(MathSqrt(result)); - } -//+------------------------------------------------------------------+ -//| Returns True, if U set is empty. | -//| * State.X is used as point, | -//| * State.G - as gradient, | -//| * D is calculated within function (because State.D may have | -//| different meaning depending on current optimization algorithm) | -//| For a meaning of U see 'NEW ACTIVE SET ALGORITHM FOR BOX | -//| CONSTRAINED OPTIMIZATION' by WILLIAM W. HAGER AND HONGCHAO ZHANG.| -//+------------------------------------------------------------------+ -static bool CMinComp::ASAUIsEmpty(CMinASAState &state) - { -//--- create variables - int i=0; - double d=0; - double d2=0; - double d32=0; -//--- initialization - d=ASAD1Norm(state); - d2=MathSqrt(d); - d32=d*d2; - for(i=0;i<=state.m_n-1;i++) - { - //--- check - if(MathAbs(state.m_g[i])>=d2 && MathMin(state.m_x[i]-state.m_bndl[i],state.m_bndu[i]-state.m_x[i])>=d32) - return(false); - } -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Clears request fileds (to be sure that we don't forgot to clear | -//| something) | -//+------------------------------------------------------------------+ -static void CMinComp::ClearRequestFields(CMinASAState &state) - { -//--- change values - state.m_needfg=false; - state.m_xupdated=false; - } -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -static bool CMinComp::MinASAIteration(CMinASAState &state) - { -//--- create variables - int n=0; - int i=0; - double betak=0; - double v=0; - double vv=0; - int mcinfo=0; - bool b; - bool stepfound; - int diffcnt=0; - int i_=0; -//--- This code initializes locals by: -//--- * random values determined during code -//--- generation - on first subroutine call -//--- * values from previous call - on subsequent calls - if(state.m_rstate.stage>=0) - { - //--- initialization - n=state.m_rstate.ia[0]; - i=state.m_rstate.ia[1]; - mcinfo=state.m_rstate.ia[2]; - diffcnt=state.m_rstate.ia[3]; - b=state.m_rstate.ba[0]; - stepfound=state.m_rstate.ba[1]; - betak=state.m_rstate.ra[0]; - v=state.m_rstate.ra[1]; - vv=state.m_rstate.ra[2]; - } - else - { - //--- initialization - n=-983; - i=-989; - mcinfo=-834; - diffcnt=900; - b=true; - stepfound=false; - betak=214; - v=-338; - vv=-686; - } -//--- check - if(state.m_rstate.stage==0) - { - //--- change value - state.m_needfg=false; - //--- check - if(!state.m_xrep) - return(Func_lbl_15(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - //--- progress report - ClearRequestFields(state); - state.m_xupdated=true; - state.m_rstate.stage=1; - //--- Saving state - Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv); - //--- return result - return(true); - } -//--- check - if(state.m_rstate.stage==1) - { - //--- change value - state.m_xupdated=false; - //--- function call, return result - return(Func_lbl_15(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - } -//--- check - if(state.m_rstate.stage==2) - { - //--- change values - state.m_needfg=false; - state.m_repnfev=state.m_repnfev+1; - stepfound=state.m_f<=state.m_finit+m_gpaftol*state.m_dginit; - //--- function call, return result - return(Func_lbl_24(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - } -//--- check - if(state.m_rstate.stage==3) - { - //--- change values - state.m_needfg=false; - state.m_repnfev=state.m_repnfev+1; - //--- check - if(state.m_stp<=m_stpmin) - { - for(i_=0;i_<=n-1;i_++) - state.m_xn[i_]=state.m_x[i_]; - //--- function call, return result - return(Func_lbl_26(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - } - //--- check - if(state.m_f<=state.m_finit+state.m_stp*m_gpaftol*state.m_dginit) - { - //--- copy - for(i_=0;i_<=n-1;i_++) - state.m_xn[i_]=state.m_x[i_]; - //--- function call, return result - return(Func_lbl_26(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - } - //--- change value - state.m_stp=state.m_stp*m_gpadecay; - //--- function call, return result - return(Func_lbl_27(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - } -//--- check - if(state.m_rstate.stage==4) - { - //--- change value - state.m_xupdated=false; - //--- function call, return result - return(Func_lbl_29(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - } -//--- check - if(state.m_rstate.stage==5) - { - //--- change value - state.m_xupdated=false; - //--- return result - return(false); - } -//--- check - if(state.m_rstate.stage==6) - { - //--- change value - state.m_xupdated=false; - //--- return result - return(false); - } -//--- check - if(state.m_rstate.stage==7) - { - //--- change value - state.m_xupdated=false; - //--- return result - return(false); - } -//--- check - if(state.m_rstate.stage==8) - { - //--- change value - state.m_xupdated=false; - //--- return result - return(false); - } -//--- check - if(state.m_rstate.stage==9) - { - //--- change value - state.m_needfg=false; - //--- postprocess data: zero components of G corresponding to - //--- the active constraints - for(i=0;i<=n-1;i++) - { - //--- check - if(state.m_x[i]==state.m_bndl[i] || state.m_x[i]==state.m_bndu[i]) - state.m_gc[i]=0; - else - state.m_gc[i]=state.m_g[i]; - } - CLinMin::MCSrch(n,state.m_xn,state.m_f,state.m_gc,state.m_d,state.m_stp,state.m_stpmax,m_gtol,mcinfo,state.m_nfev,state.m_work,state.m_lstate,state.m_mcstage); - //--- function call, return result - return(Func_lbl_51(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - } -//--- check - if(state.m_rstate.stage==10) - { - //--- change value - state.m_xupdated=false; - //--- function call, return result - return(Func_lbl_53(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - } -//--- check - if(state.m_rstate.stage==11) - { - //--- change value - state.m_xupdated=false; - //--- return result - return(false); - } -//--- check - if(state.m_rstate.stage==12) - { - //--- change value - state.m_xupdated=false; - //--- return result - return(false); - } -//--- check - if(state.m_rstate.stage==13) - { - //--- change value - state.m_xupdated=false; - //--- return result - return(false); - } -//--- check - if(state.m_rstate.stage==14) - { - //--- change value - state.m_xupdated=false; - //--- return result - return(false); - } -//--- Routine body -//--- Prepare - n=state.m_n; - state.m_repterminationtype=0; - state.m_repiterationscount=0; - state.m_repnfev=0; - state.m_debugrestartscount=0; - state.m_cgtype=1; -//--- copy - for(i_=0;i_<=n-1;i_++) - state.m_xk[i_]=state.m_x[i_]; - for(i=0;i<=n-1;i++) - { - //--- check - if(state.m_xk[i]==state.m_bndl[i] || state.m_xk[i]==state.m_bndu[i]) - state.m_ak[i]=0; - else - state.m_ak[i]=1; - } -//--- change values - state.m_mu=0.1; - state.m_curalgo=0; -//--- Calculate F/G,initialize algorithm - ClearRequestFields(state); -//--- change values - state.m_needfg=true; - state.m_rstate.stage=0; -//--- Saving state - Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinASAIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static void CMinComp::Func_lbl_rcomm(CMinASAState &state,int n,int i, - int mcinfo,int diffcnt,bool b, - bool stepfound,double betak, - double v,double vv) - { -//--- save - state.m_rstate.ia[0]=n; - state.m_rstate.ia[1]=i; - state.m_rstate.ia[2]=mcinfo; - state.m_rstate.ia[3]=diffcnt; - state.m_rstate.ba[0]=b; - state.m_rstate.ba[1]=stepfound; - state.m_rstate.ra[0]=betak; - state.m_rstate.ra[1]=v; - state.m_rstate.ra[2]=vv; - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinASAIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinComp::Func_lbl_15(CMinASAState &state,int &n,int &i, - int &mcinfo,int &diffcnt,bool &b, - bool &stepfound,double &betak, - double &v,double &vv) - { -//--- check - if(ASABoundedAntigradNorm(state)<=state.m_epsg) - { - state.m_repterminationtype=4; - //--- return result - return(false); - } - state.m_repnfev=state.m_repnfev+1; -//--- Main cycle -//--- At the beginning of new iteration: -//--- * CurAlgo stores current algorithm selector -//--- * State.XK,State.F and State.G store current X/F/G -//--- * State.AK stores current set of active constraints - return(Func_lbl_17(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinASAIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinComp::Func_lbl_17(CMinASAState &state,int &n,int &i, - int &mcinfo,int &diffcnt,bool &b, - bool &stepfound,double &betak, - double &v,double &vv) - { -//--- GPA algorithm - if(state.m_curalgo!=0) - return(Func_lbl_19(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); -//--- change values - state.m_k=0; - state.m_acount=0; -//--- function call, return result - return(Func_lbl_21(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinASAIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinComp::Func_lbl_19(CMinASAState &state,int &n,int &i, - int &mcinfo,int &diffcnt,bool &b, - bool &stepfound,double &betak, - double &v,double &vv) - { -//--- CG algorithm - if(state.m_curalgo!=1) - return(Func_lbl_17(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); -//--- first,check that there are non-active constraints. -//--- move to GPA algorithm,if all constraints are active - b=true; - for(i=0;i<=n-1;i++) - { - //--- check - if(state.m_ak[i]!=0.0) - { - b=false; - break; - } - } -//--- check - if(b) - { - state.m_curalgo=0; - //--- function call, return result - return(Func_lbl_17(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - } -//--- CG iterations - state.m_fold=state.m_f; - for(int i_=0;i_<=n-1;i_++) - state.m_xk[i_]=state.m_x[i_]; - for(i=0;i<=n-1;i++) - { - //--- change values - state.m_dk[i]=-(state.m_g[i]*state.m_ak[i]); - state.m_gc[i]=state.m_g[i]*state.m_ak[i]; - } -//--- function call, return result - return(Func_lbl_49(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinASAIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinComp::Func_lbl_21(CMinASAState &state,int &n,int &i, - int &mcinfo,int &diffcnt,bool &b, - bool &stepfound,double &betak, - double &v,double &vv) - { -//--- Determine Dk=proj(xk - gk)-xk - for(i=0;i<=n-1;i++) - state.m_d[i]=CApServ::BoundVal(state.m_xk[i]-state.m_g[i],state.m_bndl[i],state.m_bndu[i])-state.m_xk[i]; -//--- Armijo line search. -//--- * exact search with alpha=1 is tried first, -//--- 'exact' means that we evaluate f() EXACTLY at -//--- bound(x-g,bndl,bndu),without intermediate floating -//--- point operations. -//--- * alpha<1 are tried if explicit search wasn't successful -//--- Result is placed into XN. -//--- Two types of search are needed because we can't -//--- just use second type with alpha=1 because in finite -//--- precision arithmetics (x1-x0)+x0 may differ from x1. -//--- So while x1 is correctly bounded (it lie EXACTLY on -//--- boundary,if it is active),(x1-x0)+x0 may be -//--- not bounded. - v=0.0; - for(int i_=0;i_<=n-1;i_++) - v+=state.m_d[i_]*state.m_g[i_]; -//--- change values - state.m_dginit=v; - state.m_finit=state.m_f; -//--- check - if(!(ASAD1Norm(state)<=state.m_stpmax || state.m_stpmax==0.0)) - { - stepfound=false; - //--- function call, return result - return(Func_lbl_24(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - } -//--- Try alpha=1 step first - for(i=0;i<=n-1;i++) - state.m_x[i]=CApServ::BoundVal(state.m_xk[i]-state.m_g[i],state.m_bndl[i],state.m_bndu[i]); -//--- function call - ClearRequestFields(state); -//--- change values - state.m_needfg=true; - state.m_rstate.stage=2; -//--- Saving state - Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinASAIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinComp::Func_lbl_24(CMinASAState &state,int &n,int &i, - int &mcinfo,int &diffcnt,bool &b, - bool &stepfound,double &betak, - double &v,double &vv) - { -//--- check - if(!stepfound) - { - //--- alpha=1 is too large,try smaller values - state.m_stp=1; - //--- function call - CLinMin::LinMinNormalized(state.m_d,state.m_stp,n); - //--- change values - state.m_dginit=state.m_dginit/state.m_stp; - state.m_stp=m_gpadecay*state.m_stp; - //--- check - if(state.m_stpmax>0.0) - state.m_stp=MathMin(state.m_stp,state.m_stpmax); - //--- function call, return result - return(Func_lbl_27(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - } -//--- we are at the boundary(ies) - for(int i_=0;i_<=n-1;i_++) - state.m_xn[i_]=state.m_x[i_]; - state.m_stp=1; -//--- function call, return result - return(Func_lbl_26(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinASAIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinComp::Func_lbl_26(CMinASAState &state,int &n,int &i, - int &mcinfo,int &diffcnt,bool &b, - bool &stepfound,double &betak, - double &v,double &vv) - { - state.m_repiterationscount=state.m_repiterationscount+1; -//--- check - if(!state.m_xrep) - return(Func_lbl_29(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); -//--- progress report - ClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_rstate.stage=4; -//--- Saving state - Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinASAIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinComp::Func_lbl_27(CMinASAState &state,int &n,int &i, - int &mcinfo,int &diffcnt,bool &b, - bool &stepfound,double &betak, - double &v,double &vv) - { - v=state.m_stp; -//--- copy - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xk[i_]; - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_x[i_]+v*state.m_d[i_]; - ClearRequestFields(state); -//--- change values - state.m_needfg=true; - state.m_rstate.stage=3; -//--- Saving state - Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinASAIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinComp::Func_lbl_29(CMinASAState &state,int &n,int &i, - int &mcinfo,int &diffcnt,bool &b, - bool &stepfound,double &betak, - double &v,double &vv) - { -//--- Calculate new set of active constraints. -//--- Reset counter if active set was changed. -//--- Prepare for the new iteration - for(i=0;i<=n-1;i++) - { - //--- check - if(state.m_xn[i]==state.m_bndl[i] || state.m_xn[i]==state.m_bndu[i]) - state.m_an[i]=0; - else - state.m_an[i]=1; - } - for(i=0;i<=n-1;i++) - { - //--- check - if(state.m_ak[i]!=state.m_an[i]) - { - state.m_acount=-1; - break; - } - } - state.m_acount=state.m_acount+1; -//--- copy - for(int i_=0;i_<=n-1;i_++) - state.m_xk[i_]=state.m_xn[i_]; - for(int i_=0;i_<=n-1;i_++) - state.m_ak[i_]=state.m_an[i_]; -//--- Stopping conditions - if(!(state.m_repiterationscount>=state.m_maxits&&state.m_maxits>0)) - return(Func_lbl_31(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); -//--- Too many iterations - state.m_repterminationtype=5; -//--- check - if(!state.m_xrep) - return(false); -//--- function call - ClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_rstate.stage=5; -//--- Saving state - Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinASAIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinComp::Func_lbl_31(CMinASAState &state,int &n,int &i, - int &mcinfo,int &diffcnt,bool &b, - bool &stepfound,double &betak, - double &v,double &vv) - { -//--- check - if(ASABoundedAntigradNorm(state)>state.m_epsg) - return(Func_lbl_35(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); -//--- Gradient is small enough - state.m_repterminationtype=4; -//--- check - if(!state.m_xrep) - return(false); -//--- function call - ClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_rstate.stage=6; -//--- Saving state - Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinASAIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinComp::Func_lbl_35(CMinASAState &state,int &n,int &i, - int &mcinfo,int &diffcnt,bool &b, - bool &stepfound,double &betak, - double &v,double &vv) - { -//--- change value - v=0.0; - for(int i_=0;i_<=n-1;i_++) - v+=state.m_d[i_]*state.m_d[i_]; -//--- check - if(MathSqrt(v)*state.m_stp>state.m_epsx) - return(Func_lbl_39(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); -//--- Step size is too small,no further improvement is -//--- possible - state.m_repterminationtype=2; -//--- check - if(!state.m_xrep) - return(false); -//--- function call - ClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_rstate.stage=7; -//--- Saving state - Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinASAIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinComp::Func_lbl_39(CMinASAState &state,int &n,int &i, - int &mcinfo,int &diffcnt,bool &b, - bool &stepfound,double &betak, - double &v,double &vv) - { -//--- check - if(state.m_finit-state.m_f>state.m_epsf*MathMax(MathAbs(state.m_finit),MathMax(MathAbs(state.m_f),1.0))) - return(Func_lbl_43(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); -//--- F(k+1)-F(k) is small enough - state.m_repterminationtype=1; -//--- check - if(!state.m_xrep) - return(false); - ClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_rstate.stage=8; -//--- Saving state - Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinASAIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinComp::Func_lbl_43(CMinASAState &state,int &n,int &i, - int &mcinfo,int &diffcnt,bool &b, - bool &stepfound,double &betak, - double &v,double &vv) - { -//--- Decide - should we switch algorithm or not - if(ASAUIsEmpty(state)) - { - //--- check - if(ASAGINorm(state)>=state.m_mu*ASAD1Norm(state)) - { - state.m_curalgo=1; - //--- function call, return result - return(Func_lbl_19(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - } - else - state.m_mu=state.m_mu*m_asarho; - } - else - { - //--- check - if(state.m_acount==m_n1) - { - //--- check - if(ASAGINorm(state)>=state.m_mu*ASAD1Norm(state)) - { - state.m_curalgo=1; - //--- function call, return result - return(Func_lbl_19(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - } - } - } -//--- Next iteration - state.m_k=state.m_k+1; -//--- function call, return result - return(Func_lbl_21(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinASAIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinComp::Func_lbl_49(CMinASAState &state,int &n,int &i, - int &mcinfo,int &diffcnt,bool &b, - bool &stepfound,double &betak, - double &v,double &vv) - { -//--- Store G[k] for later calculation of Y[k] - for(i=0;i<=n-1;i++) - state.m_yk[i]=-state.m_gc[i]; -//--- Make a CG step in direction given by DK[]: -//--- * calculate step. Step projection into feasible set -//--- is used. It has several benefits: a) step may be -//--- found with usual line search,b) multiple constraints -//--- may be activated with one step,c) activated constraints -//--- are detected in a natural way - just compare x[i] with -//--- bounds -//--- * update active set,set B to True,if there -//--- were changes in the set. - for(int i_=0;i_<=n-1;i_++) - state.m_d[i_]=state.m_dk[i_]; - for(int i_=0;i_<=n-1;i_++) - state.m_xn[i_]=state.m_xk[i_]; -//--- change values - state.m_mcstage=0; - state.m_stp=1; -//--- function call - CLinMin::LinMinNormalized(state.m_d,state.m_stp,n); -//--- check - if(state.m_laststep!=0.0) - state.m_stp=state.m_laststep; -//--- function call - CLinMin::MCSrch(n,state.m_xn,state.m_f,state.m_gc,state.m_d,state.m_stp,state.m_stpmax,m_gtol,mcinfo,state.m_nfev,state.m_work,state.m_lstate,state.m_mcstage); -//--- function call, return result - return(Func_lbl_51(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinASAIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinComp::Func_lbl_51(CMinASAState &state,int &n,int &i, - int &mcinfo,int &diffcnt,bool &b, - bool &stepfound,double &betak, - double &v,double &vv) - { -//--- check - if(state.m_mcstage==0) - return(Func_lbl_52(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); -//--- preprocess data: bound State.XN so it belongs to the -//--- feasible set and store it in the State.X - for(i=0;i<=n-1;i++) - state.m_x[i]=CApServ::BoundVal(state.m_xn[i],state.m_bndl[i],state.m_bndu[i]); -//--- RComm - ClearRequestFields(state); -//--- change values - state.m_needfg=true; - state.m_rstate.stage=9; -//--- Saving state - Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinASAIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinComp::Func_lbl_52(CMinASAState &state,int &n,int &i, - int &mcinfo,int &diffcnt,bool &b, - bool &stepfound,double &betak, - double &v,double &vv) - { - diffcnt=0; - for(i=0;i<=n-1;i++) - { - //--- XN contains unprojected result,project it, - //--- save copy to X (will be used for progress reporting) - state.m_xn[i]=CApServ::BoundVal(state.m_xn[i],state.m_bndl[i],state.m_bndu[i]); - //--- update active set - if(state.m_xn[i]==state.m_bndl[i] || state.m_xn[i]==state.m_bndu[i]) - state.m_an[i]=0; - else - state.m_an[i]=1; - //--- check - if(state.m_an[i]!=state.m_ak[i]) - diffcnt=diffcnt+1; - state.m_ak[i]=state.m_an[i]; - } - for(int i_=0;i_<=n-1;i_++) - state.m_xk[i_]=state.m_xn[i_]; -//--- change values - state.m_repnfev=state.m_repnfev+state.m_nfev; - state.m_repiterationscount=state.m_repiterationscount+1; -//--- check - if(!state.m_xrep) - return(Func_lbl_53(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); -//--- progress report - ClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_rstate.stage=10; -//--- Saving state - Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinASAIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinComp::Func_lbl_53(CMinASAState &state,int &n,int &i, - int &mcinfo,int &diffcnt,bool &b, - bool &stepfound,double &betak, - double &v,double &vv) - { -//--- Update info about step length - v=0.0; - for(int i_=0;i_<=n-1;i_++) - v+=state.m_d[i_]*state.m_d[i_]; - state.m_laststep=MathSqrt(v)*state.m_stp; -//--- Check stopping conditions. - if(ASABoundedAntigradNorm(state)>state.m_epsg) - return(Func_lbl_55(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); -//--- Gradient is small enough - state.m_repterminationtype=4; -//--- check - if(!state.m_xrep) - return(false); - ClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_rstate.stage=11; -//--- Saving state - Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinASAIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinComp::Func_lbl_55(CMinASAState &state,int &n,int &i, - int &mcinfo,int &diffcnt,bool &b, - bool &stepfound,double &betak, - double &v,double &vv) - { -//--- check - if(!(state.m_repiterationscount>=state.m_maxits && state.m_maxits>0)) - return(Func_lbl_59(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); -//--- Too many iterations - state.m_repterminationtype=5; -//--- check - if(!state.m_xrep) - return(false); - ClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_rstate.stage=12; -//--- Saving state - Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinASAIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinComp::Func_lbl_59(CMinASAState &state,int &n,int &i, - int &mcinfo,int &diffcnt,bool &b, - bool &stepfound,double &betak, - double &v,double &vv) - { -//--- check - if(!(ASAGINorm(state)>=state.m_mu*ASAD1Norm(state) && diffcnt==0)) - return(Func_lbl_63(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); -//--- These conditions (EpsF/EpsX) are explicitly or implicitly -//--- related to the current step size and influenced -//--- by changes in the active constraints. -//--- For these reasons they are checked only when we don't -//--- want to 'unstick' at the end of the iteration and there -//--- were no changes in the active set. -//--- NOTE: consition |G|>=Mu*|D1| must be exactly opposite -//--- to the condition used to switch back to GPA. At least -//--- one inequality must be strict,otherwise infinite cycle -//--- may occur when |G|=Mu*|D1| (we DON'T test stopping -//--- conditions and we DON'T switch to GPA,so we cycle -//--- indefinitely). - if(state.m_fold-state.m_f>state.m_epsf*MathMax(MathAbs(state.m_fold),MathMax(MathAbs(state.m_f),1.0))) - return(Func_lbl_65(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); -//--- F(k+1)-F(k) is small enough - state.m_repterminationtype=1; - if(!state.m_xrep) - return(false); -//--- function call - ClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_rstate.stage=13; -//--- Saving state - Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinASAIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinComp::Func_lbl_63(CMinASAState &state,int &n,int &i, - int &mcinfo,int &diffcnt,bool &b, - bool &stepfound,double &betak, - double &v,double &vv) - { -//--- Check conditions for switching - if(ASAGINorm(state)0) - { - //--- check - if(ASAUIsEmpty(state) || diffcnt>=m_n2) - state.m_curalgo=1; - else - state.m_curalgo=0; - //--- function call, return result - return(Func_lbl_17(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - } -//--- Calculate D(k+1) -//--- Line search may result in: -//--- * maximum feasible step being taken (already processed) -//--- * point satisfying Wolfe conditions -//--- * some kind of error (CG is restarted by assigning 0.0 to Beta) - if(mcinfo==1) - { - //--- Standard Wolfe conditions are satisfied: - //--- * calculate Y[K] and BetaK - for(int i_=0;i_<=n-1;i_++) - state.m_yk[i_]=state.m_yk[i_]+state.m_gc[i_]; - //--- change value - vv=0.0; - for(int i_=0;i_<=n-1;i_++) - vv+=state.m_yk[i_]*state.m_dk[i_]; - //--- change value - v=0.0; - for(int i_=0;i_<=n-1;i_++) - v+=state.m_gc[i_]*state.m_gc[i_]; - state.m_betady=v/vv; - //--- change value - v=0.0; - for(int i_=0;i_<=n-1;i_++) - v+=state.m_gc[i_]*state.m_yk[i_]; - state.m_betahs=v/vv; - //--- check - if(state.m_cgtype==0) - betak=state.m_betady; - //--- check - if(state.m_cgtype==1) - betak=MathMax(0,MathMin(state.m_betady,state.m_betahs)); - } - else - { - //--- Something is wrong (may be function is too wild or too flat). - //--- We'll set BetaK=0,which will restart CG algorithm. - //--- We can stop later (during normal checks) if stopping conditions are met. - betak=0; - state.m_debugrestartscount=state.m_debugrestartscount+1; - } -//--- change values - for(int i_=0;i_<=n-1;i_++) - state.m_dn[i_]=-state.m_gc[i_]; - for(int i_=0;i_<=n-1;i_++) - state.m_dn[i_]=state.m_dn[i_]+betak*state.m_dk[i_]; - for(int i_=0;i_<=n-1;i_++) - state.m_dk[i_]=state.m_dn[i_]; -//--- update other information - state.m_fold=state.m_f; - state.m_k=state.m_k+1; -//--- function call, return result - return(Func_lbl_49(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for MinASAIteration. Is a product to get rid | -//| of the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static bool CMinComp::Func_lbl_65(CMinASAState &state,int &n,int &i, - int &mcinfo,int &diffcnt,bool &b, - bool &stepfound,double &betak, - double &v,double &vv) - { -//--- check - if(state.m_laststep>state.m_epsx) - return(Func_lbl_63(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv)); -//--- X(k+1)-X(k) is small enough - state.m_repterminationtype=2; -//--- check - if(!state.m_xrep) - return(false); -//--- function call - ClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_rstate.stage=14; -//--- Saving state - Func_lbl_rcomm(state,n,i,mcinfo,diffcnt,b,stepfound,betak,v,vv); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Alglib/solvers.mqh b/Include/Math/Alglib/solvers.mqh deleted file mode 100644 index 5b4d5ed..0000000 --- a/Include/Math/Alglib/solvers.mqh +++ /dev/null @@ -1,3829 +0,0 @@ -//+------------------------------------------------------------------+ -//| solvers.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 "matrix.mqh" -#include "ap.mqh" -#include "alglibinternal.mqh" -#include "linalg.mqh" -//+------------------------------------------------------------------+ -//| Auxiliary class for CDenseSolver | -//+------------------------------------------------------------------+ -class CDenseSolverReport - { -public: - double m_r1; - double m_rinf; - - CDenseSolverReport(void); - ~CDenseSolverReport(void); - - void Copy(CDenseSolverReport &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CDenseSolverReport::CDenseSolverReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CDenseSolverReport::~CDenseSolverReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CDenseSolverReport::Copy(CDenseSolverReport &obj) - { -//--- copy variables - m_r1=obj.m_r1; - m_rinf=obj.m_rinf; - } -//+------------------------------------------------------------------+ -//| This class is a shell for class CDenseSolverReport | -//+------------------------------------------------------------------+ -class CDenseSolverReportShell - { -private: - CDenseSolverReport m_innerobj; -public: - //--- constructors, destructor - CDenseSolverReportShell(void); - CDenseSolverReportShell(CDenseSolverReport &obj); - ~CDenseSolverReportShell(void); - //--- methods - double GetR1(void); - void SetR1(const double d); - double GetRInf(void); - void SetRInf(const double d); - CDenseSolverReport *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CDenseSolverReportShell::CDenseSolverReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CDenseSolverReportShell::CDenseSolverReportShell(CDenseSolverReport &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CDenseSolverReportShell::~CDenseSolverReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable r1 | -//+------------------------------------------------------------------+ -double CDenseSolverReportShell::GetR1(void) - { -//--- return result - return(m_innerobj.m_r1); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable r1 | -//+------------------------------------------------------------------+ -void CDenseSolverReportShell::SetR1(const double d) - { -//--- change value - m_innerobj.m_r1=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable rinf | -//+------------------------------------------------------------------+ -double CDenseSolverReportShell::GetRInf(void) - { -//--- return result - return(m_innerobj.m_rinf); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable rinf | -//+------------------------------------------------------------------+ -void CDenseSolverReportShell::SetRInf(const double d) - { -//--- change value - m_innerobj.m_rinf=d; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CDenseSolverReport *CDenseSolverReportShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Auxiliary class for CDenseSolver | -//+------------------------------------------------------------------+ -class CDenseSolverLSReport - { -public: - double m_r2; - CMatrixDouble m_cx; - int m_n; - int m_k; - //--- constructor, destructor - CDenseSolverLSReport(void); - ~CDenseSolverLSReport(void); - //--- copy - void Copy(CDenseSolverLSReport &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CDenseSolverLSReport::CDenseSolverLSReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CDenseSolverLSReport::~CDenseSolverLSReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CDenseSolverLSReport::Copy(CDenseSolverLSReport &obj) - { -//--- copy variables - m_r2=obj.m_r2; - m_n=obj.m_n; - m_k=obj.m_k; -//--- copy matrix - m_cx=obj.m_cx; - } -//+------------------------------------------------------------------+ -//| This class is a shell for class CDenseSolverLSReport | -//+------------------------------------------------------------------+ -class CDenseSolverLSReportShell - { -private: - CDenseSolverLSReport m_innerobj; -public: - //--- constructors, destructor - CDenseSolverLSReportShell(void); - CDenseSolverLSReportShell(CDenseSolverLSReport &obj); - ~CDenseSolverLSReportShell(void); - //--- methods - double GetR2(void); - void SetR2(const double d); - int GetN(void); - void SetN(const int i); - int GetK(void); - void SetK(const int i); - CDenseSolverLSReport *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CDenseSolverLSReportShell::CDenseSolverLSReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CDenseSolverLSReportShell::CDenseSolverLSReportShell(CDenseSolverLSReport &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CDenseSolverLSReportShell::~CDenseSolverLSReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable r2 | -//+------------------------------------------------------------------+ -double CDenseSolverLSReportShell::GetR2(void) - { -//--- return result - return(m_innerobj.m_r2); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable r2 | -//+------------------------------------------------------------------+ -void CDenseSolverLSReportShell::SetR2(const double d) - { -//--- change value - m_innerobj.m_r2=d; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable n | -//+------------------------------------------------------------------+ -int CDenseSolverLSReportShell::GetN(void) - { -//--- return result - return(m_innerobj.m_n); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable n | -//+------------------------------------------------------------------+ -void CDenseSolverLSReportShell::SetN(const int i) - { -//--- change value - m_innerobj.m_n=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable k | -//+------------------------------------------------------------------+ -int CDenseSolverLSReportShell::GetK(void) - { -//--- return result - return(m_innerobj.m_k); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable k | -//+------------------------------------------------------------------+ -void CDenseSolverLSReportShell::SetK(const int i) - { -//--- change value - m_innerobj.m_k=i; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CDenseSolverLSReport *CDenseSolverLSReportShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Dense solver | -//+------------------------------------------------------------------+ -class CDenseSolver - { -private: - //--- private methods - static void RMatrixLUSolveInternal(CMatrixDouble &lua,int &p[],const double scalea,const int n,CMatrixDouble &a,const bool havea,CMatrixDouble &b,const int m,int &info,CDenseSolverReport &rep,CMatrixDouble &x); - static void SPDMatrixCholeskySolveInternal(CMatrixDouble &cha,const double sqrtscalea,const int n,const bool isupper,CMatrixDouble &a,const bool havea,CMatrixDouble &b,const int m,int &info,CDenseSolverReport &rep,CMatrixDouble &x); - static void CMatrixLUSolveInternal(CMatrixComplex &lua,int &p[],const double scalea,const int n,CMatrixComplex &a,const bool havea,CMatrixComplex &b,const int m,int &info,CDenseSolverReport &rep,CMatrixComplex &x); - static void HPDMatrixCholeskySolveInternal(CMatrixComplex &cha,const double sqrtscalea,const int n,const bool isupper,CMatrixComplex &a,const bool havea,CMatrixComplex &b,const int m,int &info,CDenseSolverReport &rep,CMatrixComplex &x); - static int CDenseSolverRFSMax(const int n,const double r1,const double rinf); - static int CDenseSolverRFSMaxV2(const int n,const double r2); - static void RBasicLUSolve(CMatrixDouble &lua,int &p[],const double scalea,const int n,double &xb[],double &tmp[]); - static void SPDBasicCholeskySolve(CMatrixDouble &cha,const double sqrtscalea,const int n,const bool isupper,double &xb[],double &tmp[]); - static void CBasicLUSolve(CMatrixComplex &lua,int &p[],const double scalea,const int n,al_complex &xb[],al_complex &tmp[]); - static void HPDBasicCholeskySolve(CMatrixComplex &cha,const double sqrtscalea,const int n,const bool isupper,al_complex &xb[],al_complex &tmp[]); -public: - //--- constructor, destructor - CDenseSolver(void); - ~CDenseSolver(void); - //--- public methods - static void RMatrixSolve(CMatrixDouble &a,const int n,double &b[],int &info,CDenseSolverReport &rep,double &x[]); - static void RMatrixSolveM(CMatrixDouble &a,const int n,CMatrixDouble &b,const int m,const bool rfs,int &info,CDenseSolverReport &rep,CMatrixDouble &x); - static void RMatrixLUSolve(CMatrixDouble &lua,int &p[],const int n,double &b[],int &info,CDenseSolverReport &rep,double &x[]); - static void RMatrixLUSolveM(CMatrixDouble &lua,int &p[],const int n,CMatrixDouble &b,const int m,int &info,CDenseSolverReport &rep,CMatrixDouble &x); - static void RMatrixMixedSolve(CMatrixDouble &a,CMatrixDouble &lua,int &p[],const int n,double &b[],int &info,CDenseSolverReport &rep,double &x[]); - static void RMatrixMixedSolveM(CMatrixDouble &a,CMatrixDouble &lua,int &p[],const int n,CMatrixDouble &b,const int m,int &info,CDenseSolverReport &rep,CMatrixDouble &x); - static void CMatrixSolveM(CMatrixComplex &a,const int n,CMatrixComplex &b,const int m,const bool rfs,int &info,CDenseSolverReport &rep,CMatrixComplex &x); - static void CMatrixSolve(CMatrixComplex &a,const int n,al_complex &b[],int &info,CDenseSolverReport &rep,al_complex &x[]); - static void CMatrixLUSolveM(CMatrixComplex &lua,int &p[],const int n,CMatrixComplex &b,const int m,int &info,CDenseSolverReport &rep,CMatrixComplex &x); - static void CMatrixLUSolve(CMatrixComplex &lua,int &p[],const int n,al_complex &b[],int &info,CDenseSolverReport &rep,al_complex &x[]); - static void CMatrixMixedSolveM(CMatrixComplex &a,CMatrixComplex &lua,int &p[],const int n,CMatrixComplex &b,const int m,int &info,CDenseSolverReport &rep,CMatrixComplex &x); - static void CMatrixMixedSolve(CMatrixComplex &a,CMatrixComplex &lua,int &p[],const int n,al_complex &b[],int &info,CDenseSolverReport &rep,al_complex &x[]); - static void SPDMatrixSolveM(CMatrixDouble &a,const int n,const bool isupper,CMatrixDouble &b,const int m,int &info,CDenseSolverReport &rep,CMatrixDouble &x); - static void SPDMatrixSolve(CMatrixDouble &a,const int n,const bool isupper,double &b[],int &info,CDenseSolverReport &rep,double &x[]); - static void SPDMatrixCholeskySolveM(CMatrixDouble &cha,const int n,const bool isupper,CMatrixDouble &b,const int m,int &info,CDenseSolverReport &rep,CMatrixDouble &x); - static void SPDMatrixCholeskySolve(CMatrixDouble &cha,const int n,const bool isupper,double &b[],int &info,CDenseSolverReport &rep,double &x[]); - static void HPDMatrixSolveM(CMatrixComplex &a,const int n,const bool isupper,CMatrixComplex &b,const int m,int &info,CDenseSolverReport &rep,CMatrixComplex &x); - static void HPDMatrixSolve(CMatrixComplex &a,const int n,const bool isupper,al_complex &b[],int &info,CDenseSolverReport &rep,al_complex &x[]); - static void HPDMatrixCholeskySolveM(CMatrixComplex &cha,const int n,const bool isupper,CMatrixComplex &b,const int m,int &info,CDenseSolverReport &rep,CMatrixComplex &x); - static void HPDMatrixCholeskySolve(CMatrixComplex &cha,const int n,const bool isupper,al_complex &b[],int &info,CDenseSolverReport &rep,al_complex &x[]); - static void RMatrixSolveLS(CMatrixDouble &a,const int nrows,const int ncols,double &b[],double threshold,int &info,CDenseSolverLSReport &rep,double &x[]); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CDenseSolver::CDenseSolver(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CDenseSolver::~CDenseSolver(void) - { - - } -//+------------------------------------------------------------------+ -//| Dense solver. | -//| This subroutine solves a system A*x=b, where A is NxN | -//| non-denegerate real matrix, x and b are vectors. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * iterative refinement | -//| * O(N^3) complexity | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| N - size of A | -//| B - array[0..N-1], right part | -//| OUTPUT PARAMETERS | -//| Info - return code: | -//| * -3 A is singular, or VERY close to singular.| -//| X is filled by zeros in such cases. | -//| * -1 N<=0 was passed | -//| * 1 task is solved (but matrix A may be | -//| ill-conditioned, check R1/RInf parameters| -//| for condition numbers). | -//| Rep - solver report, see below for more info | -//| X - array[0..N-1], it contains: | -//| * solution of A*x=b if A is non-singular | -//| (well-conditioned or ill-conditioned, but not | -//| very close to singular) | -//| * zeros, if A is singular or VERY close to | -//| singular (in this case Info=-3). | -//| SOLVER REPORT | -//| Subroutine sets following fields of the Rep structure: | -//| * R1 reciprocal of condition number: 1/cond(A), 1-norm. | -//| * RInf reciprocal of condition number: 1/cond(A), inf-norm. | -//+------------------------------------------------------------------+ -static void CDenseSolver::RMatrixSolve(CMatrixDouble &a,const int n,double &b[], - int &info,CDenseSolverReport &rep, - double &x[]) - { -//--- create a variable - int i_=0; -//--- create matrix - CMatrixDouble bm; - CMatrixDouble xm; -//--- initialization - info=0; -//--- check - if(n<=0) - { - info=-1; - return; - } -//--- allocation - bm.Resize(n,1); -//--- filling - for(i_=0;i_<=n-1;i_++) - bm[i_].Set(0,b[i_]); -//--- function call - RMatrixSolveM(a,n,bm,1,true,info,rep,xm); -//--- allocation - ArrayResizeAL(x,n); -//--- copy - for(i_=0;i_<=n-1;i_++) - x[i_]=xm[i_][0]; - } -//+------------------------------------------------------------------+ -//| Dense solver. | -//| Similar to RMatrixSolve() but solves task with multiple right | -//| parts (where b and x are NxM matrices). | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * optional iterative refinement | -//| * O(N^3+M*N^2) complexity | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| N - size of A | -//| B - array[0..N-1,0..M-1], right part | -//| M - right part size | -//| RFS - iterative refinement switch: | -//| * True - refinement is used. | -//| Less performance, more precision. | -//| * False - refinement is not used. | -//| More performance, less precision. | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CDenseSolver::RMatrixSolveM(CMatrixDouble &a,const int n, - CMatrixDouble &b,const int m, - const bool rfs,int &info, - CDenseSolverReport &rep, - CMatrixDouble &x) - { -//--- create variables - double scalea=0; - int i=0; - int j=0; - int i_=0; -//--- create matrix - CMatrixDouble da; - CMatrixDouble emptya; -//--- create array - int p[]; -//--- initialization - info=0; -//--- prepare: check inputs,allocate space... - if(n<=0 || m<=0) - { - info=-1; - return; - } -//--- allocation - da.Resize(n,n); -//--- 1. scale matrix,max(|A[i][j]|) -//--- 2. factorize scaled matrix -//--- 3. solve - scalea=0; - for(i=0;i<=n-1;i++) - { - for(j=0;j<=n-1;j++) - scalea=MathMax(scalea,MathAbs(a[i][j])); - } -//--- check - if(scalea==0.0) - scalea=1; -//--- change values - scalea=1/scalea; - for(i=0;i<=n-1;i++) - { - for(i_=0;i_<=n-1;i_++) - da[i].Set(i_,a[i][i_]); - } -//--- function call - CTrFac::RMatrixLU(da,n,n,p); -//--- check - if(rfs) - RMatrixLUSolveInternal(da,p,scalea,n,a,true,b,m,info,rep,x); - else - RMatrixLUSolveInternal(da,p,scalea,n,emptya,false,b,m,info,rep,x); - } -//+------------------------------------------------------------------+ -//| Dense solver. | -//| This subroutine solves a system A*X=B, where A is NxN | -//| non-denegerate real matrix given by its LU decomposition, X and | -//| B are NxM real matrices. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * O(N^2) complexity | -//| * condition number estimation | -//| No iterative refinement is provided because exact form of | -//| original matrix is not known to subroutine. Use RMatrixSolve or | -//| RMatrixMixedSolve if you need iterative refinement. | -//| INPUT PARAMETERS | -//| LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU| -//| result | -//| P - array[0..N-1], pivots array, RMatrixLU result | -//| N - size of A | -//| B - array[0..N-1], right part | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CDenseSolver::RMatrixLUSolve(CMatrixDouble &lua,int &p[], - const int n,double &b[], - int &info,CDenseSolverReport &rep, - double &x[]) - { -//--- create matrix - CMatrixDouble bm; - CMatrixDouble xm; -//--- create a variable - int i_=0; -//--- initialization - info=0; -//--- check - if(n<=0) - { - info=-1; - return; - } -//--- allocation - bm.Resize(n,1); -//--- filling - for(i_=0;i_<=n-1;i_++) - bm[i_].Set(0,b[i_]); -//--- function call - RMatrixLUSolveM(lua,p,n,bm,1,info,rep,xm); -//--- allocation - ArrayResizeAL(x,n); -//--- copy - for(i_=0;i_<=n-1;i_++) - x[i_]=xm[i_][0]; - } -//+------------------------------------------------------------------+ -//| Dense solver. | -//| Similar to RMatrixLUSolve() but solves task with multiple right | -//| parts (where b and x are NxM matrices). | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * O(M*N^2) complexity | -//| * condition number estimation | -//| No iterative refinement is provided because exact form of | -//| original matrix is not known to subroutine. Use RMatrixSolve or | -//| RMatrixMixedSolve if you need iterative refinement. | -//| INPUT PARAMETERS | -//| LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU| -//| result | -//| P - array[0..N-1], pivots array, RMatrixLU result | -//| N - size of A | -//| B - array[0..N-1,0..M-1], right part | -//| M - right part size | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CDenseSolver::RMatrixLUSolveM(CMatrixDouble &lua,int &p[], - const int n,CMatrixDouble &b, - const int m,int &info, - CDenseSolverReport &rep, - CMatrixDouble &x) - { -//--- create matrix - CMatrixDouble emptya; -//--- create variables - int i=0; - int j=0; - double scalea=0; -//--- initialization - info=0; -//--- prepare: check inputs,allocate space... - if(n<=0 || m<=0) - { - info=-1; - return; - } -//--- 1. scale matrix,max(|U[i][j]|) -//--- we assume that LU is in its normal form,i.e. |L[i][j]|<=1 -//--- 2. solve - scalea=0; - for(i=0;i<=n-1;i++) - { - for(j=i;j<=n-1;j++) - scalea=MathMax(scalea,MathAbs(lua[i][j])); - } -//--- check - if(scalea==0.0) - scalea=1; -//--- change values - scalea=1/scalea; -//--- function call - RMatrixLUSolveInternal(lua,p,scalea,n,emptya,false,b,m,info,rep,x); - } -//+------------------------------------------------------------------+ -//| Dense solver. | -//| This subroutine solves a system A*x=b, where BOTH ORIGINAL A AND | -//| ITS LU DECOMPOSITION ARE KNOWN. You can use it if for some | -//| reasons you have both A and its LU decomposition. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * iterative refinement | -//| * O(N^2) complexity | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU| -//| result | -//| P - array[0..N-1], pivots array, RMatrixLU result | -//| N - size of A | -//| B - array[0..N-1], right part | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolveM | -//| Rep - same as in RMatrixSolveM | -//| X - same as in RMatrixSolveM | -//+------------------------------------------------------------------+ -static void CDenseSolver::RMatrixMixedSolve(CMatrixDouble &a,CMatrixDouble &lua, - int &p[],const int n,double &b[], - int &info,CDenseSolverReport &rep, - double &x[]) - { -//--- create a variable - int i_=0; -//--- create matrix - CMatrixDouble bm; - CMatrixDouble xm; -//--- initialization - info=0; -//--- check - if(n<=0) - { - info=-1; - return; - } -//--- allocation - bm.Resize(n,1); -//--- filling - for(i_=0;i_<=n-1;i_++) - bm[i_].Set(0,b[i_]); -//--- function call - RMatrixMixedSolveM(a,lua,p,n,bm,1,info,rep,xm); -//--- allocation - ArrayResizeAL(x,n); -//--- copy - for(i_=0;i_<=n-1;i_++) - x[i_]=xm[i_][0]; - } -//+------------------------------------------------------------------+ -//| Dense solver. | -//| Similar to RMatrixMixedSolve() but solves task with multiple | -//| right parts (where b and x are NxM matrices). | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * iterative refinement | -//| * O(M*N^2) complexity | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU| -//| result | -//| P - array[0..N-1], pivots array, RMatrixLU result | -//| N - size of A | -//| B - array[0..N-1,0..M-1], right part | -//| M - right part size | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolveM | -//| Rep - same as in RMatrixSolveM | -//| X - same as in RMatrixSolveM | -//+------------------------------------------------------------------+ -static void CDenseSolver::RMatrixMixedSolveM(CMatrixDouble &a,CMatrixDouble &lua, - int &p[],const int n,CMatrixDouble &b, - const int m,int &info, - CDenseSolverReport &rep, - CMatrixDouble &x) - { -//--- create variables - double scalea=0; - int i=0; - int j=0; -//--- initialization - info=0; -//--- prepare: check inputs,allocate space... - if(n<=0 || m<=0) - { - info=-1; - return; - } -//--- 1. scale matrix,max(|A[i][j]|) -//--- 2. factorize scaled matrix -//--- 3. solve - scalea=0; - for(i=0;i<=n-1;i++) - { - for(j=0;j<=n-1;j++) - scalea=MathMax(scalea,MathAbs(a[i][j])); - } -//--- check - if(scalea==0.0) - scalea=1; -//--- change values - scalea=1/scalea; -//--- function call - RMatrixLUSolveInternal(lua,p,scalea,n,a,true,b,m,info,rep,x); - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixSolveM(), but for complex matrices. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * iterative refinement | -//| * O(N^3+M*N^2) complexity | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| N - size of A | -//| B - array[0..N-1,0..M-1], right part | -//| M - right part size | -//| RFS - iterative refinement switch: | -//| * True - refinement is used. | -//| Less performance, more precision. | -//| * False - refinement is not used. | -//| More performance, less precision. | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CDenseSolver::CMatrixSolveM(CMatrixComplex &a,const int n, - CMatrixComplex &b,const int m, - const bool rfs,int &info, - CDenseSolverReport &rep, - CMatrixComplex &x) - { -//--- create variables - double scalea=0; - int i=0; - int j=0; - int i_=0; -//--- create array - int p[]; -//--- create matrix - CMatrixComplex da; - CMatrixComplex emptya; -//--- initialization - info=0; -//--- prepare: check inputs,allocate space... - if(n<=0 || m<=0) - { - info=-1; - return; - } -//--- allocation - da.Resize(n,n); -//--- 1. scale matrix,max(|A[i][j]|) -//--- 2. factorize scaled matrix -//--- 3. solve - scalea=0; - for(i=0;i<=n-1;i++) - { - for(j=0;j<=n-1;j++) - scalea=MathMax(scalea,CMath::AbsComplex(a[i][j])); - } -//--- check - if(scalea==0.0) - scalea=1; -//--- change values - scalea=1/scalea; - for(i=0;i<=n-1;i++) - { - for(i_=0;i_<=n-1;i_++) - da[i].Set(i_,a[i][i_]); - } -//--- function call - CTrFac::CMatrixLU(da,n,n,p); -//--- check - if(rfs) - CMatrixLUSolveInternal(da,p,scalea,n,a,true,b,m,info,rep,x); - else - CMatrixLUSolveInternal(da,p,scalea,n,emptya,false,b,m,info,rep,x); - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixSolve(), but for complex matrices. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * iterative refinement | -//| * O(N^3) complexity | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| N - size of A | -//| B - array[0..N-1], right part | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CDenseSolver::CMatrixSolve(CMatrixComplex &a,const int n, - al_complex &b[],int &info, - CDenseSolverReport &rep,al_complex &x[]) - { -//--- create a variable - int i_=0; -//--- create matrix - CMatrixComplex bm; - CMatrixComplex xm; -//--- initialization - info=0; -//--- check - if(n<=0) - { - info=-1; - return; - } -//--- allocation - bm.Resize(n,1); -//--- filling - for(i_=0;i_<=n-1;i_++) - bm[i_].Set(0,b[i_]); -//--- function call - CMatrixSolveM(a,n,bm,1,true,info,rep,xm); -//--- allocation - ArrayResizeAL(x,n); -//--- copy - for(i_=0;i_<=n-1;i_++) - x[i_]=xm[i_][0]; - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixLUSolveM(), but for complex | -//| matrices. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * O(M*N^2) complexity | -//| * condition number estimation | -//| No iterative refinement is provided because exact form of | -//| original matrix is not known to subroutine. Use CMatrixSolve or | -//| CMatrixMixedSolve if you need iterative refinement. | -//| INPUT PARAMETERS | -//| LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU| -//| result | -//| P - array[0..N-1], pivots array, RMatrixLU result | -//| N - size of A | -//| B - array[0..N-1,0..M-1], right part | -//| M - right part size | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CDenseSolver::CMatrixLUSolveM(CMatrixComplex &lua,int &p[], - const int n,CMatrixComplex &b, - const int m,int &info, - CDenseSolverReport &rep, - CMatrixComplex &x) - { -//--- create variables - int i=0; - int j=0; - double scalea=0; -//--- create matrix - CMatrixComplex emptya; -//--- initialization - info=0; -//--- prepare: check inputs,allocate space... - if(n<=0 || m<=0) - { - info=-1; - return; - } -//--- 1. scale matrix,max(|U[i][j]|) -//--- we assume that LU is in its normal form,i.e. |L[i][j]|<=1 -//--- 2. solve - scalea=0; - for(i=0;i<=n-1;i++) - { - for(j=i;j<=n-1;j++) - scalea=MathMax(scalea,CMath::AbsComplex(lua[i][j])); - } -//--- check - if(scalea==0.0) - scalea=1; -//--- change values - scalea=1/scalea; -//--- function call - CMatrixLUSolveInternal(lua,p,scalea,n,emptya,false,b,m,info,rep,x); - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixLUSolve(), but for complex matrices.| -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * O(N^2) complexity | -//| * condition number estimation | -//| No iterative refinement is provided because exact form of | -//| original matrix is not known to subroutine. Use CMatrixSolve or | -//| CMatrixMixedSolve if you need iterative refinement. | -//| INPUT PARAMETERS | -//| LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU| -//| result | -//| P - array[0..N-1], pivots array, CMatrixLU result | -//| N - size of A | -//| B - array[0..N-1], right part | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CDenseSolver::CMatrixLUSolve(CMatrixComplex &lua,int &p[], - const int n,al_complex &b[],int &info, - CDenseSolverReport &rep,al_complex &x[]) - { -//--- create matrix - CMatrixComplex bm; - CMatrixComplex xm; -//--- create a variable - int i_=0; -//--- initialization - info=0; -//--- check - if(n<=0) - { - info=-1; - return; - } -//--- allocation - bm.Resize(n,1); -//--- filling - for(i_=0;i_<=n-1;i_++) - bm[i_].Set(0,b[i_]); -//--- function call - CMatrixLUSolveM(lua,p,n,bm,1,info,rep,xm); -//--- allocation - ArrayResizeAL(x,n); -//--- copy - for(i_=0;i_<=n-1;i_++) - x[i_]=xm[i_][0]; - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixMixedSolveM(), but for complex | -//| matrices. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * iterative refinement | -//| * O(M*N^2) complexity | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU| -//| result | -//| P - array[0..N-1], pivots array, CMatrixLU result | -//| N - size of A | -//| B - array[0..N-1,0..M-1], right part | -//| M - right part size | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolveM | -//| Rep - same as in RMatrixSolveM | -//| X - same as in RMatrixSolveM | -//+------------------------------------------------------------------+ -static void CDenseSolver::CMatrixMixedSolveM(CMatrixComplex &a,CMatrixComplex &lua, - int &p[],const int n,CMatrixComplex &b, - const int m,int &info,CDenseSolverReport &rep, - CMatrixComplex &x) - { -//--- create variables - double scalea=0; - int i=0; - int j=0; -//--- initialization - info=0; -//--- prepare: check inputs,allocate space... - if(n<=0 || m<=0) - { - info=-1; - return; - } -//--- 1. scale matrix,max(|A[i][j]|) -//--- 2. factorize scaled matrix -//--- 3. solve - scalea=0; - for(i=0;i<=n-1;i++) - { - for(j=0;j<=n-1;j++) - scalea=MathMax(scalea,CMath::AbsComplex(a[i][j])); - } -//--- check - if(scalea==0.0) - scalea=1; -//--- change values - scalea=1/scalea; -//--- function call - CMatrixLUSolveInternal(lua,p,scalea,n,a,true,b,m,info,rep,x); - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixMixedSolve(), but for complex | -//| matrices. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * iterative refinement | -//| * O(N^2) complexity | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU| -//| result | -//| P - array[0..N-1], pivots array, CMatrixLU result | -//| N - size of A | -//| B - array[0..N-1], right part | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolveM | -//| Rep - same as in RMatrixSolveM | -//| X - same as in RMatrixSolveM | -//+------------------------------------------------------------------+ -static void CDenseSolver::CMatrixMixedSolve(CMatrixComplex &a,CMatrixComplex &lua, - int &p[],const int n,al_complex &b[], - int &info,CDenseSolverReport &rep, - al_complex &x[]) - { -//--- create matrix - CMatrixComplex bm; - CMatrixComplex xm; -//--- create a variable - int i_=0; -//--- initialization - info=0; -//--- check - if(n<=0) - { - info=-1; - return; - } -//--- allocation - bm.Resize(n,1); -//--- filling - for(i_=0;i_<=n-1;i_++) - bm[i_].Set(0,b[i_]); -//--- function call - CMatrixMixedSolveM(a,lua,p,n,bm,1,info,rep,xm); -//--- allocation - ArrayResizeAL(x,n); -//--- copy - for(i_=0;i_<=n-1;i_++) - x[i_]=xm[i_][0]; - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixSolveM(), but for symmetric positive| -//| definite matrices. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * O(N^3+M*N^2) complexity | -//| * matrix is represented by its upper or lower triangle | -//| No iterative refinement is provided because such partial | -//| representation of matrix does not allow efficient calculation of | -//| extra-precise matrix-vector products for large matrices. Use | -//| RMatrixSolve or RMatrixMixedSolve if you need iterative | -//| refinement. | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| N - size of A | -//| IsUpper - what half of A is provided | -//| B - array[0..N-1,0..M-1], right part | -//| M - right part size | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve. | -//| Returns -3 for non-SPD matrices. | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CDenseSolver::SPDMatrixSolveM(CMatrixDouble &a,const int n, - const bool isupper,CMatrixDouble &b, - const int m,int &info, - CDenseSolverReport &rep, - CMatrixDouble &x) - { -//--- create variables - double sqrtscalea=0; - int i=0; - int j=0; - int j1=0; - int j2=0; - int i_=0; -//--- create matrix - CMatrixDouble da; -//--- initialization - info=0; -//--- prepare: check inputs,allocate space... - if(n<=0 || m<=0) - { - info=-1; - return; - } -//--- allocation - da.Resize(n,n); -//--- 1. scale matrix,max(|A[i][j]|) -//--- 2. factorize scaled matrix -//--- 3. solve - sqrtscalea=0; - for(i=0;i<=n-1;i++) - { - //--- check - if(isupper) - { - j1=i; - j2=n-1; - } - else - { - j1=0; - j2=i; - } - //--- calculation - for(j=j1;j<=j2;j++) - sqrtscalea=MathMax(sqrtscalea,MathAbs(a[i][j])); - } -//--- check - if(sqrtscalea==0.0) - sqrtscalea=1; -//--- change values - sqrtscalea=1/sqrtscalea; - sqrtscalea=MathSqrt(sqrtscalea); - for(i=0;i<=n-1;i++) - { - //--- check - if(isupper) - { - j1=i; - j2=n-1; - } - else - { - j1=0; - j2=i; - } - //--- calculation - for(i_=j1;i_<=j2;i_++) - da[i].Set(i_,a[i][i_]); - } -//--- check - if(!CTrFac::SPDMatrixCholesky(da,n,isupper)) - { - //--- allocation - x.Resize(n,m); - for(i=0;i<=n-1;i++) - { - for(j=0;j<=m-1;j++) - x[i].Set(j,0); - } - //--- change values - rep.m_r1=0; - rep.m_rinf=0; - info=-3; - //--- exit the function - return; - } - info=1; -//--- function call - SPDMatrixCholeskySolveInternal(da,sqrtscalea,n,isupper,a,true,b,m,info,rep,x); - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixSolve(), but for SPD matrices. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * O(N^3) complexity | -//| * matrix is represented by its upper or lower triangle | -//| No iterative refinement is provided because such partial | -//| representation of matrix does not allow efficient calculation of | -//| extra-precise matrix-vector products for large matrices. Use | -//| RMatrixSolve or RMatrixMixedSolve if you need iterative | -//| refinement. | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| N - size of A | -//| IsUpper - what half of A is provided | -//| B - array[0..N-1], right part | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Returns -3 for non-SPD matrices. | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CDenseSolver::SPDMatrixSolve(CMatrixDouble &a,const int n, - const bool isupper,double &b[], - int &info,CDenseSolverReport &rep, - double &x[]) - { -//--- create a variable - int i_=0; -//--- create matrix - CMatrixDouble bm; - CMatrixDouble xm; -//--- initialization - info=0; -//--- check - if(n<=0) - { - info=-1; - return; - } -//--- allocation - bm.Resize(n,1); -//--- filling - for(i_=0;i_<=n-1;i_++) - bm[i_].Set(0,b[i_]); -//--- function call - SPDMatrixSolveM(a,n,isupper,bm,1,info,rep,xm); -//--- allocation - ArrayResizeAL(x,n); -//--- copy - for(i_=0;i_<=n-1;i_++) - x[i_]=xm[i_][0]; - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixLUSolveM(), but for SPD matrices | -//| represented by their Cholesky decomposition. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * O(M*N^2) complexity | -//| * condition number estimation | -//| * matrix is represented by its upper or lower triangle | -//| No iterative refinement is provided because such partial | -//| representation of matrix does not allow efficient calculation of | -//| extra-precise matrix-vector products for large matrices. Use | -//| RMatrixSolve or RMatrixMixedSolve if you need iterative | -//| refinement. | -//| INPUT PARAMETERS | -//| CHA - array[0..N-1,0..N-1], Cholesky decomposition, | -//| SPDMatrixCholesky result | -//| N - size of CHA | -//| IsUpper - what half of CHA is provided | -//| B - array[0..N-1,0..M-1], right part | -//| M - right part size | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CDenseSolver::SPDMatrixCholeskySolveM(CMatrixDouble &cha,const int n, - const bool isupper,CMatrixDouble &b, - const int m,int &info, - CDenseSolverReport &rep, - CMatrixDouble &x) - { -//--- create variables - double sqrtscalea=0; - int i=0; - int j=0; - int j1=0; - int j2=0; -//--- create matrix - CMatrixDouble emptya; -//--- initialization - info=0; -//--- prepare: check inputs,allocate space... - if(n<=0 || m<=0) - { - info=-1; - return; - } -//--- 1. scale matrix,max(|U[i][j]|) -//--- 2. factorize scaled matrix -//--- 3. solve - sqrtscalea=0; - for(i=0;i<=n-1;i++) - { - //--- check - if(isupper) - { - j1=i; - j2=n-1; - } - else - { - j1=0; - j2=i; - } - //--- calculation - for(j=j1;j<=j2;j++) - sqrtscalea=MathMax(sqrtscalea,MathAbs(cha[i][j])); - } -//--- check - if(sqrtscalea==0.0) - sqrtscalea=1; -//--- change values - sqrtscalea=1/sqrtscalea; -//--- function call - SPDMatrixCholeskySolveInternal(cha,sqrtscalea,n,isupper,emptya,false,b,m,info,rep,x); - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixLUSolve(), but for SPD matrices | -//| represented by their Cholesky decomposition. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * O(N^2) complexity | -//| * condition number estimation | -//| * matrix is represented by its upper or lower triangle | -//| No iterative refinement is provided because such partial | -//| representation of matrix does not allow efficient calculation of | -//| extra-precise matrix-vector products for large matrices. Use | -//| RMatrixSolve or RMatrixMixedSolve if you need iterative | -//| refinement. | -//| INPUT PARAMETERS | -//| CHA - array[0..N-1,0..N-1], Cholesky decomposition, | -//| SPDMatrixCholesky result | -//| N - size of A | -//| IsUpper - what half of CHA is provided | -//| B - array[0..N-1], right part | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CDenseSolver::SPDMatrixCholeskySolve(CMatrixDouble &cha,const int n, - const bool isupper,double &b[], - int &info,CDenseSolverReport &rep, - double &x[]) - { -//--- create a variable - int i_=0; -//--- create matrix - CMatrixDouble bm; - CMatrixDouble xm; -//--- initialization - info=0; -//--- check - if(n<=0) - { - info=-1; - return; - } -//--- allocation - bm.Resize(n,1); -//--- filling - for(i_=0;i_<=n-1;i_++) - bm[i_].Set(0,b[i_]); -//--- function call - SPDMatrixCholeskySolveM(cha,n,isupper,bm,1,info,rep,xm); -//--- allocation - ArrayResizeAL(x,n); -//--- copy - for(i_=0;i_<=n-1;i_++) - x[i_]=xm[i_][0]; - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixSolveM(), but for Hermitian positive| -//| definite matrices. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * O(N^3+M*N^2) complexity | -//| * matrix is represented by its upper or lower triangle | -//| No iterative refinement is provided because such partial | -//| representation of matrix does not allow efficient calculation of | -//| extra-precise matrix-vector products for large matrices. Use | -//| RMatrixSolve or RMatrixMixedSolve if you need iterative | -//| refinement. | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| N - size of A | -//| IsUpper - what half of A is provided | -//| B - array[0..N-1,0..M-1], right part | -//| M - right part size | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve. | -//| Returns -3 for non-HPD matrices. | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CDenseSolver::HPDMatrixSolveM(CMatrixComplex &a,const int n, - const bool isupper,CMatrixComplex &b, - const int m,int &info, - CDenseSolverReport &rep,CMatrixComplex &x) - { -//--- create variables - double sqrtscalea=0; - int i=0; - int j=0; - int j1=0; - int j2=0; - int i_=0; -//--- create matrix - CMatrixComplex da; -//--- initialization - info=0; -//--- prepare: check inputs,allocate space... - if(n<=0 || m<=0) - { - info=-1; - return; - } -//--- allocation - da.Resize(n,n); -//--- 1. scale matrix,max(|A[i][j]|) -//--- 2. factorize scaled matrix -//--- 3. solve - sqrtscalea=0; - for(i=0;i<=n-1;i++) - { - //--- check - if(isupper) - { - j1=i; - j2=n-1; - } - else - { - j1=0; - j2=i; - } - //--- calculation - for(j=j1;j<=j2;j++) - sqrtscalea=MathMax(sqrtscalea,CMath::AbsComplex(a[i][j])); - } -//--- check - if(sqrtscalea==0.0) - sqrtscalea=1; -//--- change values - sqrtscalea=1/sqrtscalea; - sqrtscalea=MathSqrt(sqrtscalea); - for(i=0;i<=n-1;i++) - { - //--- check - if(isupper) - { - j1=i; - j2=n-1; - } - else - { - j1=0; - j2=i; - } - //--- calculation - for(i_=j1;i_<=j2;i_++) - da[i].Set(i_,a[i][i_]); - } -//--- check - if(!CTrFac::HPDMatrixCholesky(da,n,isupper)) - { - //--- allocation - x.Resize(n,m); - for(i=0;i<=n-1;i++) - { - for(j=0;j<=m-1;j++) - x[i].Set(j,0); - } - //--- change values - rep.m_r1=0; - rep.m_rinf=0; - info=-3; - //--- exit the function - return; - } - info=1; -//--- function call - HPDMatrixCholeskySolveInternal(da,sqrtscalea,n,isupper,a,true,b,m,info,rep,x); - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixSolve(), but for Hermitian positive | -//| definite matrices. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * condition number estimation | -//| * O(N^3) complexity | -//| * matrix is represented by its upper or lower triangle | -//| No iterative refinement is provided because such partial | -//| representation of matrix does not allow efficient calculation of | -//| extra-precise matrix-vector products for large matrices. Use | -//| RMatrixSolve or RMatrixMixedSolve if you need iterative | -//| refinement. | -//| INPUT PARAMETERS | -//| A - array[0..N-1,0..N-1], system matrix | -//| N - size of A | -//| IsUpper - what half of A is provided | -//| B - array[0..N-1], right part | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Returns -3 for non-HPD matrices. | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CDenseSolver::HPDMatrixSolve(CMatrixComplex &a,const int n, - const bool isupper,al_complex &b[], - int &info,CDenseSolverReport &rep, - al_complex &x[]) - { -//--- create a variable - int i_=0; -//--- create matrix - CMatrixComplex bm; - CMatrixComplex xm; -//--- initialization - info=0; -//--- check - if(n<=0) - { - info=-1; - return; - } -//--- allocation - bm.Resize(n,1); -//--- filling - for(i_=0;i_<=n-1;i_++) - bm[i_].Set(0,b[i_]); -//--- function call - HPDMatrixSolveM(a,n,isupper,bm,1,info,rep,xm); -//--- allocation - ArrayResizeAL(x,n); -//--- copy - for(i_=0;i_<=n-1;i_++) - x[i_]=xm[i_][0]; - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixLUSolveM(), but for HPD matrices | -//| represented by their Cholesky decomposition. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * O(M*N^2) complexity | -//| * condition number estimation | -//| * matrix is represented by its upper or lower triangle | -//| No iterative refinement is provided because such partial | -//| representation of matrix does not allow efficient calculation of | -//| extra-precise matrix-vector products for large matrices. Use | -//| RMatrixSolve or RMatrixMixedSolve if you need iterative | -//| refinement. | -//| INPUT PARAMETERS | -//| CHA - array[0..N-1,0..N-1], Cholesky decomposition, | -//| HPDMatrixCholesky result | -//| N - size of CHA | -//| IsUpper - what half of CHA is provided | -//| B - array[0..N-1,0..M-1], right part | -//| M - right part size | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CDenseSolver::HPDMatrixCholeskySolveM(CMatrixComplex &cha, - const int n,const bool isupper, - CMatrixComplex &b,const int m, - int &info,CDenseSolverReport &rep, - CMatrixComplex &x) - { -//--- create variables - double sqrtscalea=0; - int i=0; - int j=0; - int j1=0; - int j2=0; -//--- create matrix - CMatrixComplex emptya; -//--- initialization - info=0; -//--- prepare: check inputs,allocate space... - if(n<=0 || m<=0) - { - info=-1; - return; - } -//--- 1. scale matrix,max(|U[i][j]|) -//--- 2. factorize scaled matrix -//--- 3. solve - sqrtscalea=0; - for(i=0;i<=n-1;i++) - { - //--- check - if(isupper) - { - j1=i; - j2=n-1; - } - else - { - j1=0; - j2=i; - } - //--- calculation - for(j=j1;j<=j2;j++) - { - sqrtscalea=MathMax(sqrtscalea,CMath::AbsComplex(cha[i][j])); - } - } -//--- check - if(sqrtscalea==0.0) - { - sqrtscalea=1; - } -//--- change values - sqrtscalea=1/sqrtscalea; -//--- function call - HPDMatrixCholeskySolveInternal(cha,sqrtscalea,n,isupper,emptya,false,b,m,info,rep,x); - } -//+------------------------------------------------------------------+ -//| Dense solver. Same as RMatrixLUSolve(), but for HPD matrices | -//| represented by their Cholesky decomposition. | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * O(N^2) complexity | -//| * condition number estimation | -//| * matrix is represented by its upper or lower triangle | -//| No iterative refinement is provided because such partial | -//| representation of matrix does not allow efficient calculation of | -//| extra-precise matrix-vector products for large matrices. Use | -//| RMatrixSolve or RMatrixMixedSolve if you need iterative | -//| refinement. | -//| INPUT PARAMETERS | -//| CHA - array[0..N-1,0..N-1], Cholesky decomposition, | -//| SPDMatrixCholesky result | -//| N - size of A | -//| IsUpper - what half of CHA is provided | -//| B - array[0..N-1], right part | -//| OUTPUT PARAMETERS | -//| Info - same as in RMatrixSolve | -//| Rep - same as in RMatrixSolve | -//| X - same as in RMatrixSolve | -//+------------------------------------------------------------------+ -static void CDenseSolver::HPDMatrixCholeskySolve(CMatrixComplex &cha, - const int n,const bool isupper, - al_complex &b[],int &info, - CDenseSolverReport &rep, - al_complex &x[]) - { -//--- create a variable - int i_=0; -//--- create matrix - CMatrixComplex bm; - CMatrixComplex xm; -//--- initialization - info=0; -//--- check - if(n<=0) - { - info=-1; - return; - } -//--- allocation - bm.Resize(n,1); -//--- filling - for(i_=0;i_<=n-1;i_++) - bm[i_].Set(0,b[i_]); -//--- function call - HPDMatrixCholeskySolveM(cha,n,isupper,bm,1,info,rep,xm); -//--- allocation - ArrayResizeAL(x,n); -//--- copy - for(i_=0;i_<=n-1;i_++) - x[i_]=xm[i_][0]; - } -//+------------------------------------------------------------------+ -//| Dense solver. | -//| This subroutine finds solution of the linear system A*X=B with | -//| non-square, possibly degenerate A. System is solved in the least | -//| squares sense, and general least squares solution X = X0 + CX*y | -//| which minimizes |A*X-B| is returned. If A is non-degenerate, | -//| solution in the usual sense is returned | -//| Algorithm features: | -//| * automatic detection of degenerate cases | -//| * iterative refinement | -//| * O(N^3) complexity | -//| INPUT PARAMETERS | -//| A - array[0..NRows-1,0..NCols-1], system matrix | -//| NRows - vertical size of A | -//| NCols - horizontal size of A | -//| B - array[0..NCols-1], right part | -//| Threshold- a number in [0,1]. Singular values beyond | -//| Threshold are considered zero. Set it to 0.0, | -//| if you don't understand what it means, so the | -//| solver will choose good value on its own. | -//| OUTPUT PARAMETERS | -//| Info - return code: | -//| * -4 SVD subroutine failed | -//| * -1 if NRows<=0 or NCols<=0 or Threshold<0 | -//| was passed | -//| * 1 if task is solved | -//| Rep - solver report, see below for more info | -//| X - array[0..N-1,0..M-1], it contains: | -//| * solution of A*X=B if A is non-singular | -//| (well-conditioned or ill-conditioned, but not | -//| very close to singular) | -//| * zeros, if A is singular or VERY close to | -//| singular (in this case Info=-3). | -//| SOLVER REPORT | -//| Subroutine sets following fields of the Rep structure: | -//| * R2 reciprocal of condition number: 1/cond(A), 2-norm. | -//| * N = NCols | -//| * K dim(Null(A)) | -//| * CX array[0..N-1,0..K-1], kernel of A. | -//| Columns of CX store such vectors that A*CX[i]=0. | -//+------------------------------------------------------------------+ -static void CDenseSolver::RMatrixSolveLS(CMatrixDouble &a,const int nrows, - const int ncols,double &b[], - double threshold,int &info, - CDenseSolverLSReport &rep, - double &x[]) - { -//--- create matrix - CMatrixDouble u; - CMatrixDouble vt; -//--- create arrays - double sv[]; - double rp[]; - double utb[]; - double sutb[]; - double tmp[]; - double ta[]; - double tx[]; - double buf[]; - double w[]; -//--- create variables - int i=0; - int j=0; - int nsv=0; - int kernelidx=0; - double v=0; - double verr=0; - bool svdfailed; - bool zeroa; - int rfs=0; - int nrfs=0; - bool terminatenexttime; - bool smallerr; - int i_=0; -//--- initialization - info=0; -//--- check - if((nrows<=0 || ncols<=0) || threshold<0.0) - { - info=-1; - return; - } -//--- check - if(threshold==0.0) - threshold=1000*CMath::m_machineepsilon; -//--- Factorize A first - svdfailed=!CSingValueDecompose::RMatrixSVD(a,nrows,ncols,1,2,2,sv,u,vt); -//--- check - if(sv[0]==0.0) - zeroa=true; - else - zeroa=false; -//--- check - if(svdfailed || zeroa) - { - //--- check - if(svdfailed) - info=-4; - else - info=1; - //--- allocation - ArrayResizeAL(x,ncols); - for(i=0;i<=ncols-1;i++) - x[i]=0; - //--- change values - rep.m_n=ncols; - rep.m_k=ncols; - rep.m_cx.Resize(ncols,ncols); - for(i=0;i<=ncols-1;i++) - { - for(j=0;j<=ncols-1;j++) - { - //--- check - if(i==j) - rep.m_cx[i].Set(j,1); - else - rep.m_cx[i].Set(j,0); - } - } - rep.m_r2=0; - //--- exit the function - return; - } - nsv=MathMin(ncols,nrows); -//--- check - if(nsv==ncols) - rep.m_r2=sv[nsv-1]/sv[0]; - else - rep.m_r2=0; -//--- change values - rep.m_n=ncols; - info=1; -//--- Iterative refinement of xc combined with solution: -//--- 1. xc=0 -//--- 2. calculate r=bc-A*xc using extra-precise dot product -//--- 3. solve A*y=r -//--- 4. update x:=x+r -//--- 5. goto 2 -//--- This cycle is executed until one of two things happens: -//--- 1. maximum number of iterations reached -//--- 2. last iteration decreased error to the lower limit - ArrayResizeAL(utb,nsv); - ArrayResizeAL(sutb,nsv); - ArrayResizeAL(x,ncols); - ArrayResizeAL(tmp,ncols); - ArrayResizeAL(ta,ncols+1); - ArrayResizeAL(tx,ncols+1); - ArrayResizeAL(buf,ncols+1); -//--- initialization - for(i=0;i<=ncols-1;i++) - x[i]=0; - kernelidx=nsv; - for(i=0;i<=nsv-1;i++) - { - //--- check - if(sv[i]<=threshold*sv[0]) - { - kernelidx=i; - break; - } - } -//--- change values - rep.m_k=ncols-kernelidx; - nrfs=CDenseSolverRFSMaxV2(ncols,rep.m_r2); - terminatenexttime=false; -//--- allocation - ArrayResizeAL(rp,nrows); - for(rfs=0;rfs<=nrfs;rfs++) - { - //--- check - if(terminatenexttime) - break; - //--- calculate right part - if(rfs==0) - { - for(i_=0;i_<=nrows-1;i_++) - rp[i_]=b[i_]; - } - else - { - smallerr=true; - for(i=0;i<=nrows-1;i++) - { - //--- copy - for(i_=0;i_<=ncols-1;i_++) - ta[i_]=a[i][i_]; - ta[ncols]=-1; - //--- copy - for(i_=0;i_<=ncols-1;i_++) - tx[i_]=x[i_]; - tx[ncols]=b[i]; - //--- function call - CXblas::XDot(ta,tx,ncols+1,buf,v,verr); - rp[i]=-v; - smallerr=smallerr && MathAbs(v)<4*verr; - } - //--- check - if(smallerr) - terminatenexttime=true; - } - //--- solve A*dx=rp - for(i=0;i<=ncols-1;i++) - tmp[i]=0; - for(i=0;i<=nsv-1;i++) - utb[i]=0; - //--- change values - for(i=0;i<=nrows-1;i++) - { - v=rp[i]; - for(i_=0;i_<=nsv-1;i_++) - utb[i_]=utb[i_]+v*u[i][i_]; - } - for(i=0;i<=nsv-1;i++) - { - //--- check - if(i0) - { - //--- allocation - rep.m_cx.Resize(ncols,rep.m_k); - for(i=0;i<=rep.m_k-1;i++) - { - for(i_=0;i_<=ncols-1;i_++) - rep.m_cx[i_].Set(i,vt[kernelidx+i][i_]); - } - } - } -//+------------------------------------------------------------------+ -//| Internal LU solver | -//+------------------------------------------------------------------+ -static void CDenseSolver::RMatrixLUSolveInternal(CMatrixDouble &lua,int &p[], - const double scalea,const int n, - CMatrixDouble &a,const bool havea, - CMatrixDouble &b,const int m, - int &info,CDenseSolverReport &rep, - CMatrixDouble &x) - { -//--- create variables - int i=0; - int j=0; - int k=0; - int rfs=0; - int nrfs=0; - double v=0; - double verr=0; - double mxb=0; - double scaleright=0; - bool smallerr; - bool terminatenexttime; - int i_=0; -//--- create arrays - double xc[]; - double y[]; - double bc[]; - double xa[]; - double xb[]; - double tx[]; -//--- initialization - info=0; -//--- check - if(!CAp::Assert(scalea>0.0)) - return; -//--- prepare: check inputs,allocate space... - if(n<=0 || m<=0) - { - info=-1; - return; - } - for(i=0;i<=n-1;i++) - { - //--- check - if(p[i]>n-1 || p[i]0.0)) - return; -//--- prepare: check inputs,allocate space... - if(n<=0 || m<=0) - { - info=-1; - return; - } -//--- allocation - x.Resize(n,m); - ArrayResizeAL(y,n); - ArrayResizeAL(xc,n); - ArrayResizeAL(bc,n); - ArrayResizeAL(tx,n+1); - ArrayResizeAL(xa,n+1); - ArrayResizeAL(xb,n+1); -//--- estimate condition number,test for near singularity - rep.m_r1=CRCond::SPDMatrixCholeskyRCond(cha,n,isupper); - rep.m_rinf=rep.m_r1; -//--- check - if(rep.m_r10.0)) - return; -//--- prepare: check inputs,allocate space... - if(n<=0 || m<=0) - { - info=-1; - return; - } - for(i=0;i<=n-1;i++) - { - //--- check - if(p[i]>n-1 || p[i]0.0)) - return; -//--- prepare: check inputs,allocate space... - if(n<=0 || m<=0) - { - info=-1; - return; - } -//--- allocation - x.Resize(n,m); - ArrayResizeAL(y,n); - ArrayResizeAL(xc,n); - ArrayResizeAL(bc,n); - ArrayResizeAL(tx,n+1); - ArrayResizeAL(xa,n+1); - ArrayResizeAL(xb,n+1); -//--- estimate condition number,test for near singularity - rep.m_r1=CRCond::HPDMatrixCholeskyRCond(cha,n,isupper); - rep.m_rinf=rep.m_r1; -//--- check - if(rep.m_r1=0;i--) - { - //--- calculation - for(i_=i+1;i_<=n-1;i_++) - tmp[i_]=lua[i][i_]*scalea; - v=0.0; - //--- change value - for(i_=i+1;i_<=n-1;i_++) - v+=tmp[i_]*xb[i_]; - //--- get result - xb[i]=(xb[i]-v)/(lua[i][i]*scalea); - } - } -//+------------------------------------------------------------------+ -//| Basic Cholesky solver for ScaleA*Cholesky(A)'*x = y. | -//| This subroutine assumes that: | -//| * A*ScaleA is well scaled | -//| * A is well-conditioned, so no zero divisions or overflow may | -//| occur | -//+------------------------------------------------------------------+ -static void CDenseSolver::SPDBasicCholeskySolve(CMatrixDouble &cha, - const double sqrtscalea, - const int n,const bool isupper, - double &xb[],double &tmp[]) - { -//--- create variables - int i=0; - double v=0; - int i_=0; -//--- A=L*L' or A=U'*U - if(isupper) - { - //--- Solve U'*y=b first. - for(i=0;i<=n-1;i++) - { - xb[i]=xb[i]/(sqrtscalea*cha[i][i]); - //--- check - if(i=0;i--) - { - //--- check - if(i0) - { - for(i_=0;i_<=i-1;i_++) - tmp[i_]=sqrtscalea*cha[i][i_]; - //--- change value - v=0.0; - for(i_=0;i_<=i-1;i_++) - v+=tmp[i_]*xb[i_]; - //--- shift - xb[i]=xb[i]-v; - } - xb[i]=xb[i]/(sqrtscalea*cha[i][i]); - } - //--- Solve L'*x=y then. - for(i=n-1;i>=0;i--) - { - xb[i]=xb[i]/(sqrtscalea*cha[i][i]); - //--- check - if(i>0) - { - v=xb[i]; - //--- calculation - for(i_=0;i_<=i-1;i_++) - tmp[i_]=sqrtscalea*cha[i][i_]; - for(i_=0;i_<=i-1;i_++) - xb[i_]=xb[i_]-v*tmp[i_]; - } - } - } - } -//+------------------------------------------------------------------+ -//| Basic LU solver for ScaleA*PLU*x = y. | -//| This subroutine assumes that: | -//| * L is well-scaled, and it is U which needs scaling by ScaleA. | -//| * A=PLU is well-conditioned, so no zero divisions or overflow may| -//| occur | -//+------------------------------------------------------------------+ -static void CDenseSolver::CBasicLUSolve(CMatrixComplex &lua,int &p[], - const double scalea,const int n, - al_complex &xb[],al_complex &tmp[]) - { -//--- create variables - int i=0; - al_complex v=0; - int i_=0; -//--- swap - for(i=0;i<=n-1;i++) - { - //--- check - if(p[i]!=i) - { - v=xb[i]; - xb[i]=xb[p[i]]; - xb[p[i]]=v; - } - } - for(i=1;i<=n-1;i++) - { - v=0.0; - //--- calculation - for(i_=0;i_<=i-1;i_++) - v+=lua[i][i_]*xb[i_]; - //--- shift - xb[i]=xb[i]-v; - } -//--- change values - xb[n-1]=xb[n-1]/(lua[n-1][n-1]*scalea); - for(i=n-2;i>=0;i--) - { - for(i_=i+1;i_<=n-1;i_++) - tmp[i_]=lua[i][i_]*scalea; - //--- calculation - v=0.0; - for(i_=i+1;i_<=n-1;i_++) - v+=tmp[i_]*xb[i_]; - //--- get result - xb[i]=(xb[i]-v)/(lua[i][i]*scalea); - } - } -//+------------------------------------------------------------------+ -//| Basic Cholesky solver for ScaleA*Cholesky(A)'*x = y. | -//| This subroutine assumes that: | -//| * A*ScaleA is well scaled | -//| * A is well-conditioned, so no zero divisions or overflow may | -//| occur | -//+------------------------------------------------------------------+ -static void CDenseSolver::HPDBasicCholeskySolve(CMatrixComplex &cha, - const double sqrtscalea, - const int n,const bool isupper, - al_complex &xb[],al_complex &tmp[]) - { -//--- create variables - int i=0; - al_complex v=0; - int i_=0; -//--- A=L*L' or A=U'*U - if(isupper) - { - //--- Solve U'*y=b first. - for(i=0;i<=n-1;i++) - { - xb[i]=xb[i]/(CMath::Conj(cha[i][i])*sqrtscalea); - //--- check - if(i=0;i--) - { - //--- check - if(i0) - { - for(i_=0;i_<=i-1;i_++) - tmp[i_]=cha[i][i_]*sqrtscalea; - //--- change value - v=0.0; - for(i_=0;i_<=i-1;i_++) - v+=tmp[i_]*xb[i_]; - //--- shift - xb[i]=xb[i]-v; - } - xb[i]=xb[i]/(cha[i][i]*sqrtscalea); - } - //--- Solve L'*x=y then. - for(i=n-1;i>=0;i--) - { - xb[i]=xb[i]/(CMath::Conj(cha[i][i])*sqrtscalea); - //--- check - if(i>0) - { - v=xb[i]; - //--- calculation - for(i_=0;i_<=i-1;i_++) - tmp[i_]=CMath::Conj(cha[i][i_])*sqrtscalea; - for(i_=0;i_<=i-1;i_++) - xb[i_]=xb[i_]-v*tmp[i_]; - } - } - } - } -//+------------------------------------------------------------------+ -//| Auxiliary class for CNlEq | -//+------------------------------------------------------------------+ -class CNlEqState - { -public: - //--- variables - int m_n; - int m_m; - double m_epsf; - int m_maxits; - bool m_xrep; - double m_stpmax; - double m_f; - bool m_needf; - bool m_needfij; - bool m_xupdated; - RCommState m_rstate; - int m_repiterationscount; - int m_repnfunc; - int m_repnjac; - int m_repterminationtype; - double m_fbase; - double m_fprev; - //--- arrays - double m_x[]; - double m_fi[]; - double m_xbase[]; - double m_candstep[]; - double m_rightpart[]; - double m_cgbuf[]; - //--- matrix - CMatrixDouble m_j; - //--- constructor, destructor - CNlEqState(void); - ~CNlEqState(void); - //--- copy - void Copy(CNlEqState &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CNlEqState::CNlEqState(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CNlEqState::~CNlEqState(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CNlEqState::Copy(CNlEqState &obj) - { -//--- copy variables - m_n=obj.m_n; - m_m=obj.m_m; - m_epsf=obj.m_epsf; - m_maxits=obj.m_maxits; - m_xrep=obj.m_xrep; - m_stpmax=obj.m_stpmax; - m_f=obj.m_f; - m_needf=obj.m_needf; - m_needfij=obj.m_needfij; - m_xupdated=obj.m_xupdated; - m_repiterationscount=obj.m_repiterationscount; - m_repnfunc=obj.m_repnfunc; - m_repnjac=obj.m_repnjac; - m_repterminationtype=obj.m_repterminationtype; - m_fbase=obj.m_fbase; - m_fprev=obj.m_fprev; - m_rstate.Copy(obj.m_rstate); -//--- copy arrays - ArrayCopy(m_x,obj.m_x); - ArrayCopy(m_fi,obj.m_fi); - ArrayCopy(m_xbase,obj.m_xbase); - ArrayCopy(m_candstep,obj.m_candstep); - ArrayCopy(m_rightpart,obj.m_rightpart); - ArrayCopy(m_cgbuf,obj.m_cgbuf); -//--- copy matrix - m_j=obj.m_j; - } -//+------------------------------------------------------------------+ -//| This class is a shell for class CNlEqState | -//+------------------------------------------------------------------+ -class CNlEqStateShell - { -private: - CNlEqState m_innerobj; -public: - //--- constructors, destructor - CNlEqStateShell(void); - CNlEqStateShell(CNlEqState &obj); - ~CNlEqStateShell(void); - //--- methods - bool GetNeedF(void); - void SetNeedF(const bool b); - bool GetNeedFIJ(void); - void SetNeedFIJ(const bool b); - bool GetXUpdated(void); - void SetXUpdated(const bool b); - double GetF(void); - void SetF(const double d); - CNlEqState *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CNlEqStateShell::CNlEqStateShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CNlEqStateShell::CNlEqStateShell(CNlEqState &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CNlEqStateShell::~CNlEqStateShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable needf | -//+------------------------------------------------------------------+ -bool CNlEqStateShell::GetNeedF(void) - { -//--- return result - return(m_innerobj.m_needf); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable needf | -//+------------------------------------------------------------------+ -void CNlEqStateShell::SetNeedF(const bool b) - { -//--- change value - m_innerobj.m_needf=b; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable needfij | -//+------------------------------------------------------------------+ -bool CNlEqStateShell::GetNeedFIJ(void) - { -//--- return result - return(m_innerobj.m_needfij); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable needfij | -//+------------------------------------------------------------------+ -void CNlEqStateShell::SetNeedFIJ(const bool b) - { -//--- change value - m_innerobj.m_needfij=b; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable xupdated | -//+------------------------------------------------------------------+ -bool CNlEqStateShell::GetXUpdated(void) - { -//--- return result - return(m_innerobj.m_xupdated); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable xupdated | -//+------------------------------------------------------------------+ -void CNlEqStateShell::SetXUpdated(const bool b) - { -//--- change value - m_innerobj.m_xupdated=b; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable f | -//+------------------------------------------------------------------+ -double CNlEqStateShell::GetF(void) - { -//--- return result - return(m_innerobj.m_f); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable f | -//+------------------------------------------------------------------+ -void CNlEqStateShell::SetF(const double d) - { -//--- change value - m_innerobj.m_f=d; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CNlEqState *CNlEqStateShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Auxiliary class for CNlEq | -//+------------------------------------------------------------------+ -class CNlEqReport - { -public: - //--- variables - int m_iterationscount; - int m_nfunc; - int m_njac; - int m_terminationtype; - //--- constructor, destructor - CNlEqReport(void); - ~CNlEqReport(void); - //--- copy - void Copy(CNlEqReport &obj); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CNlEqReport::CNlEqReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CNlEqReport::~CNlEqReport(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy | -//+------------------------------------------------------------------+ -void CNlEqReport::Copy(CNlEqReport &obj) - { -//--- copy variables - m_iterationscount=obj.m_iterationscount; - m_nfunc=obj.m_nfunc; - m_njac=obj.m_njac; - m_terminationtype=obj.m_terminationtype; - } -//+------------------------------------------------------------------+ -//| This class is a shell for class CNlEqReport | -//+------------------------------------------------------------------+ -class CNlEqReportShell - { -private: - CNlEqReport m_innerobj; -public: - //--- constructors, destructor - CNlEqReportShell(void); - CNlEqReportShell(CNlEqReport &obj); - ~CNlEqReportShell(void); - //--- methods - int GetIterationsCount(void); - void SetIterationsCount(const int i); - int GetNFunc(void); - void SetNFunc(const int i); - int GetNJac(void); - void SetNJac(const int i); - int GetTerminationType(void); - void SetTerminationType(const int i); - CNlEqReport *GetInnerObj(void); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CNlEqReportShell::CNlEqReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Copy constructor | -//+------------------------------------------------------------------+ -CNlEqReportShell::CNlEqReportShell(CNlEqReport &obj) - { -//--- copy - m_innerobj.Copy(obj); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CNlEqReportShell::~CNlEqReportShell(void) - { - - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable iterationscount | -//+------------------------------------------------------------------+ -int CNlEqReportShell::GetIterationsCount(void) - { -//--- return result - return(m_innerobj.m_iterationscount); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable iterationscount | -//+------------------------------------------------------------------+ -void CNlEqReportShell::SetIterationsCount(const int i) - { -//--- change value - m_innerobj.m_iterationscount=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable nfunc | -//+------------------------------------------------------------------+ -int CNlEqReportShell::GetNFunc(void) - { -//--- return result - return(m_innerobj.m_nfunc); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable nfunc | -//+------------------------------------------------------------------+ -void CNlEqReportShell::SetNFunc(const int i) - { -//--- change value - m_innerobj.m_nfunc=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable njac | -//+------------------------------------------------------------------+ -int CNlEqReportShell::GetNJac(void) - { -//--- return result - return(m_innerobj.m_njac); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable njac | -//+------------------------------------------------------------------+ -void CNlEqReportShell::SetNJac(const int i) - { -//--- change value - m_innerobj.m_njac=i; - } -//+------------------------------------------------------------------+ -//| Returns the value of the variable terminationtype | -//+------------------------------------------------------------------+ -int CNlEqReportShell::GetTerminationType(void) - { -//--- return result - return(m_innerobj.m_terminationtype); - } -//+------------------------------------------------------------------+ -//| Changing the value of the variable terminationtype | -//+------------------------------------------------------------------+ -void CNlEqReportShell::SetTerminationType(const int i) - { -//--- change value - m_innerobj.m_terminationtype=i; - } -//+------------------------------------------------------------------+ -//| Return object of class | -//+------------------------------------------------------------------+ -CNlEqReport *CNlEqReportShell::GetInnerObj(void) - { -//--- return result - return(GetPointer(m_innerobj)); - } -//+------------------------------------------------------------------+ -//| Solving systems of nonlinear equations | -//+------------------------------------------------------------------+ -class CNlEq - { -private: - //--- private methods - static void ClearRequestFields(CNlEqState &state); - static bool IncreaseLambda(double &lambdav,double &nu,const double lambdaup); - static void DecreaseLambda(double &lambdav,double &nu,const double lambdadown); - //--- auxiliary functions forNlEqiteration - static void Func_lbl_rcomm(CNlEqState &state,const int n,const int m,const int i,const bool b,const double lambdaup,const double lambdadown,const double lambdav,const double rho,const double mu,const double stepnorm); - static void Func_lbl_7(CNlEqState &state,const int n); - static bool Func_lbl_5(CNlEqState &state,double &lambdaup,double &lambdadown,double &lambdav,double &rho); - static bool Func_lbl_11(CNlEqState &state,const double stepnorm); - static int Func_lbl_10(CNlEqState &state,const int n,const int m,const int i,const bool b,const double lambdaup,const double lambdadown,const double lambdav,const double rho,const double mu,const double stepnorm); - static int Func_lbl_9(CNlEqState &state,int &n,int &m,int &i,bool &b,const double lambdaup,const double lambdadown,double &lambdav,const double rho,const double mu,double &stepnorm); -public: - //--- constant - static const int m_armijomaxfev; - //--- constructor, destructor - CNlEq(void); - ~CNlEq(void); - //--- public methods - static void NlEqCreateLM(const int n,const int m,double &x[],CNlEqState &state); - static void NlEqSetCond(CNlEqState &state,double epsf,const int maxits); - static void NlEqSetXRep(CNlEqState &state,const bool needxrep); - static void NlEqSetStpMax(CNlEqState &state,const double stpmax); - static void NlEqResults(CNlEqState &state,double &x[],CNlEqReport &rep); - static void NlEqResultsBuf(CNlEqState &state,double &x[],CNlEqReport &rep); - static void NlEqRestartFrom(CNlEqState &state,double &x[]); - static bool NlEqIteration(CNlEqState &state); - }; -//+------------------------------------------------------------------+ -//| Initialize constant | -//+------------------------------------------------------------------+ -const int CNlEq::m_armijomaxfev=20; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CNlEq::CNlEq(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CNlEq::~CNlEq(void) - { - - } -//+------------------------------------------------------------------+ -//| LEVENBERG-MARQUARDT-LIKE NONLINEAR SOLVER | -//| DESCRIPTION: | -//| This algorithm solves system of nonlinear equations | -//| F[0](x[0], ..., x[n-1]) = 0 | -//| F[1](x[0], ..., x[n-1]) = 0 | -//| ... | -//| F[M-1](x[0], ..., x[n-1]) = 0 | -//| with M/N do not necessarily coincide. Algorithm converges | -//| quadratically under following conditions: | -//| * the solution set XS is nonempty | -//| * for some xs in XS there exist such neighbourhood N(xs) | -//| that: | -//| * vector function F(x) and its Jacobian J(x) are | -//| continuously differentiable on N | -//| * ||F(x)|| provides local error bound on N, i.e. there | -//| exists such c1, that ||F(x)||>c1*distance(x,XS) | -//| Note that these conditions are much more weaker than usual | -//| non-singularity conditions. For example, algorithm will converge | -//| for any affine function F (whether its Jacobian singular or not).| -//| REQUIREMENTS: | -//| Algorithm will request following information during its | -//| operation: | -//| * function vector F[] and Jacobian matrix at given point X | -//| * value of merit function f(x)=F[0]^2(x)+...+F[M-1]^2(x) at given| -//| point X | -//| USAGE: | -//| 1. User initializes algorithm state with NLEQCreateLM() call | -//| 2. User tunes solver parameters with NLEQSetCond(), | -//| NLEQSetStpMax() and other functions | -//| 3. User calls NLEQSolve() function which takes algorithm state | -//| and pointers (delegates, etc.) to callback functions which | -//| calculate merit function value and Jacobian. | -//| 4. User calls NLEQResults() to get solution | -//| 5. Optionally, user may call NLEQRestartFrom() to solve another | -//| problem with same parameters (N/M) but another starting point | -//| and/or another function vector. NLEQRestartFrom() allows to | -//| reuse already initialized structure. | -//| INPUT PARAMETERS: | -//| N - space dimension, N>1: | -//| * if provided, only leading N elements of X are | -//| used | -//| * if not provided, determined automatically from | -//| size of X | -//| M - system size | -//| X - starting point | -//| OUTPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NOTES: | -//| 1. you may tune stopping conditions with NLEQSetCond() function | -//| 2. if target function contains exp() or other fast growing | -//| functions, and optimization algorithm makes too large steps | -//| which leads to overflow, use NLEQSetStpMax() function to bound| -//| algorithm's steps. | -//| 3. this algorithm is a slightly modified implementation of the | -//| method described in 'Levenberg-Marquardt method for | -//| constrained nonlinear equations with strong local convergence | -//| properties' by Christian Kanzow Nobuo Yamashita and Masao | -//| Fukushima and further developed in 'On the convergence of a | -//| New Levenberg-Marquardt Method' by Jin-yan Fan and Ya-Xiang | -//| Yuan. | -//+------------------------------------------------------------------+ -static void CNlEq::NlEqCreateLM(const int n,const int m,double &x[], - CNlEqState &state) - { -//--- check - if(!CAp::Assert(n>=1,__FUNCTION__+": N<1!")) - return; -//--- check - if(!CAp::Assert(m>=1,__FUNCTION__+": M<1!")) - return; -//--- check - if(!CAp::Assert(CAp::Len(x)>=n,__FUNCTION__+": Length(X)=0 | -//| The subroutine finishes its work if on k+1-th | -//| iteration the condition ||F||<=EpsF is satisfied | -//| MaxIts - maximum number of iterations. If MaxIts=0, the | -//| number of iterations is unlimited. | -//| Passing EpsF=0 and MaxIts=0 simultaneously will lead to | -//| automatic stopping criterion selection (small EpsF). | -//| NOTES: | -//+------------------------------------------------------------------+ -static void CNlEq::NlEqSetCond(CNlEqState &state,double epsf,const int maxits) - { -//--- check - if(!CAp::Assert(CMath::IsFinite(epsf),__FUNCTION__+": EpsF is not finite number!")) - return; -//--- check - if(!CAp::Assert(epsf>=0.0,__FUNCTION__+": negative EpsF!")) - return; -//--- check - if(!CAp::Assert(maxits>=0,__FUNCTION__+": negative MaxIts!")) - return; -//--- check - if(epsf==0.0 && maxits==0) - epsf=1.0E-6; -//--- change values - state.m_epsf=epsf; - state.m_maxits=maxits; - } -//+------------------------------------------------------------------+ -//| This function turns on/off reporting. | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| NeedXRep- whether iteration reports are needed or not | -//| If NeedXRep is True, algorithm will call rep() callback function | -//| if it is provided to NLEQSolve(). | -//+------------------------------------------------------------------+ -static void CNlEq::NlEqSetXRep(CNlEqState &state,const bool needxrep) - { -//--- change value - state.m_xrep=needxrep; - } -//+------------------------------------------------------------------+ -//| This function sets maximum step length | -//| INPUT PARAMETERS: | -//| State - structure which stores algorithm state | -//| StpMax - maximum step length, >=0. Set StpMax to 0.0, if | -//| you don't want to limit step length. | -//| Use this subroutine when target function contains exp() or other | -//| fast growing functions, and algorithm makes too large steps which| -//| lead to overflow. This function allows us to reject steps that | -//| are too large (and therefore expose us to the possible overflow) | -//| without actually calculating function value at the x+stp*d. | -//+------------------------------------------------------------------+ -static void CNlEq::NlEqSetStpMax(CNlEqState &state,const double stpmax) - { -//--- check - if(!CAp::Assert(CMath::IsFinite(stpmax),__FUNCTION__+": StpMax is not finite!")) - return; -//--- check - if(!CAp::Assert(stpmax>=0.0,__FUNCTION__+": StpMax<0!")) - return; -//--- change value - state.m_stpmax=stpmax; - } -//+------------------------------------------------------------------+ -//| NLEQ solver results | -//| INPUT PARAMETERS: | -//| State - algorithm state. | -//| OUTPUT PARAMETERS: | -//| X - array[0..N-1], solution | -//| Rep - optimization report: | -//| * Rep.TerminationType completetion code: | -//| * -4 ERROR: algorithm has converged to the| -//| stationary point Xf which is local | -//| minimum of f=F[0]^2+...+F[m-1]^2, | -//| but is not solution of nonlinear | -//| system. | -//| * 1 sqrt(f)<=EpsF. | -//| * 5 MaxIts steps was taken | -//| * 7 stopping conditions are too | -//| stringent, further improvement is | -//| impossible | -//| * Rep.IterationsCount contains iterations count | -//| * NFEV countains number of function calculations | -//| * ActiveConstraints contains number of active | -//| constraints | -//+------------------------------------------------------------------+ -static void CNlEq::NlEqResults(CNlEqState &state,double &x[],CNlEqReport &rep) - { - ArrayResizeAL(x,0); -//--- function call - NlEqResultsBuf(state,x,rep); - } -//+------------------------------------------------------------------+ -//| NLEQ solver results | -//| Buffered implementation of NLEQResults(), which uses | -//| pre-allocated buffer to store X[]. If buffer size is too small, | -//| it resizes buffer. It is intended to be used in the inner cycles | -//| of performance critical algorithms where array reallocation | -//| penalty is too large to be ignored. | -//+------------------------------------------------------------------+ -static void CNlEq::NlEqResultsBuf(CNlEqState &state,double &x[],CNlEqReport &rep) - { -//--- create a variable - int i_=0; -//--- check - if(CAp::Len(x)=state.m_n,__FUNCTION__+": Length(X)lnmax) - return(false); -//--- check - if(lnnu+MathLog(2)>lnmax) - return(false); -//--- change values - lambdav=lambdav*lambdaup*nu; - nu=nu*2; -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Decreases lambda, but leaves it unchanged when there is danger of| -//| underflow. | -//+------------------------------------------------------------------+ -static void CNlEq::DecreaseLambda(double &lambdav,double &nu,const double lambdadown) - { -//--- initialization - nu=1; -//--- check - if(MathLog(lambdav)+MathLog(lambdadown)=0) - { - //--- initialization - n=state.m_rstate.ia[0]; - m=state.m_rstate.ia[1]; - i=state.m_rstate.ia[2]; - b=state.m_rstate.ba[0]; - lambdaup=state.m_rstate.ra[0]; - lambdadown=state.m_rstate.ra[1]; - lambdav=state.m_rstate.ra[2]; - rho=state.m_rstate.ra[3]; - mu=state.m_rstate.ra[4]; - stepnorm=state.m_rstate.ra[5]; - } - else - { - //--- initialization - n=-983; - m=-989; - i=-834; - b=false; - lambdaup=-287; - lambdadown=364; - lambdav=214; - rho=-338; - mu=-686; - stepnorm=912; - } -//--- check - if(state.m_rstate.stage==0) - { - //--- change values - state.m_needf=false; - state.m_repnfunc=state.m_repnfunc+1; - //--- copy - for(i_=0;i_<=n-1;i_++) - state.m_xbase[i_]=state.m_x[i_]; - //--- change values - state.m_fbase=state.m_f; - state.m_fprev=CMath::m_maxrealnumber; - //--- check - if(!state.m_xrep) - { - //--- check - if(!Func_lbl_5(state,lambdaup,lambdadown,lambdav,rho)) - return(false); - //--- function call - Func_lbl_7(state,n); - //--- Saving state - Func_lbl_rcomm(state,n,m,i,b,lambdaup,lambdadown,lambdav,rho,mu,stepnorm); - //--- return result - return(true); - } - //--- progress report - ClearRequestFields(state); - state.m_xupdated=true; - state.m_rstate.stage=1; - //--- Saving state - Func_lbl_rcomm(state,n,m,i,b,lambdaup,lambdadown,lambdav,rho,mu,stepnorm); - //--- return result - return(true); - } -//--- check - if(state.m_rstate.stage==1) - { - //--- change value - state.m_xupdated=false; - //--- check - if(!Func_lbl_5(state,lambdaup,lambdadown,lambdav,rho)) - return(false); - //--- function call - Func_lbl_7(state,n); - //--- Saving state - Func_lbl_rcomm(state,n,m,i,b,lambdaup,lambdadown,lambdav,rho,mu,stepnorm); - //--- return result - return(true); - } -//--- check - if(state.m_rstate.stage==2) - { - //--- change values - state.m_needfij=false; - state.m_repnfunc=state.m_repnfunc+1; - state.m_repnjac=state.m_repnjac+1; - //--- function call - CAblas::RMatrixMVect(n,m,state.m_j,0,0,1,state.m_fi,0,state.m_rightpart,0); - for(i_=0;i_<=n-1;i_++) - state.m_rightpart[i_]=-1*state.m_rightpart[i_]; - //--- Inner cycle: find good lambda - temp=Func_lbl_9(state,n,m,i,b,lambdaup,lambdadown,lambdav,rho,mu,stepnorm); - //--- check - if(temp==-1) - return(false); - //--- check - if(temp==1) - return(true); - //--- Saving state - Func_lbl_rcomm(state,n,m,i,b,lambdaup,lambdadown,lambdav,rho,mu,stepnorm); - //--- return result - return(true); - } -//--- check - if(state.m_rstate.stage==3) - { - //--- change values - state.m_needf=false; - state.m_repnfunc=state.m_repnfunc+1; - //--- check - if(state.m_f=state.m_maxits && state.m_maxits>0) - state.m_repterminationtype=5; -//--- check - if(state.m_repterminationtype!=0) - return(false); -//--- return result - return(true); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for NlEqiteration. Is a product to get rid of | -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static int CNlEq::Func_lbl_10(CNlEqState &state,const int n,const int m, - const int i,const bool b,const double lambdaup, - const double lambdadown,const double lambdav, - const double rho,const double mu, - const double stepnorm) - { -//--- Accept step: -//--- * new position -//--- * new function value - state.m_fbase=state.m_f; - for(int i_=0;i_<=n-1;i_++) - state.m_xbase[i_]=state.m_xbase[i_]+stepnorm*state.m_candstep[i_]; - state.m_repiterationscount=state.m_repiterationscount+1; -//--- Report new iteration - if(!state.m_xrep) - { - //--- check - if(!Func_lbl_11(state,stepnorm)) - return(-1); - //--- Now,iteration is finally over - Func_lbl_7(state,n); - //--- Saving state - Func_lbl_rcomm(state,n,m,i,b,lambdaup,lambdadown,lambdav,rho,mu,stepnorm); - //--- return result - return(1); - } -//--- function call - ClearRequestFields(state); -//--- change values - state.m_xupdated=true; - state.m_f=state.m_fbase; -//--- copy - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xbase[i_]; - state.m_rstate.stage=4; -//--- return result - return(0); - } -//+------------------------------------------------------------------+ -//| Auxiliary function for NlEqiteration. Is a product to get rid of | -//| the operator unconditional jump goto. | -//+------------------------------------------------------------------+ -static int CNlEq::Func_lbl_9(CNlEqState &state,int &n,int &m,int &i,bool &b, - const double lambdaup,const double lambdadown, - double &lambdav,const double rho,const double mu, - double &stepnorm) - { -//--- Solve (J^T*J + (Lambda+Mu)*I)*y=J^T*F -//--- to get step d=-y where: -//--- * Mu=||F|| - is damping parameter for nonlinear system -//--- * Lambda - is additional Levenberg-Marquardt parameter -//--- for better convergence when far away from minimum - for(i=0;i<=n-1;i++) - state.m_candstep[i]=0; -//--- function call - CFbls::FblsSolveCGx(state.m_j,m,n,lambdav,state.m_rightpart,state.m_candstep,state.m_cgbuf); -//--- Normalize step (it must be no more than StpMax) - stepnorm=0; - for(i=0;i<=n-1;i++) - { - //--- check - if(state.m_candstep[i]!=0.0) - { - stepnorm=1; - break; - } - } - CLinMin::LinMinNormalized(state.m_candstep,stepnorm,n); -//--- check - if(state.m_stpmax!=0.0) - stepnorm=MathMin(stepnorm,state.m_stpmax); -//--- Test new step - is it good enough? -//--- * if not,Lambda is increased and we try again. -//--- * if step is good,we decrease Lambda and move on. -//--- We can break this cycle on two occasions: -//--- * step is so small that x+step==x (in floating point arithmetics) -//--- * lambda is so large - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xbase[i_]; - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_x[i_]+stepnorm*state.m_candstep[i_]; - b=true; - for(i=0;i<=n-1;i++) - { - //--- check - if(state.m_x[i]!=state.m_xbase[i]) - { - b=false; - break; - } - } -//--- check - if(b) - { - //--- Step is too small,force zero step and break - stepnorm=0; - for(int i_=0;i_<=n-1;i_++) - state.m_x[i_]=state.m_xbase[i_]; - state.m_f=state.m_fbase; - //--- function call - int temp=Func_lbl_10(state,n,m,i,b,lambdaup,lambdadown,lambdav,rho,mu,stepnorm); - //--- check - if(temp!=0) - return(temp); - //--- Saving state - Func_lbl_rcomm(state,n,m,i,b,lambdaup,lambdadown,lambdav,rho,mu,stepnorm); - //--- return result - return(1); - } -//--- function call - ClearRequestFields(state); -//--- change values - state.m_needf=true; - state.m_rstate.stage=3; -//--- return result - return(0); - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Alglib/specialfunctions.mqh b/Include/Math/Alglib/specialfunctions.mqh deleted file mode 100644 index 53e400a..0000000 --- a/Include/Math/Alglib/specialfunctions.mqh +++ /dev/null @@ -1,6599 +0,0 @@ -//+------------------------------------------------------------------+ -//| specialfunctions.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 "ap.mqh" -#include "alglibinternal.mqh" -//+------------------------------------------------------------------+ -//| Gamma function | -//+------------------------------------------------------------------+ -class CGammaFunc - { -private: - static double GammaStirlFunc(double x); - -public: - CGammaFunc(void); - ~CGammaFunc(void); - static double GammaFunc(double x); - static double LnGamma(double x,double &sgngam); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CGammaFunc::CGammaFunc(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CGammaFunc::~CGammaFunc(void) - { - - } -//+------------------------------------------------------------------+ -//| Stirling function | -//+------------------------------------------------------------------+ -static double CGammaFunc::GammaStirlFunc(double x) - { -//--- create variables - double y; - double w; - double v; - double stir; -//--- initialization - w=1/x; - stir=7.87311395793093628397E-4; - stir=-2.29549961613378126380E-4+w*stir; - stir=-2.68132617805781232825E-3+w*stir; - stir=3.47222221605458667310E-3+w*stir; - stir=8.33333333333482257126E-2+w*stir; - w=1+w*stir; - y=MathExp(x); -//--- check - if(x>143.01608) - { - v=MathPow(x,0.5*x-0.25); - y=v*(v/y); - } - else - y=MathPow(x,x-0.5)/y; -//--- return result - return(2.50662827463100050242*y*w); - } -//+------------------------------------------------------------------+ -//| Gamma function | -//| Input parameters: | -//| X - argument | -//| Domain: | -//| 0 < X < 171.6 | -//| -170 < X < 0, X is not an integer. | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE -170,-33 20000 2.3e-15 3.3e-16 | -//| IEEE -33, 33 20000 9.4e-16 2.2e-16 | -//| IEEE 33, 171.6 20000 2.3e-15 3.2e-16 | -//+------------------------------------------------------------------+ -static double CGammaFunc::GammaFunc(double x) - { -//--- create variables - double p; - double pp; - double q=MathAbs(x); - double qq; - double z; - int i; - double sgngam=1; -//--- check - if(q>33.0) - { - //--- check - if(x<0.0) - { - p=(int)MathFloor(q); - i=(int)MathRound(p); - //--- check - if(i%2==0) - sgngam=-1; - z=q-p; - //--- check - if(z>0.5) - { - p++; - z=q-p; - } - //--- calculation z - z=q*MathSin(M_PI*z); - z=MathAbs(z); - z=M_PI/(z*GammaStirlFunc(q)); - } - else - z=GammaStirlFunc(x); - //--- return result - return(sgngam*z); - } -//--- q<=33 - z=1; - while(x>=3) - { - x--; - z*=x; - } -//--- x<0 - while(x<0) - { - //--- check - if(x>-0.000000001) - return(z/((1+0.5772156649015329*x)*x)); - z/=x; - x++; - } -//--- 00.5) - { - p++; - z=p-q; - } - z=q*MathSin(M_PI*z); - //--- return result - return(logpi-MathLog(z)-w); - } -//--- x>=-34 - if(x<13) - { - z=1; - p=0; - u=x; - //--- cycle - while(u>=3) - { - p--; - u=x+p; - z*=u; - } - //--- cycle - while(u<2) - { - z/=u; - p++; - u=x+p; - } - //--- check - if(z<0) - { - sgngam=-1; - z=-z; - } - else - sgngam=1; - //--- check - if(u==2) - return(MathLog(z)); - //--- calculation - p-=2; - x+=p; - b=-1378.25152569120859100; - b=-38801.6315134637840924+x*b; - b=-331612.992738871184744+x*b; - b=-1162370.97492762307383+x*b; - b=-1721737.00820839662146+x*b; - b=-853555.664245765465627+x*b; - c=1; - c=-351.815701436523470549+x*c; - c=-17064.2106651881159223+x*c; - c=-220528.590553854454839+x*c; - c=-1139334.44367982507207+x*c; - c=-2532523.07177582951285+x*c; - c=-2018891.41433532773231+x*c; - p=x*b/c; - //--- return result - return(MathLog(z)+p); - } -//--- x>=13 - q=(x-0.5)*MathLog(x)-x+ls2pi; -//--- check - if(x>100000000) - return(q); -//--- change value - p=1/(x*x); -//--- check - if(x>=1000.0) - q+=((7.9365079365079365079365*0.0001*p-2.7777777777777777777778*0.001)*p+0.0833333333333333333333)/x; - else - { - a=8.11614167470508450300*0.0001; - a=-(5.95061904284301438324*0.0001)+p*a; - a=7.93650340457716943945*0.0001+p*a; - a=-(2.77777777730099687205*0.001)+p*a; - a=8.33333333333331927722*0.01+p*a; - q+=a/x; - } -//--- return result - return(q); - } -//+------------------------------------------------------------------+ -//| Normal distribution | -//+------------------------------------------------------------------+ -class CNormalDistr - { -public: - //--- constructor, destructor - CNormalDistr(void); - ~CNormalDistr(void); - //--- methods - static double ErrorFunction(double x); - static double ErrorFunctionC(double x); - static double NormalDistribution(const double x); - static double InvErF(const double e); - static double InvNormalDistribution(double y0); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CNormalDistr::CNormalDistr(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CNormalDistr::~CNormalDistr(void) - { - - } -//+------------------------------------------------------------------+ -//| Error function | -//| The integral is | -//| x | -//| - | -//| 2 | | 2 | -//| erf(x) = -------- | exp( - t ) dt. | -//| sqrt(pi) | | | -//| - | -//| 0 | -//| For 0 <= |x| < 1, erf(x) = x * P4(x**2)/Q5(x**2); otherwise | -//| erf(x) = 1 - erfc(x). | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0,1 30000 3.7e-16 1.0e-16 | -//+------------------------------------------------------------------+ -static double CNormalDistr::ErrorFunction(double x) - { -//--- create variables - double xsq=0; - double s=0; - double p=0; - double q=0; -//--- initialization - s=MathSign(x); -//--- change value - x=MathAbs(x); -//--- check - if(x<0.5) - { - //--- calculation - xsq=x*x; - p=0.007547728033418631287834; - p=0.288805137207594084924010+xsq*p; - p=14.3383842191748205576712+xsq*p; - p=38.0140318123903008244444+xsq*p; - p=3017.82788536507577809226+xsq*p; - p=7404.07142710151470082064+xsq*p; - p=80437.3630960840172832162+xsq*p; - q=0.0; - q=1.00000000000000000000000+xsq*q; - q=38.0190713951939403753468+xsq*q; - q=658.070155459240506326937+xsq*q; - q=6379.60017324428279487120+xsq*q; - q=34216.5257924628539769006+xsq*q; - q=80437.3630960840172826266+xsq*q; - //--- return result - return(s*1.1283791670955125738961589031*x*p/q); - } -//--- check - if(x>=10) - return(s); -//--- return result - return(s*(1-ErrorFunctionC(x))); - } -//+------------------------------------------------------------------+ -//| Complementary error function | -//| 1 - erf(x) = | -//| inf. | -//| - | -//| 2 | | 2 | -//| erfc(x) = -------- | exp( - t ) dt | -//| sqrt(pi) | | | -//| - | -//| x | -//| For small x, erfc(x) = 1 - erf(x); otherwise rational | -//| approximations are computed. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0,26.6417 30000 5.7e-14 1.5e-14 | -//+------------------------------------------------------------------+ -static double CNormalDistr::ErrorFunctionC(double x) - { -//--- create variables - double p=0; - double q=0; -//--- check - if(x<0.0) - return(2-ErrorFunctionC(-x)); -//--- check - if(x<0.5) - return(1.0-ErrorFunction(x)); -//--- check - if(x>=10) - return(0); -//--- calculation - p=0.0; - p=0.5641877825507397413087057563+x*p; - p=9.675807882987265400604202961+x*p; - p=77.08161730368428609781633646+x*p; - p=368.5196154710010637133875746+x*p; - p=1143.262070703886173606073338+x*p; - p=2320.439590251635247384768711+x*p; - p=2898.0293292167655611275846+x*p; - p=1826.3348842295112592168999+x*p; - q=1.0; - q=17.14980943627607849376131193+x*q; - q=137.1255960500622202878443578+x*q; - q=661.7361207107653469211984771+x*q; - q=2094.384367789539593790281779+x*q; - q=4429.612803883682726711528526+x*q; - q=6089.5424232724435504633068+x*q; - q=4958.82756472114071495438422+x*q; - q=1826.3348842295112595576438+x*q; -//--- return result - return(MathExp(-CMath::Sqr(x))*p/q); - } -//+------------------------------------------------------------------+ -//| Normal distribution function | -//| Returns the area under the Gaussian probability density | -//| function, integrated from minus infinity to x: | -//| x | -//| - | -//| 1 | | 2 | -//| ndtr(x) = --------- | exp( - t /2 ) dt | -//| sqrt(2pi) | | | -//| - | -//| -inf. | -//| = ( 1 + erf(z) ) / 2 | -//| = erfc(z) / 2 | -//| where z = x/sqrt(2). Computation is via the functions | -//| erf and erfc. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE -13,0 30000 3.4e-14 6.7e-15 | -//+------------------------------------------------------------------+ -static double CNormalDistr::NormalDistribution(const double x) - { -//--- return result - return(0.5*(ErrorFunction(x/1.41421356237309504880)+1)); - } -//+------------------------------------------------------------------+ -//| Inverse of the error function | -//+------------------------------------------------------------------+ -static double CNormalDistr::InvErF(const double e) - { -//--- return result - return(InvNormalDistribution(0.5*(e+1))/MathSqrt(2)); - } -//+------------------------------------------------------------------+ -//| Inverse of Normal distribution function | -//| Returns the argument, x, for which the area under the | -//| Gaussian probability density function (integrated from | -//| minus infinity to x) is equal to y. | -//| For small arguments 0 < y < exp(-2), the program computes | -//| z = sqrt( -2.0 * log(y) ); then the approximation is | -//| x = z - log(z)/z - (1/z) P(1/z) / Q(1/z). | -//| There are two rational functions P/Q, one for 0 < y < exp(-32) | -//| and the other for y up to exp(-2). For larger arguments, | -//| w = y - 0.5, and x/sqrt(2pi) = w + w**3 R(w**2)/S(w**2)). | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0.125, 1 20000 7.2e-16 1.3e-16 | -//| IEEE 3e-308, 0.135 50000 4.6e-16 9.8e-17 | -//+------------------------------------------------------------------+ -static double CNormalDistr::InvNormalDistribution(double y0) - { -//--- check - if(y0<=0) - return(-CMath::m_maxrealnumber); -//--- check - if(y0>=1) - return(CMath::m_maxrealnumber); -//--- create variables - double expm2=0.13533528323661269189; - double s2pi=2.50662827463100050242; - double x; - double y=y0; - double z; - double y2; - double x0; - double x1; - int code=1; - double p0; - double q0; - double p1; - double q1; - double p2; - double q2; -//--- check - if(y>1.0-expm2) - { - y=1.0-y; - code=0; - } -//--- check - if(y>expm2) - { - y-=0.5; - y2=y*y; - p0=-59.9633501014107895267; - p0=98.0010754185999661536+y2*p0; - p0=-56.6762857469070293439+y2*p0; - p0=13.9312609387279679503+y2*p0; - p0=-1.23916583867381258016+y2*p0; - q0=1; - q0=1.95448858338141759834+y2*q0; - q0=4.67627912898881538453+y2*q0; - q0=86.3602421390890590575+y2*q0; - q0=-225.462687854119370527+y2*q0; - q0=200.260212380060660359+y2*q0; - q0=-82.0372256168333339912+y2*q0; - q0=15.9056225126211695515+y2*q0; - q0=-1.18331621121330003142+y2*q0; - x=y+y*y2*p0/q0; - x*=s2pi; - //--- return result - return(x); - } -//--- calculation - x=MathSqrt(-(2.0*MathLog(y))); - x0=x-MathLog(x)/x; - z=1.0/x; -//--- check - if(x<8.0) - { - p1=4.05544892305962419923; - p1=31.5251094599893866154+z*p1; - p1=57.1628192246421288162+z*p1; - p1=44.0805073893200834700+z*p1; - p1=14.6849561928858024014+z*p1; - p1=2.18663306850790267539+z*p1; - p1=-(1.40256079171354495875*0.1)+z*p1; - p1=-(3.50424626827848203418*0.01)+z*p1; - p1=-(8.57456785154685413611*0.0001)+z*p1; - q1=1; - q1=15.7799883256466749731+z*q1; - q1=45.3907635128879210584+z*q1; - q1=41.3172038254672030440+z*q1; - q1=15.0425385692907503408+z*q1; - q1=2.50464946208309415979+z*q1; - q1=-(1.42182922854787788574*0.1)+z*q1; - q1=-(3.80806407691578277194*0.01)+z*q1; - q1=-(9.33259480895457427372*0.0001)+z*q1; - x1=z*p1/q1; - } - else - { - p2=3.23774891776946035970; - p2=6.91522889068984211695+z*p2; - p2=3.93881025292474443415+z*p2; - p2=1.33303460815807542389+z*p2; - p2=2.01485389549179081538*0.1+z*p2; - p2=1.23716634817820021358*0.01+z*p2; - p2=3.01581553508235416007*0.0001+z*p2; - p2=2.65806974686737550832*0.000001+z*p2; - p2=6.23974539184983293730*0.000000001+z*p2; - q2=1; - q2=6.02427039364742014255+z*q2; - q2=3.67983563856160859403+z*q2; - q2=1.37702099489081330271+z*q2; - q2=2.16236993594496635890*0.1+z*q2; - q2=1.34204006088543189037*0.01+z*q2; - q2=3.28014464682127739104*0.0001+z*q2; - q2=2.89247864745380683936*0.000001+z*q2; - q2=6.79019408009981274425*0.000000001+z*q2; - x1=z*p2/q2; - } - x=x0-x1; -//--- check - if(code!=0) - x=-x; -//--- return result - return(x); - } -//+------------------------------------------------------------------+ -//| Incomplete gamma function | -//+------------------------------------------------------------------+ -class CIncGammaF - { -public: - //--- constructor, destructor - CIncGammaF(void); - ~CIncGammaF(void); - //--- methods - static double IncompleteGamma(const double a,const double x); - static double IncompleteGammaC(const double a,const double x); - static double InvIncompleteGammaC(const double a,const double y0); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CIncGammaF::CIncGammaF(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CIncGammaF::~CIncGammaF(void) - { - - } -//+------------------------------------------------------------------+ -//| Incomplete gamma integral | -//| The function is defined by | -//| x | -//| - | -//| 1 | | -t a-1 | -//| igam(a,x) = ----- | e t dt. | -//| - | | | -//| | (a) - | -//| 0 | -//| In this implementation both arguments must be positive. | -//| The integral is evaluated by either a power series or | -//| continued fraction expansion, depending on the relative | -//| values of a and x. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0,30 200000 3.6e-14 2.9e-15 | -//| IEEE 0,100 300000 9.9e-14 1.5e-14 | -//+------------------------------------------------------------------+ -static double CIncGammaF::IncompleteGamma(const double a,const double x) - { -//--- check - if(x<=0 || a<=0) - return(0); -//--- check - if(x>1 && x>a) - return(1-IncompleteGammaC(a,x)); -//--- create variables - double igammaepsilon=0.000000000000001; - double ans; - double ax; - double c; - double r; - double tmp=0; -//--- change value - ax=a*MathLog(x)-x-CGammaFunc::LnGamma(a,tmp); -//--- check - if(ax<-709.78271289338399) - return(0); -//--- change values - ax=MathExp(ax); - r=a; - c=1; - ans=1; -//--- cycle - do - { - r++; - c*=x/r; - ans+=c; - } - while(c/ans>igammaepsilon); -//--- return result - return(ans*ax/a); - } -//+------------------------------------------------------------------+ -//| Complemented incomplete gamma integral | -//| The function is defined by | -//| igamc(a,x) = 1 - igam(a,x) | -//| inf. | -//| - | -//| 1 | | -t a-1 | -//| = ----- | e t dt. | -//| - | | | -//| | (a) - | -//| x | -//| In this implementation both arguments must be positive. | -//| The integral is evaluated by either a power series or | -//| continued fraction expansion, depending on the relative | -//| values of a and x. | -//| ACCURACY: | -//| Tested at random a, x. | -//| a x Relative error: | -//| arithmetic domain domain # trials peak rms | -//| IEEE 0.5,100 0,100 200000 1.9e-14 1.7e-15| -//| IEEE 0.01,0.5 0,100 200000 1.4e-13 1.6e-15| -//+------------------------------------------------------------------+ -static double CIncGammaF::IncompleteGammaC(const double a,const double x) - { -//--- check - if(x<=0 || a<=0) - return(1); -//--- check - if(x<1 || xigammabignumber) - { - pkm2=pkm2*igammabignumberinv; - pkm1=pkm1*igammabignumberinv; - qkm2=qkm2*igammabignumberinv; - qkm1=qkm1*igammabignumberinv; - } - } - while(t>igammaepsilon); -//--- return result - return(ans*ax); - } -//+------------------------------------------------------------------+ -//| Inverse of complemented imcomplete gamma integral | -//| Given p, the function finds x such that | -//| igamc( a, x ) = p. | -//| Starting with the approximate value | -//| 3 | -//| x = a t | -//| where | -//| t = 1 - d - ndtri(p) sqrt(d) | -//| and | -//| d = 1/9a, | -//| the routine performs up to 10 Newton iterations to find the | -//| root of igamc(a,x) - p = 0. | -//| ACCURACY: | -//| Tested at random a, p in the intervals indicated. | -//| a p Relative error: | -//| arithmetic domain domain # trials peak rms | -//| IEEE 0.5,100 0,0.5 100000 1.0e-14 1.7e-15| -//| IEEE 0.01,0.5 0,0.5 100000 9.0e-14 3.4e-15| -//| IEEE 0.5,10000 0,0.5 20000 2.3e-13 3.8e-14| -//+------------------------------------------------------------------+ -static double CIncGammaF::InvIncompleteGammaC(const double a,const double y0) - { -//--- create variables - double igammaepsilon=0; - double iinvgammabignumber=0; - double x0=0; - double x1=0; - double x=0; - double yl=0; - double yh=0; - double y=0; - double d=0; - double lgm=0; - double dithresh=0; - int i=0; - int dir=0; - double tmp=0; -//--- initialization - igammaepsilon=0.000000000000001; - iinvgammabignumber=4503599627370496.0; - x0=iinvgammabignumber; - yl=0; - x1=0; - yh=1; - dithresh=5*igammaepsilon; - d=1/(9*a); - y=1-d-CNormalDistr::InvNormalDistribution(y0)*MathSqrt(d); - x=a*y*y*y; - lgm=CGammaFunc::LnGamma(a,tmp); - i=0; -//--- cycle - while(i<10) - { - //--- check - if(x>x0 || xyh) - { - d=0.0625; - break; - } - //--- check - if(y=y0) - { - x1=x; - yh=y; - //--- check - if(dir<0) - { - dir=0; - d=0.5; - } - else - { - //--- check - if(dir>1) - d=0.5*d+0.5; - else - d=(y0-yl)/(yh-yl); - } - dir=dir+1; - } - else - { - x0=x; - yl=y; - //--- check - if(dir>0) - { - dir=0; - d=0.5; - } - else - { - //--- check - if(dir<-1) - d=0.5*d; - else - d=(y0-yl)/(yh-yl); - } - dir=dir-1; - } - i=i+1; - } -//--- return result - return(x); - } -//+------------------------------------------------------------------+ -//| Airy function | -//+------------------------------------------------------------------+ -class CAiryF - { -public: - //--- constructor, destructor - CAiryF(void); - ~CAiryF(void); - //--- method - static void Airy(const double x,double &ai,double &aip,double &bi,double &bip); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CAiryF::CAiryF(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CAiryF::~CAiryF(void) - { - - } -//+------------------------------------------------------------------+ -//| Airy function | -//| Solution of the differential equation | -//| y"(x) = xy. | -//| The function returns the two independent solutions Ai, Bi | -//| and their first derivatives Ai'(x), Bi'(x). | -//| Evaluation is by power series summation for small x, | -//| by rational minimax approximations for large x. | -//| ACCURACY: | -//| Error criterion is absolute when function <= 1, relative | -//| when function > 1, except * denotes relative error criterion. | -//| For large negative x, the absolute error increases as x^1.5. | -//| For large positive x, the relative error increases as x^1.5. | -//| Arithmetic domain function # trials peak rms | -//| IEEE -10, 0 Ai 10000 1.6e-15 2.7e-16 | -//| IEEE 0, 10 Ai 10000 2.3e-14* 1.8e-15*| -//| IEEE -10, 0 Ai' 10000 4.6e-15 7.6e-16 | -//| IEEE 0, 10 Ai' 10000 1.8e-14* 1.5e-15*| -//| IEEE -10, 10 Bi 30000 4.2e-15 5.3e-16 | -//| IEEE -10, 10 Bi' 30000 4.9e-15 7.3e-16 | -//+------------------------------------------------------------------+ -static void CAiryF::Airy(const double x,double &ai,double &aip,double &bi, - double &bip) - { -//--- create variables - double z=0; - double zz=0; - double t=0; - double f=0; - double g=0; - double uf=0; - double ug=0; - double k=0; - double zeta=0; - double theta=0; - int domflg=0; - double c1=0; - double c2=0; - double sqrt3=0; - double sqpii=0; - double afn=0; - double afd=0; - double agn=0; - double agd=0; - double apfn=0; - double apfd=0; - double apgn=0; - double apgd=0; - double an=0; - double ad=0; - double apn=0; - double apd=0; - double bn16=0; - double bd16=0; - double bppn=0; - double bppd=0; -//--- initialization - ai=0; - aip=0; - bi=0; - bip=0; - sqpii=5.64189583547756286948E-1; - c1=0.35502805388781723926; - c2=0.258819403792806798405; - sqrt3=1.732050807568877293527; - domflg=0; -//--- check - if(x>25.77) - { - //--- initialization - ai=0; - aip=0; - bi=CMath::m_maxrealnumber; - bip=CMath::m_maxrealnumber; - //--- exit the function - return; - } -//--- check - if(x<-2.09) - { - //--- calculation - domflg=15; - t=MathSqrt(-x); - zeta=-(2.0*x*t/3.0); - t=MathSqrt(t); - k=sqpii/t; - z=1.0/zeta; - zz=z*z; - //--- calculation - afn=-1.31696323418331795333E-1; - afn=afn*zz-6.26456544431912369773E-1; - afn=afn*zz-6.93158036036933542233E-1; - afn=afn*zz-2.79779981545119124951E-1; - afn=afn*zz-4.91900132609500318020E-2; - afn=afn*zz-4.06265923594885404393E-3; - afn=afn*zz-1.59276496239262096340E-4; - afn=afn*zz-2.77649108155232920844E-6; - afn=afn*zz-1.67787698489114633780E-8; - //--- calculation - afd=1.00000000000000000000E0; - afd=afd*zz+1.33560420706553243746E1; - afd=afd*zz+3.26825032795224613948E1; - afd=afd*zz+2.67367040941499554804E1; - afd=afd*zz+9.18707402907259625840E0; - afd=afd*zz+1.47529146771666414581E0; - afd=afd*zz+1.15687173795188044134E-1; - afd=afd*zz+4.40291641615211203805E-3; - afd=afd*zz+7.54720348287414296618E-5; - afd=afd*zz+4.51850092970580378464E-7; - uf=1.0+zz*afn/afd; - //--- calculation - agn=1.97339932091685679179E-2; - agn=agn*zz+3.91103029615688277255E-1; - agn=agn*zz+1.06579897599595591108E0; - agn=agn*zz+9.39169229816650230044E-1; - agn=agn*zz+3.51465656105547619242E-1; - agn=agn*zz+6.33888919628925490927E-2; - agn=agn*zz+5.85804113048388458567E-3; - agn=agn*zz+2.82851600836737019778E-4; - agn=agn*zz+6.98793669997260967291E-6; - agn=agn*zz+8.11789239554389293311E-8; - agn=agn*zz+3.41551784765923618484E-10; - //--- calculation - agd=1.00000000000000000000E0; - agd=agd*zz+9.30892908077441974853E0; - agd=agd*zz+1.98352928718312140417E1; - agd=agd*zz+1.55646628932864612953E1; - agd=agd*zz+5.47686069422975497931E0; - agd=agd*zz+9.54293611618961883998E-1; - agd=agd*zz+8.64580826352392193095E-2; - agd=agd*zz+4.12656523824222607191E-3; - agd=agd*zz+1.01259085116509135510E-4; - agd=agd*zz+1.17166733214413521882E-6; - agd=agd*zz+4.91834570062930015649E-9; - //--- calculation - ug=z*agn/agd; - theta=zeta+0.25*M_PI; - f=MathSin(theta); - g=MathCos(theta); - ai=k*(f*uf-g*ug); - bi=k*(g*uf+f*ug); - apfn=1.85365624022535566142E-1; - apfn=apfn*zz+8.86712188052584095637E-1; - apfn=apfn*zz+9.87391981747398547272E-1; - apfn=apfn*zz+4.01241082318003734092E-1; - apfn=apfn*zz+7.10304926289631174579E-2; - apfn=apfn*zz+5.90618657995661810071E-3; - apfn=apfn*zz+2.33051409401776799569E-4; - apfn=apfn*zz+4.08718778289035454598E-6; - apfn=apfn*zz+2.48379932900442457853E-8; - //--- calculation - apfd=1.00000000000000000000E0; - apfd=apfd*zz+1.47345854687502542552E1; - apfd=apfd*zz+3.75423933435489594466E1; - apfd=apfd*zz+3.14657751203046424330E1; - apfd=apfd*zz+1.09969125207298778536E1; - apfd=apfd*zz+1.78885054766999417817E0; - apfd=apfd*zz+1.41733275753662636873E-1; - apfd=apfd*zz+5.44066067017226003627E-3; - apfd=apfd*zz+9.39421290654511171663E-5; - apfd=apfd*zz+5.65978713036027009243E-7; - uf=1.0+zz*apfn/apfd; - //--- calculation - apgn=-3.55615429033082288335E-2; - apgn=apgn*zz-6.37311518129435504426E-1; - apgn=apgn*zz-1.70856738884312371053E0; - apgn=apgn*zz-1.50221872117316635393E0; - apgn=apgn*zz-5.63606665822102676611E-1; - apgn=apgn*zz-1.02101031120216891789E-1; - apgn=apgn*zz-9.48396695961445269093E-3; - apgn=apgn*zz-4.60325307486780994357E-4; - apgn=apgn*zz-1.14300836484517375919E-5; - apgn=apgn*zz-1.33415518685547420648E-7; - apgn=apgn*zz-5.63803833958893494476E-10; - //--- calculation - apgd=1.00000000000000000000E0; - apgd=apgd*zz+9.85865801696130355144E0; - apgd=apgd*zz+2.16401867356585941885E1; - apgd=apgd*zz+1.73130776389749389525E1; - apgd=apgd*zz+6.17872175280828766327E0; - apgd=apgd*zz+1.08848694396321495475E0; - apgd=apgd*zz+9.95005543440888479402E-2; - apgd=apgd*zz+4.78468199683886610842E-3; - apgd=apgd*zz+1.18159633322838625562E-4; - apgd=apgd*zz+1.37480673554219441465E-6; - apgd=apgd*zz+5.79912514929147598821E-9; - ug=z*apgn/apgd; - k=sqpii*t; - aip=-(k*(g*uf+f*ug)); - bip=k*(f*uf-g*ug); - //--- exit the function - return; - } -//--- check - if(x>=(double)(2.09)) - { - domflg=5; - t=MathSqrt(x); - zeta=2.0*x*t/3.0; - g=MathExp(zeta); - t=MathSqrt(t); - k=2.0*t*g; - z=1.0/zeta; - //--- calculation - an=3.46538101525629032477E-1; - an=an*z+1.20075952739645805542E1; - an=an*z+7.62796053615234516538E1; - an=an*z+1.68089224934630576269E2; - an=an*z+1.59756391350164413639E2; - an=an*z+7.05360906840444183113E1; - an=an*z+1.40264691163389668864E1; - an=an*z+9.99999999999999995305E-1; - ad=5.67594532638770212846E-1; - ad=ad*z+1.47562562584847203173E1; - ad=ad*z+8.45138970141474626562E1; - ad=ad*z+1.77318088145400459522E2; - ad=ad*z+1.64234692871529701831E2; - ad=ad*z+7.14778400825575695274E1; - ad=ad*z+1.40959135607834029598E1; - ad=ad*z+1.00000000000000000470E0; - //--- calculation - f=an/ad; - ai=sqpii*f/k; - k=-(0.5*sqpii*t/g); - apn=6.13759184814035759225E-1; - apn=apn*z+1.47454670787755323881E1; - apn=apn*z+8.20584123476060982430E1; - apn=apn*z+1.71184781360976385540E2; - apn=apn*z+1.59317847137141783523E2; - apn=apn*z+6.99778599330103016170E1; - apn=apn*z+1.39470856980481566958E1; - apn=apn*z+1.00000000000000000550E0; - apd=3.34203677749736953049E-1; - apd=apd*z+1.11810297306158156705E1; - apd=apd*z+7.11727352147859965283E1; - apd=apd*z+1.58778084372838313640E2; - apd=apd*z+1.53206427475809220834E2; - apd=apd*z+6.86752304592780337944E1; - apd=apd*z+1.38498634758259442477E1; - apd=apd*z+9.99999999999999994502E-1; - f=apn/apd; - aip=f*k; - //--- check - if(x>(double)(8.3203353)) - { - //--- calculation - bn16=-2.53240795869364152689E-1; - bn16=bn16*z+5.75285167332467384228E-1; - bn16=bn16*z-3.29907036873225371650E-1; - bn16=bn16*z+6.44404068948199951727E-2; - bn16=bn16*z-3.82519546641336734394E-3; - bd16=1.00000000000000000000E0; - bd16=bd16*z-7.15685095054035237902E0; - bd16=bd16*z+1.06039580715664694291E1; - bd16=bd16*z-5.23246636471251500874E0; - bd16=bd16*z+9.57395864378383833152E-1; - bd16=bd16*z-5.50828147163549611107E-2; - //--- calculation - f=z*bn16/bd16; - k=sqpii*g; - bi=k*(1.0+f)/t; - bppn=4.65461162774651610328E-1; - bppn=bppn*z-1.08992173800493920734E0; - bppn=bppn*z+6.38800117371827987759E-1; - bppn=bppn*z-1.26844349553102907034E-1; - bppn=bppn*z+7.62487844342109852105E-3; - bppd=1.00000000000000000000E0; - bppd=bppd*z-8.70622787633159124240E0; - bppd=bppd*z+1.38993162704553213172E1; - bppd=bppd*z-7.14116144616431159572E0; - bppd=bppd*z+1.34008595960680518666E0; - bppd=bppd*z-7.84273211323341930448E-2; - f=z*bppn/bppd; - bip=k*t*(1.0+f); - //--- exit the function - return; - } - } -//--- change values - f=1.0; - g=x; - t=1.0; - uf=1.0; - ug=x; - k=1.0; - z=x*x*x; -//--- cycle - while(t>CMath::m_machineepsilon) - { - //--- calculation - uf=uf*z; - k=k+1.0; - uf=uf/k; - ug=ug*z; - k=k+1.0; - ug=ug/k; - uf=uf/k; - f=f+uf; - k=k+1.0; - ug=ug/k; - g=g+ug; - t=MathAbs(uf/f); - } -//--- change values - uf=c1*f; - ug=c2*g; -//--- check - if(domflg%2==0) - ai=uf-ug; -//--- check - if(domflg/2%2==0) - bi=sqrt3*(uf+ug); -//--- change values - k=4.0; - uf=x*x/2.0; - ug=z/3.0; - f=uf; - g=1.0+ug; - uf=uf/3.0; - t=1.0; -//--- cycle - while(t>CMath::m_machineepsilon) - { - //--- calculation - uf=uf*z; - ug=ug/k; - k=k+1.0; - ug=ug*z; - uf=uf/k; - f=f+uf; - k=k+1.0; - ug=ug/k; - uf=uf/k; - g=g+ug; - k=k+1.0; - t=MathAbs(ug/g); - } -//--- change values - uf=c1*f; - ug=c2*g; -//--- check - if(domflg/4%2==0) - aip=uf-ug; -//--- check - if(domflg/8%2==0) - bip=sqrt3*(uf+ug); - } -//+------------------------------------------------------------------+ -//| Bessel function | -//+------------------------------------------------------------------+ -class CBessel - { -private: - //--- private methods - static void BesselMFirstCheb(const double c,double &b0,double &b1,double &b2); - static void BesselMNextCheb(const double x,const double c,double &b0,double &b1,double &b2); - static void BesselM1FirstCheb(const double c,double &b0,double &b1,double &b2); - static void BesselM1NextCheb(const double x,const double c,double &b0,double &b1,double &b2); - static void BesselAsympt0(const double x,double &pzero,double &qzero); - static void BesselAsympt1(const double x,double &pzero,double &qzero); -public: - //--- constructor, destructor - CBessel(void); - ~CBessel(void); - //--- public methods - static double BesselJ0(double x); - static double BesselJ1(double x); - static double BesselJN(int n,double x); - static double BesselY0(double x); - static double BesselY1(double x); - static double BesselYN(int n,double x); - static double BesselI0(double x); - static double BesselI1(double x); - static double BesselK0(double x); - static double BesselK1(double x); - static double BesselKN(int nn,double x); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CBessel::CBessel(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CBessel::~CBessel(void) - { - - } -//+------------------------------------------------------------------+ -//| Bessel function of order zero | -//| Returns Bessel function of order zero of the argument. | -//| The domain is divided into the intervals [0, 5] and | -//| (5, infinity). In the first interval the following rational | -//| approximation is used: | -//| 2 2 | -//| (w - r ) (w - r ) P (w) / Q (w) | -//| 1 2 3 8 | -//| 2 | -//| where w = x and the two r's are zeros of the function. | -//| In the second interval, the Hankel asymptotic expansion | -//| is employed with two rational functions of degree 6/6 | -//| and 7/7. | -//| ACCURACY: | -//| Absolute error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0, 30 60000 4.2e-16 1.1e-16 | -//+------------------------------------------------------------------+ -static double CBessel::BesselJ0(double x) - { -//--- create variables - double xsq=0; - double nn=0; - double pzero=0; - double qzero=0; - double p1=0; - double q1=0; -//--- check - if(x<0.0) - x=-x; -//--- check - if(x>8.0) - { - //--- function call - BesselAsympt0(x,pzero,qzero); - nn=x-M_PI/4; - //--- return result - return(MathSqrt(2/M_PI/x)*(pzero*MathCos(nn)-qzero*MathSin(nn))); - } -//--- calculation - xsq=CMath::Sqr(x); - p1=26857.86856980014981415848441; - p1=-40504123.71833132706360663322+xsq*p1; - p1=25071582855.36881945555156435+xsq*p1; - p1=-8085222034853.793871199468171+xsq*p1; - p1=1434354939140344.111664316553+xsq*p1; - p1=-136762035308817138.6865416609+xsq*p1; - p1=6382059341072356562.289432465+xsq*p1; - p1=-117915762910761053603.8440800+xsq*p1; - p1=493378725179413356181.6813446+xsq*p1; - q1=1.0; - q1=1363.063652328970604442810507+xsq*q1; - q1=1114636.098462985378182402543+xsq*q1; - q1=669998767.2982239671814028660+xsq*q1; - q1=312304311494.1213172572469442+xsq*q1; - q1=112775673967979.8507056031594+xsq*q1; - q1=30246356167094626.98627330784+xsq*q1; - q1=5428918384092285160.200195092+xsq*q1; - q1=493378725179413356211.3278438+xsq*q1; -//--- return result - return(p1/q1); - } -//+------------------------------------------------------------------+ -//| Bessel function of order one | -//| Returns Bessel function of order one of the argument. | -//| The domain is divided into the intervals [0, 8] and | -//| (8, infinity). In the first interval a 24 term Chebyshev | -//| expansion is used. In the second, the asymptotic | -//| trigonometric representation is employed using two | -//| rational functions of degree 5/5. | -//| ACCURACY: | -//| Absolute error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0, 30 30000 2.6e-16 1.1e-16 | -//+------------------------------------------------------------------+ -static double CBessel::BesselJ1(double x) - { -//--- create variables - double result=0; - double s=0; - double xsq=0; - double nn=0; - double pzero=0; - double qzero=0; - double p1=0; - double q1=0; -//--- calculation - s=MathSign(x); -//--- check - if(x<0.0) - x=-x; -//--- check - if(x>8.0) - { - //--- function call - BesselAsympt1(x,pzero,qzero); - nn=x-3*M_PI/4; - result=MathSqrt(2/M_PI/x)*(pzero*MathCos(nn)-qzero*MathSin(nn)); - //--- check - if(s<0.0) - result=-result; - //--- return result - return(result); - } -//--- calculation - xsq=CMath::Sqr(x); - p1=2701.122710892323414856790990; - p1=-4695753.530642995859767162166+xsq*p1; - p1=3413234182.301700539091292655+xsq*p1; - p1=-1322983480332.126453125473247+xsq*p1; - p1=290879526383477.5409737601689+xsq*p1; - p1=-35888175699101060.50743641413+xsq*p1; - p1=2316433580634002297.931815435+xsq*p1; - p1=-66721065689249162980.20941484+xsq*p1; - p1=581199354001606143928.050809+xsq*p1; - q1=1.0; - q1=1606.931573481487801970916749+xsq*q1; - q1=1501793.594998585505921097578+xsq*q1; - q1=1013863514.358673989967045588+xsq*q1; - q1=524371026216.7649715406728642+xsq*q1; - q1=208166122130760.7351240184229+xsq*q1; - q1=60920613989175217.46105196863+xsq*q1; - q1=11857707121903209998.37113348+xsq*q1; - q1=1162398708003212287858.529400+xsq*q1; -//--- return result - return(s*x*p1/q1); - } -//+------------------------------------------------------------------+ -//| Bessel function of integer order | -//| Returns Bessel function of order n, where n is a | -//| (possibly negative) integer. | -//| The ratio of jn(x) to j0(x) is computed by backward | -//| recurrence. First the ratio jn/jn-1 is found by a | -//| continued fraction expansion. Then the recurrence | -//| relating successive orders is applied until j0 or j1 is | -//| reached. | -//| If n = 0 or 1 the routine for j0 or j1 is called | -//| directly. | -//| ACCURACY: | -//| Absolute error: | -//| arithmetic range # trials peak rms | -//| IEEE 0, 30 5000 4.4e-16 7.9e-17 | -//| Not suitable for large n or x. Use jv() (fractional order) | -//| instead. | -//+------------------------------------------------------------------+ -static double CBessel::BesselJN(int n,double x) - { -//--- create variables - double result=0; - double pkm2=0; - double pkm1=0; - double pk=0; - double xk=0; - double r=0; - double ans=0; - int k=0; - int sg=0; -//--- check - if(n<0) - { - n=-n; - //--- check - if(n%2==0) - sg=1; - else - sg=-1; - } - else - sg=1; -//--- check - if(x<0.0) - { - //--- check - if(n%2!=0) - sg=-sg; - x=-x; - } -//--- check - if(n==0) - return(sg*BesselJ0(x)); -//--- check - if(n==1) - return(sg*BesselJ1(x)); -//--- check - if(n==2) - { - //--- check - if(x==0.0) - return(0); - else - return(sg*(2.0*BesselJ1(x)/x-BesselJ0(x))); - } -//--- check - if(xMathAbs(pkm1)) - ans=BesselJ1(x)/pk; - else - ans=BesselJ0(x)/pkm1; -//--- return result - return(sg*ans); - } -//+------------------------------------------------------------------+ -//| Bessel function of the second kind, order zero | -//| Returns Bessel function of the second kind, of order | -//| zero, of the argument. | -//| The domain is divided into the intervals [0, 5] and | -//| (5, infinity). In the first interval a rational approximation | -//| R(x) is employed to compute | -//| y0(x) = R(x) + 2 * log(x) * j0(x) / PI. | -//| Thus a call to j0() is required. | -//| In the second interval, the Hankel asymptotic expansion | -//| is employed with two rational functions of degree 6/6 | -//| and 7/7. | -//| ACCURACY: | -//| Absolute error, when y0(x) < 1; else relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0, 30 30000 1.3e-15 1.6e-16 | -//+------------------------------------------------------------------+ -static double CBessel::BesselY0(double x) - { -//--- create variables - double nn=0; - double xsq=0; - double pzero=0; - double qzero=0; - double p4=0; - double q4=0; -//--- check - if(x>8.0) - { - //--- function call - BesselAsympt0(x,pzero,qzero); - nn=x-M_PI/4; - //--- return result - return(MathSqrt(2/M_PI/x)*(pzero*MathSin(nn)+qzero*MathCos(nn))); - } -//--- calculation - xsq=CMath::Sqr(x); - p4=-41370.35497933148554125235152; - p4=59152134.65686889654273830069+xsq*p4; - p4=-34363712229.79040378171030138+xsq*p4; - p4=10255208596863.94284509167421+xsq*p4; - p4=-1648605817185729.473122082537+xsq*p4; - p4=137562431639934407.8571335453+xsq*p4; - p4=-5247065581112764941.297350814+xsq*p4; - p4=65874732757195549259.99402049+xsq*p4; - p4=-27502866786291095837.01933175+xsq*p4; - q4=1.0; - q4=1282.452772478993804176329391+xsq*q4; - q4=1001702.641288906265666651753+xsq*q4; - q4=579512264.0700729537480087915+xsq*q4; - q4=261306575504.1081249568482092+xsq*q4; - q4=91620380340751.85262489147968+xsq*q4; - q4=23928830434997818.57439356652+xsq*q4; - q4=4192417043410839973.904769661+xsq*q4; - q4=372645883898616588198.9980+xsq*q4; -//--- return result - return(p4/q4+2/M_PI*BesselJ0(x)*MathLog(x)); - } -//+------------------------------------------------------------------+ -//| Bessel function of second kind of order one | -//| Returns Bessel function of the second kind of order one | -//| of the argument. | -//| The domain is divided into the intervals [0, 8] and | -//| (8, infinity). In the first interval a 25 term Chebyshev | -//| expansion is used, and a call to j1() is required. | -//| In the second, the asymptotic trigonometric representation | -//| is employed using two rational functions of degree 5/5. | -//| ACCURACY: | -//| Absolute error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0, 30 30000 1.0e-15 1.3e-16 | -//+------------------------------------------------------------------+ -static double CBessel::BesselY1(double x) - { -//--- create variables - double nn=0; - double xsq=0; - double pzero=0; - double qzero=0; - double p4=0; - double q4=0; -//--- check - if(x>8.0) - { - //--- function call - BesselAsympt1(x,pzero,qzero); - nn=x-3*M_PI/4; - //--- return result - return(MathSqrt(2/M_PI/x)*(pzero*MathSin(nn)+qzero*MathCos(nn))); - } -//--- calculation - xsq=CMath::Sqr(x); - p4=-2108847.540133123652824139923; - p4=3639488548.124002058278999428+xsq*p4; - p4=-2580681702194.450950541426399+xsq*p4; - p4=956993023992168.3481121552788+xsq*p4; - p4=-196588746272214065.8820322248+xsq*p4; - p4=21931073399177975921.11427556+xsq*p4; - p4=-1212297555414509577913.561535+xsq*p4; - p4=26554738314348543268942.48968+xsq*p4; - p4=-99637534243069222259967.44354+xsq*p4; - q4=1.0; - q4=1612.361029677000859332072312+xsq*q4; - q4=1563282.754899580604737366452+xsq*q4; - q4=1128686837.169442121732366891+xsq*q4; - q4=646534088126.5275571961681500+xsq*q4; - q4=297663212564727.6729292742282+xsq*q4; - q4=108225825940881955.2553850180+xsq*q4; - q4=29549879358971486742.90758119+xsq*q4; - q4=5435310377188854170800.653097+xsq*q4; - q4=508206736694124324531442.4152+xsq*q4; -//--- return result - return(x*p4/q4+2/M_PI*(BesselJ1(x)*MathLog(x)-1/x)); - } -//+------------------------------------------------------------------+ -//| Bessel function of second kind of integer order | -//| Returns Bessel function of order n, where n is a | -//| (possibly negative) integer. | -//| The function is evaluated by forward recurrence on | -//| n, starting with values computed by the routines | -//| y0() and y1(). | -//| If n = 0 or 1 the routine for y0 or y1 is called | -//| directly. | -//| ACCURACY: | -//| Absolute error, except relative | -//| when y > 1: | -//| arithmetic domain # trials peak rms | -//| IEEE 0, 30 30000 3.4e-15 4.3e-16 | -//+------------------------------------------------------------------+ -static double CBessel::BesselYN(int n,double x) - { -//--- create variables - int i=0; - double a=0; - double b=0; - double tmp=0; - double s=0; -//--- initialization - s=1; -//--- check - if(n<0) - { - n=-n; - //--- check - if(n%2!=0) - s=-1; - } -//--- check - if(n==0) - return(BesselY0(x)); -//--- check - if(n==1) - return(s*BesselY1(x)); -//--- calculation - a=BesselY0(x); - b=BesselY1(x); - for(i=1;i<=n-1;i++) - { - tmp=b; - b=2*i/x*b-a; - a=tmp; - } -//--- return result - return(s*b); - } -//+------------------------------------------------------------------+ -//| Modified Bessel function of order zero | -//| Returns modified Bessel function of order zero of the | -//| argument. | -//| The function is defined as i0(x) = j0( ix ). | -//| The range is partitioned into the two intervals [0,8] and | -//| (8, infinity). Chebyshev polynomial expansions are employed | -//| in each interval. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0,30 30000 5.8e-16 1.4e-16 | -//+------------------------------------------------------------------+ -static double CBessel::BesselI0(double x) - { -//--- create variables - double y=0; - double v=0; - double z=0; - double b0=0; - double b1=0; - double b2=0; -//--- check - if(x<0.0) - x=-x; -//--- check - if(x<=8.0) - { - y=x/2.0-2.0; - //--- function calls - BesselMFirstCheb(-4.41534164647933937950E-18,b0,b1,b2); - BesselMNextCheb(y,3.33079451882223809783E-17,b0,b1,b2); - BesselMNextCheb(y,-2.43127984654795469359E-16,b0,b1,b2); - BesselMNextCheb(y,1.71539128555513303061E-15,b0,b1,b2); - BesselMNextCheb(y,-1.16853328779934516808E-14,b0,b1,b2); - BesselMNextCheb(y,7.67618549860493561688E-14,b0,b1,b2); - BesselMNextCheb(y,-4.85644678311192946090E-13,b0,b1,b2); - BesselMNextCheb(y,2.95505266312963983461E-12,b0,b1,b2); - BesselMNextCheb(y,-1.72682629144155570723E-11,b0,b1,b2); - BesselMNextCheb(y,9.67580903537323691224E-11,b0,b1,b2); - BesselMNextCheb(y,-5.18979560163526290666E-10,b0,b1,b2); - BesselMNextCheb(y,2.65982372468238665035E-9,b0,b1,b2); - BesselMNextCheb(y,-1.30002500998624804212E-8,b0,b1,b2); - BesselMNextCheb(y,6.04699502254191894932E-8,b0,b1,b2); - BesselMNextCheb(y,-2.67079385394061173391E-7,b0,b1,b2); - BesselMNextCheb(y,1.11738753912010371815E-6,b0,b1,b2); - BesselMNextCheb(y,-4.41673835845875056359E-6,b0,b1,b2); - BesselMNextCheb(y,1.64484480707288970893E-5,b0,b1,b2); - BesselMNextCheb(y,-5.75419501008210370398E-5,b0,b1,b2); - BesselMNextCheb(y,1.88502885095841655729E-4,b0,b1,b2); - BesselMNextCheb(y,-5.76375574538582365885E-4,b0,b1,b2); - BesselMNextCheb(y,1.63947561694133579842E-3,b0,b1,b2); - BesselMNextCheb(y,-4.32430999505057594430E-3,b0,b1,b2); - BesselMNextCheb(y,1.05464603945949983183E-2,b0,b1,b2); - BesselMNextCheb(y,-2.37374148058994688156E-2,b0,b1,b2); - BesselMNextCheb(y,4.93052842396707084878E-2,b0,b1,b2); - BesselMNextCheb(y,-9.49010970480476444210E-2,b0,b1,b2); - BesselMNextCheb(y,1.71620901522208775349E-1,b0,b1,b2); - BesselMNextCheb(y,-3.04682672343198398683E-1,b0,b1,b2); - BesselMNextCheb(y,6.76795274409476084995E-1,b0,b1,b2); - //--- calculation - v=0.5*(b0-b2); - //--- return result - return(MathExp(x)*v); - } -//--- change value - z=32.0/x-2.0; -//--- function calls - BesselMFirstCheb(-7.23318048787475395456E-18,b0,b1,b2); - BesselMNextCheb(z,-4.83050448594418207126E-18,b0,b1,b2); - BesselMNextCheb(z,4.46562142029675999901E-17,b0,b1,b2); - BesselMNextCheb(z,3.46122286769746109310E-17,b0,b1,b2); - BesselMNextCheb(z,-2.82762398051658348494E-16,b0,b1,b2); - BesselMNextCheb(z,-3.42548561967721913462E-16,b0,b1,b2); - BesselMNextCheb(z,1.77256013305652638360E-15,b0,b1,b2); - BesselMNextCheb(z,3.81168066935262242075E-15,b0,b1,b2); - BesselMNextCheb(z,-9.55484669882830764870E-15,b0,b1,b2); - BesselMNextCheb(z,-4.15056934728722208663E-14,b0,b1,b2); - BesselMNextCheb(z,1.54008621752140982691E-14,b0,b1,b2); - BesselMNextCheb(z,3.85277838274214270114E-13,b0,b1,b2); - BesselMNextCheb(z,7.18012445138366623367E-13,b0,b1,b2); - BesselMNextCheb(z,-1.79417853150680611778E-12,b0,b1,b2); - BesselMNextCheb(z,-1.32158118404477131188E-11,b0,b1,b2); - BesselMNextCheb(z,-3.14991652796324136454E-11,b0,b1,b2); - BesselMNextCheb(z,1.18891471078464383424E-11,b0,b1,b2); - BesselMNextCheb(z,4.94060238822496958910E-10,b0,b1,b2); - BesselMNextCheb(z,3.39623202570838634515E-9,b0,b1,b2); - BesselMNextCheb(z,2.26666899049817806459E-8,b0,b1,b2); - BesselMNextCheb(z,2.04891858946906374183E-7,b0,b1,b2); - BesselMNextCheb(z,2.89137052083475648297E-6,b0,b1,b2); - BesselMNextCheb(z,6.88975834691682398426E-5,b0,b1,b2); - BesselMNextCheb(z,3.36911647825569408990E-3,b0,b1,b2); - BesselMNextCheb(z,8.04490411014108831608E-1,b0,b1,b2); -//--- calculation - v=0.5*(b0-b2); -//--- return result - return(MathExp(x)*v/MathSqrt(x)); - } -//+------------------------------------------------------------------+ -//| Modified Bessel function of order one | -//| Returns modified Bessel function of order one of the | -//| argument. | -//| The function is defined as i1(x) = -i j1( ix ). | -//| The range is partitioned into the two intervals [0,8] and | -//| (8, infinity). Chebyshev polynomial expansions are employed | -//| in each interval. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0, 30 30000 1.9e-15 2.1e-16 | -//+------------------------------------------------------------------+ -static double CBessel::BesselI1(double x) - { -//--- create variables - double y=0; - double z=0; - double v=0; - double b0=0; - double b1=0; - double b2=0; -//--- initialization - z=MathAbs(x); -//--- check - if(z<=8.0) - { - //--- initialization - y=z/2.0-2.0; - //--- function call - BesselM1FirstCheb(2.77791411276104639959E-18,b0,b1,b2); - BesselM1NextCheb(y,-2.11142121435816608115E-17,b0,b1,b2); - BesselM1NextCheb(y,1.55363195773620046921E-16,b0,b1,b2); - BesselM1NextCheb(y,-1.10559694773538630805E-15,b0,b1,b2); - BesselM1NextCheb(y,7.60068429473540693410E-15,b0,b1,b2); - BesselM1NextCheb(y,-5.04218550472791168711E-14,b0,b1,b2); - BesselM1NextCheb(y,3.22379336594557470981E-13,b0,b1,b2); - BesselM1NextCheb(y,-1.98397439776494371520E-12,b0,b1,b2); - BesselM1NextCheb(y,1.17361862988909016308E-11,b0,b1,b2); - BesselM1NextCheb(y,-6.66348972350202774223E-11,b0,b1,b2); - BesselM1NextCheb(y,3.62559028155211703701E-10,b0,b1,b2); - BesselM1NextCheb(y,-1.88724975172282928790E-9,b0,b1,b2); - BesselM1NextCheb(y,9.38153738649577178388E-9,b0,b1,b2); - BesselM1NextCheb(y,-4.44505912879632808065E-8,b0,b1,b2); - BesselM1NextCheb(y,2.00329475355213526229E-7,b0,b1,b2); - BesselM1NextCheb(y,-8.56872026469545474066E-7,b0,b1,b2); - BesselM1NextCheb(y,3.47025130813767847674E-6,b0,b1,b2); - BesselM1NextCheb(y,-1.32731636560394358279E-5,b0,b1,b2); - BesselM1NextCheb(y,4.78156510755005422638E-5,b0,b1,b2); - BesselM1NextCheb(y,-1.61760815825896745588E-4,b0,b1,b2); - BesselM1NextCheb(y,5.12285956168575772895E-4,b0,b1,b2); - BesselM1NextCheb(y,-1.51357245063125314899E-3,b0,b1,b2); - BesselM1NextCheb(y,4.15642294431288815669E-3,b0,b1,b2); - BesselM1NextCheb(y,-1.05640848946261981558E-2,b0,b1,b2); - BesselM1NextCheb(y,2.47264490306265168283E-2,b0,b1,b2); - BesselM1NextCheb(y,-5.29459812080949914269E-2,b0,b1,b2); - BesselM1NextCheb(y,1.02643658689847095384E-1,b0,b1,b2); - BesselM1NextCheb(y,-1.76416518357834055153E-1,b0,b1,b2); - BesselM1NextCheb(y,2.52587186443633654823E-1,b0,b1,b2); - //--- calculation - v=0.5*(b0-b2); - z=v*z*MathExp(z); - } - else - { - //--- initialization - y=32.0/z-2.0; - //--- function calls - BesselM1FirstCheb(7.51729631084210481353E-18,b0,b1,b2); - BesselM1NextCheb(y,4.41434832307170791151E-18,b0,b1,b2); - BesselM1NextCheb(y,-4.65030536848935832153E-17,b0,b1,b2); - BesselM1NextCheb(y,-3.20952592199342395980E-17,b0,b1,b2); - BesselM1NextCheb(y,2.96262899764595013876E-16,b0,b1,b2); - BesselM1NextCheb(y,3.30820231092092828324E-16,b0,b1,b2); - BesselM1NextCheb(y,-1.88035477551078244854E-15,b0,b1,b2); - BesselM1NextCheb(y,-3.81440307243700780478E-15,b0,b1,b2); - BesselM1NextCheb(y,1.04202769841288027642E-14,b0,b1,b2); - BesselM1NextCheb(y,4.27244001671195135429E-14,b0,b1,b2); - BesselM1NextCheb(y,-2.10154184277266431302E-14,b0,b1,b2); - BesselM1NextCheb(y,-4.08355111109219731823E-13,b0,b1,b2); - BesselM1NextCheb(y,-7.19855177624590851209E-13,b0,b1,b2); - BesselM1NextCheb(y,2.03562854414708950722E-12,b0,b1,b2); - BesselM1NextCheb(y,1.41258074366137813316E-11,b0,b1,b2); - BesselM1NextCheb(y,3.25260358301548823856E-11,b0,b1,b2); - BesselM1NextCheb(y,-1.89749581235054123450E-11,b0,b1,b2); - BesselM1NextCheb(y,-5.58974346219658380687E-10,b0,b1,b2); - BesselM1NextCheb(y,-3.83538038596423702205E-9,b0,b1,b2); - BesselM1NextCheb(y,-2.63146884688951950684E-8,b0,b1,b2); - BesselM1NextCheb(y,-2.51223623787020892529E-7,b0,b1,b2); - BesselM1NextCheb(y,-3.88256480887769039346E-6,b0,b1,b2); - BesselM1NextCheb(y,-1.10588938762623716291E-4,b0,b1,b2); - BesselM1NextCheb(y,-9.76109749136146840777E-3,b0,b1,b2); - BesselM1NextCheb(y,7.78576235018280120474E-1,b0,b1,b2); - //--- calculation - v=0.5*(b0-b2); - z=v*MathExp(z)/MathSqrt(z); - } -//--- check - if(x<0.0) - z=-z; -//--- return result - return(z); - } -//+------------------------------------------------------------------+ -//| Modified Bessel function, second kind, order zero | -//| Returns modified Bessel function of the second kind | -//| of order zero of the argument. | -//| The range is partitioned into the two intervals [0,8] and | -//| (8, infinity). Chebyshev polynomial expansions are employed | -//| in each interval. | -//| ACCURACY: | -//| Tested at 2000 random points between 0 and 8. Peak absolute | -//| error (relative when K0 > 1) was 1.46e-14; rms, 4.26e-15. | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0, 30 30000 1.2e-15 1.6e-16 | -//+------------------------------------------------------------------+ -static double CBessel::BesselK0(double x) - { -//--- create variables - double result=0; - double y=0; - double z=0; - double v=0; - double b0=0; - double b1=0; - double b2=0; -//--- check - if(!CAp::Assert(x>0.0,__FUNCTION__+": x<=0")) - return(EMPTY_VALUE); -//--- check - if(x<=2.0) - { - //--- initialization - y=x*x-2.0; - //--- function calls - BesselMFirstCheb(1.37446543561352307156E-16,b0,b1,b2); - BesselMNextCheb(y,4.25981614279661018399E-14,b0,b1,b2); - BesselMNextCheb(y,1.03496952576338420167E-11,b0,b1,b2); - BesselMNextCheb(y,1.90451637722020886025E-9,b0,b1,b2); - BesselMNextCheb(y,2.53479107902614945675E-7,b0,b1,b2); - BesselMNextCheb(y,2.28621210311945178607E-5,b0,b1,b2); - BesselMNextCheb(y,1.26461541144692592338E-3,b0,b1,b2); - BesselMNextCheb(y,3.59799365153615016266E-2,b0,b1,b2); - BesselMNextCheb(y,3.44289899924628486886E-1,b0,b1,b2); - BesselMNextCheb(y,-5.35327393233902768720E-1,b0,b1,b2); - v=0.5*(b0-b2); - v=v-MathLog(0.5*x)*BesselI0(x); - } - else - { - //--- initialization - z=8.0/x-2.0; - //--- function call - BesselMFirstCheb(5.30043377268626276149E-18,b0,b1,b2); - BesselMNextCheb(z,-1.64758043015242134646E-17,b0,b1,b2); - BesselMNextCheb(z,5.21039150503902756861E-17,b0,b1,b2); - BesselMNextCheb(z,-1.67823109680541210385E-16,b0,b1,b2); - BesselMNextCheb(z,5.51205597852431940784E-16,b0,b1,b2); - BesselMNextCheb(z,-1.84859337734377901440E-15,b0,b1,b2); - BesselMNextCheb(z,6.34007647740507060557E-15,b0,b1,b2); - BesselMNextCheb(z,-2.22751332699166985548E-14,b0,b1,b2); - BesselMNextCheb(z,8.03289077536357521100E-14,b0,b1,b2); - BesselMNextCheb(z,-2.98009692317273043925E-13,b0,b1,b2); - BesselMNextCheb(z,1.14034058820847496303E-12,b0,b1,b2); - BesselMNextCheb(z,-4.51459788337394416547E-12,b0,b1,b2); - BesselMNextCheb(z,1.85594911495471785253E-11,b0,b1,b2); - BesselMNextCheb(z,-7.95748924447710747776E-11,b0,b1,b2); - BesselMNextCheb(z,3.57739728140030116597E-10,b0,b1,b2); - BesselMNextCheb(z,-1.69753450938905987466E-9,b0,b1,b2); - BesselMNextCheb(z,8.57403401741422608519E-9,b0,b1,b2); - BesselMNextCheb(z,-4.66048989768794782956E-8,b0,b1,b2); - BesselMNextCheb(z,2.76681363944501510342E-7,b0,b1,b2); - BesselMNextCheb(z,-1.83175552271911948767E-6,b0,b1,b2); - BesselMNextCheb(z,1.39498137188764993662E-5,b0,b1,b2); - BesselMNextCheb(z,-1.28495495816278026384E-4,b0,b1,b2); - BesselMNextCheb(z,1.56988388573005337491E-3,b0,b1,b2); - BesselMNextCheb(z,-3.14481013119645005427E-2,b0,b1,b2); - BesselMNextCheb(z,2.44030308206595545468E0,b0,b1,b2); - //--- calculation - v=0.5*(b0-b2); - v=v*MathExp(-x)/MathSqrt(x); - } -//--- return result - return(v); - } -//+------------------------------------------------------------------+ -//| Modified Bessel function, second kind, order one | -//| Computes the modified Bessel function of the second kind | -//| of order one of the argument. | -//| The range is partitioned into the two intervals [0,2] and | -//| (2, infinity). Chebyshev polynomial expansions are employed | -//| in each interval. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0, 30 30000 1.2e-15 1.6e-16 | -//+------------------------------------------------------------------+ -static double CBessel::BesselK1(double x) - { -//--- create variables - double result=0; - double y=0; - double z=0; - double v=0; - double b0=0; - double b1=0; - double b2=0; -//--- initialization - z=0.5*x; -//--- check - if(!CAp::Assert(z>0.0,__FUNCTION__+": domain error")) - return(EMPTY_VALUE); -//--- check - if(x<=2.0) - { - //--- initialization - y=x*x-2.0; - //--- function calls - BesselM1FirstCheb(-7.02386347938628759343E-18,b0,b1,b2); - BesselM1NextCheb(y,-2.42744985051936593393E-15,b0,b1,b2); - BesselM1NextCheb(y,-6.66690169419932900609E-13,b0,b1,b2); - BesselM1NextCheb(y,-1.41148839263352776110E-10,b0,b1,b2); - BesselM1NextCheb(y,-2.21338763073472585583E-8,b0,b1,b2); - BesselM1NextCheb(y,-2.43340614156596823496E-6,b0,b1,b2); - BesselM1NextCheb(y,-1.73028895751305206302E-4,b0,b1,b2); - BesselM1NextCheb(y,-6.97572385963986435018E-3,b0,b1,b2); - BesselM1NextCheb(y,-1.22611180822657148235E-1,b0,b1,b2); - BesselM1NextCheb(y,-3.53155960776544875667E-1,b0,b1,b2); - BesselM1NextCheb(y,1.52530022733894777053E0,b0,b1,b2); - v=0.5*(b0-b2); - //--- get result - result=MathLog(z)*BesselI1(x)+v/x; - } - else - { - //--- initialization - y=8.0/x-2.0; - //--- function calls - BesselM1FirstCheb(-5.75674448366501715755E-18,b0,b1,b2); - BesselM1NextCheb(y,1.79405087314755922667E-17,b0,b1,b2); - BesselM1NextCheb(y,-5.68946255844285935196E-17,b0,b1,b2); - BesselM1NextCheb(y,1.83809354436663880070E-16,b0,b1,b2); - BesselM1NextCheb(y,-6.05704724837331885336E-16,b0,b1,b2); - BesselM1NextCheb(y,2.03870316562433424052E-15,b0,b1,b2); - BesselM1NextCheb(y,-7.01983709041831346144E-15,b0,b1,b2); - BesselM1NextCheb(y,2.47715442448130437068E-14,b0,b1,b2); - BesselM1NextCheb(y,-8.97670518232499435011E-14,b0,b1,b2); - BesselM1NextCheb(y,3.34841966607842919884E-13,b0,b1,b2); - BesselM1NextCheb(y,-1.28917396095102890680E-12,b0,b1,b2); - BesselM1NextCheb(y,5.13963967348173025100E-12,b0,b1,b2); - BesselM1NextCheb(y,-2.12996783842756842877E-11,b0,b1,b2); - BesselM1NextCheb(y,9.21831518760500529508E-11,b0,b1,b2); - BesselM1NextCheb(y,-4.19035475934189648750E-10,b0,b1,b2); - BesselM1NextCheb(y,2.01504975519703286596E-9,b0,b1,b2); - BesselM1NextCheb(y,-1.03457624656780970260E-8,b0,b1,b2); - BesselM1NextCheb(y,5.74108412545004946722E-8,b0,b1,b2); - BesselM1NextCheb(y,-3.50196060308781257119E-7,b0,b1,b2); - BesselM1NextCheb(y,2.40648494783721712015E-6,b0,b1,b2); - BesselM1NextCheb(y,-1.93619797416608296024E-5,b0,b1,b2); - BesselM1NextCheb(y,1.95215518471351631108E-4,b0,b1,b2); - BesselM1NextCheb(y,-2.85781685962277938680E-3,b0,b1,b2); - BesselM1NextCheb(y,1.03923736576817238437E-1,b0,b1,b2); - BesselM1NextCheb(y,2.72062619048444266945E0,b0,b1,b2); - v=0.5*(b0-b2); - //--- get result - result=MathExp(-x)*v/MathSqrt(x); - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Modified Bessel function, second kind, integer order | -//| Returns modified Bessel function of the second kind | -//| of order n of the argument. | -//| The range is partitioned into the two intervals [0,9.55] and | -//| (9.55, infinity). An ascending power series is used in the | -//| low range, and an asymptotic expansion in the high range. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0,30 90000 1.8e-8 3.0e-10 | -//| Error is high only near the crossover point x = 9.55 | -//| between the two expansions used. | -//+------------------------------------------------------------------+ -static double CBessel::BesselKN(int nn,double x) - { -//--- create variables - double k=0; - double kf=0; - double nk1f=0; - double nkf=0; - double zn=0; - double t=0; - double s=0; - double z0=0; - double z=0; - double ans=0; - double fn=0; - double pn=0; - double pk=0; - double zmn=0; - double tlg=0; - double tox=0; - int i=0; - int n=0; - double eul=0; -//--- initialization - eul=5.772156649015328606065e-1; -//--- check - if(nn<0) - n=-nn; - else - n=nn; -//--- check - if(!CAp::Assert(n<=31,__FUNCTION__+": overflow")) - return(EMPTY_VALUE); -//--- check - if(!CAp::Assert(x>0.0,__FUNCTION__+":domain error")) - return(EMPTY_VALUE); -//--- check - if(x<=9.55) - { - //--- initialization - ans=0.0; - z0=0.25*x*x; - fn=1.0; - pn=0.0; - zmn=1.0; - tox=2.0/x; - //--- check - if(n>0) - { - //--- calculation - pn=-eul; - k=1.0; - for(i=1;i<=n-1;i++) - { - pn=pn+1.0/k; - k=k+1.0; - fn=fn*k; - } - zmn=tox; - //--- check - if(n==1) - ans=1.0/x; - else - { - //--- change values - nk1f=fn/n; - kf=1.0; - s=nk1f; - z=-z0; - zn=1.0; - //--- calculation - for(i=1;i<=n-1;i++) - { - nk1f=nk1f/(n-i); - kf=kf*i; - zn=zn*z; - t=nk1f*zn/kf; - s=s+t; - //--- check - if(!CAp::Assert(CMath::m_maxrealnumber-MathAbs(t)>MathAbs(s),__FUNCTION__+": overflow")) - return(EMPTY_VALUE); - //--- check - if(!CAp::Assert(!(tox>1.0 && CMath::m_maxrealnumber/tox1.0 && CMath::m_maxrealnumber/zmn1.0 && CMath::m_maxrealnumber/tCMath::m_machineepsilon); - s=0.5*s/zmn; - //--- check - if(n%2!=0) - { - s=-s; - } - ans=ans+s; - //--- return result - return(ans); - } -//--- check - if(x>MathLog(CMath::m_maxrealnumber)) - return(0); -//--- change values - k=n; - pn=4.0*k*k; - pk=1.0; - z0=8.0*x; - fn=1.0; - t=1.0; - s=t; - nkf=CMath::m_maxrealnumber; - i=0; -//--- cycle - do - { - z=pn-pk*pk; - t=t*z/(fn*z0); - nk1f=MathAbs(t); - //--- check - if(i>=n && nk1f>(double)(nkf)) - break; - //--- change values - nkf=nk1f; - s=s+t; - fn=fn+1.0; - pk=pk+2.0; - i=i+1; - } - while(MathAbs(t/s)>CMath::m_machineepsilon); -//--- return result - return(MathExp(-x)*MathSqrt(M_PI/(2.0*x))*s); - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static void CBessel::BesselMFirstCheb(const double c,double &b0,double &b1, - double &b2) - { -//--- change values - b0=c; - b1=0.0; - b2=0.0; - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static void CBessel::BesselMNextCheb(const double x,const double c,double &b0, - double &b1,double &b2) - { -//--- change values - b2=b1; - b1=b0; - b0=x*b1-b2+c; - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static void CBessel::BesselM1FirstCheb(const double c,double &b0,double &b1, - double &b2) - { -//--- change values - b0=c; - b1=0.0; - b2=0.0; - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static void CBessel::BesselM1NextCheb(const double x,const double c,double &b0, - double &b1,double &b2) - { -//--- change values - b2=b1; - b1=b0; - b0=x*b1-b2+c; - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static void CBessel::BesselAsympt0(const double x,double &pzero,double &qzero) - { -//--- create variables - double xsq=0; - double p2=0; - double q2=0; - double p3=0; - double q3=0; -//--- initialization - pzero=0; - qzero=0; -//--- calculation - xsq=64.0/(x*x); - p2=0.0; - p2=2485.271928957404011288128951+xsq*p2; - p2=153982.6532623911470917825993+xsq*p2; - p2=2016135.283049983642487182349+xsq*p2; - p2=8413041.456550439208464315611+xsq*p2; - p2=12332384.76817638145232406055+xsq*p2; - p2=5393485.083869438325262122897+xsq*p2; - q2=1.0; - q2=2615.700736920839685159081813+xsq*q2; - q2=156001.7276940030940592769933+xsq*q2; - q2=2025066.801570134013891035236+xsq*q2; - q2=8426449.050629797331554404810+xsq*q2; - q2=12338310.22786324960844856182+xsq*q2; - q2=5393485.083869438325560444960+xsq*q2; - p3=-0.0; - p3=-4.887199395841261531199129300+xsq*p3; - p3=-226.2630641933704113967255053+xsq*p3; - p3=-2365.956170779108192723612816+xsq*p3; - p3=-8239.066313485606568803548860+xsq*p3; - p3=-10381.41698748464093880530341+xsq*p3; - p3=-3984.617357595222463506790588+xsq*p3; - q3=1.0; - q3=408.7714673983499223402830260+xsq*q3; - q3=15704.89191515395519392882766+xsq*q3; - q3=156021.3206679291652539287109+xsq*q3; - q3=533291.3634216897168722255057+xsq*q3; - q3=666745.4239319826986004038103+xsq*q3; - q3=255015.5108860942382983170882+xsq*q3; -//--- get result - pzero=p2/q2; - qzero=8*p3/q3/x; - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static void CBessel::BesselAsympt1(const double x,double &pzero,double &qzero) - { -//--- create variables - double xsq=0; - double p2=0; - double q2=0; - double p3=0; - double q3=0; -//--- initialization - pzero=0; - qzero=0; -//--- calculation - xsq=64.0/(x*x); - p2=-1611.616644324610116477412898; - p2=-109824.0554345934672737413139+xsq*p2; - p2=-1523529.351181137383255105722+xsq*p2; - p2=-6603373.248364939109255245434+xsq*p2; - p2=-9942246.505077641195658377899+xsq*p2; - p2=-4435757.816794127857114720794+xsq*p2; - q2=1.0; - q2=-1455.009440190496182453565068+xsq*q2; - q2=-107263.8599110382011903063867+xsq*q2; - q2=-1511809.506634160881644546358+xsq*q2; - q2=-6585339.479723087072826915069+xsq*q2; - q2=-9934124.389934585658967556309+xsq*q2; - q2=-4435757.816794127856828016962+xsq*q2; - p3=35.26513384663603218592175580; - p3=1706.375429020768002061283546+xsq*p3; - p3=18494.26287322386679652009819+xsq*p3; - p3=66178.83658127083517939992166+xsq*p3; - p3=85145.16067533570196555001171+xsq*p3; - p3=33220.91340985722351859704442+xsq*p3; - q3=1.0; - q3=863.8367769604990967475517183+xsq*q3; - q3=37890.22974577220264142952256+xsq*q3; - q3=400294.4358226697511708610813+xsq*q3; - q3=1419460.669603720892855755253+xsq*q3; - q3=1819458.042243997298924553839+xsq*q3; - q3=708712.8194102874357377502472+xsq*q3; -//--- get result - pzero=p2/q2; - qzero=8*p3/q3/x; - } -//+------------------------------------------------------------------+ -//| Beta function | -//+------------------------------------------------------------------+ -class CBetaF - { -public: - //--- constructor, destructor - CBetaF(void); - ~CBetaF(void); - //--- method - static double Beta(const double a,const double b); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CBetaF::CBetaF(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CBetaF::~CBetaF(void) - { - - } -//+------------------------------------------------------------------+ -//| Beta function | -//| - - | -//| | (a) | (b) | -//| beta( a, b ) = -----------. | -//| - | -//| | (a+b) | -//| For large arguments the logarithm of the function is | -//| evaluated using lgam(), then exponentiated. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0,30 30000 8.1e-14 1.1e-14 | -//+------------------------------------------------------------------+ -static double CBetaF::Beta(const double a,const double b) - { -//--- create variables - double y=0; - double sg=0; - double s=0; -//--- initialization - sg=1; -//--- check - if(!CAp::Assert(a>0.0 || a!=(double)((int)MathFloor(a)),__FUNCTION__+": overflow")) - return(EMPTY_VALUE); -//--- check - if(!CAp::Assert(b>0.0 || b!=(double)((int)MathFloor(b)),__FUNCTION__+": overflow")) - return(EMPTY_VALUE); - y=a+b; -//--- check - if(MathAbs(y)>171.624376956302725) - { - //--- calculation - y=CGammaFunc::LnGamma(y,s); - sg=sg*s; - y=CGammaFunc::LnGamma(b,s)-y; - sg=sg*s; - y=CGammaFunc::LnGamma(a,s)+y; - sg=sg*s; - //--- check - if(!CAp::Assert(y<=(double)(MathLog(CMath::m_maxrealnumber)),__FUNCTION__+": overflow")) - return(EMPTY_VALUE); - //--- return result - return(sg*MathExp(y)); - } -//--- function call - y=CGammaFunc::GammaFunc(y); -//--- check - if(!CAp::Assert(y!=0.0,"Overflow in Beta")) - return(EMPTY_VALUE); -//--- check - if(a>b) - { - //--- calculation - y=CGammaFunc::GammaFunc(a)/y; - y=y*CGammaFunc::GammaFunc(b); - } - else - { - //--- calculation - y=CGammaFunc::GammaFunc(b)/y; - y=y*CGammaFunc::GammaFunc(a); - } -//--- return result - return(y); - } -//+------------------------------------------------------------------+ -//| Incomplete beta function | -//+------------------------------------------------------------------+ -class CIncBetaF - { -private: - //--- private methods - static double IncompleteBetaFracExpans(const double a,const double b,const double x,const double big,const double biginv); - static double IncompleteBetaFracExpans2(const double a,const double b,const double x,const double big,const double biginv); - static double IncompleteBetaPowSeries(const double a,const double b,const double x,const double maxgam); -public: - //--- constructor, destructor - CIncBetaF(void); - ~CIncBetaF(void); - //--- public methods - static double IncompleteBeta(double a,double b,double x); - static double InvIncompleteBeta(const double a,double b,double y); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CIncBetaF::CIncBetaF(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CIncBetaF::~CIncBetaF(void) - { - - } -//+------------------------------------------------------------------+ -//| Incomplete beta integral | -//| Returns incomplete beta integral of the arguments, evaluated | -//| from zero to x. The function is defined as | -//| x | -//| - - | -//| | (a+b) | | a-1 b-1 | -//| ----------- | t (1-t) dt. | -//| - - | | | -//| | (a) | (b) - | -//| 0 | -//| The domain of definition is 0 <= x <= 1. In this | -//| implementation a and b are restricted to positive values. | -//| The integral from x to 1 may be obtained by the symmetry | -//| relation | -//| 1 - incbet( a, b, x ) = incbet( b, a, 1-x ). | -//| The integral is evaluated by a continued fraction expansion | -//| or, when b*x is small, by a power series. | -//| ACCURACY: | -//| Tested at uniformly distributed random points (a,b,x) with a and | -//| b in "domain" and x between 0 and 1. | -//| Relative error | -//| arithmetic domain # trials peak rms | -//| IEEE 0,5 10000 6.9e-15 4.5e-16 | -//| IEEE 0,85 250000 2.2e-13 1.7e-14 | -//| IEEE 0,1000 30000 5.3e-12 6.3e-13 | -//| IEEE 0,10000 250000 9.3e-11 7.1e-12 | -//| IEEE 0,100000 10000 8.7e-10 4.8e-11 | -//| Outputs smaller than the IEEE gradual underflow threshold | -//| were excluded from these statistics. | -//+------------------------------------------------------------------+ -static double CIncBetaF::IncompleteBeta(double a,double b,double x) - { -//--- check - if(!CAp::Assert(a>0 && b>0,__FUNCTION__+": the error variable")) - return(EMPTY_VALUE); -//--- check - if(!CAp::Assert(x>=0 && x<=1,__FUNCTION__+": the error variable")) - return(EMPTY_VALUE); -//--- check - if(x==0) - return(0); -//--- check - if(x==1) - return(1); -//--- create variables - double t; - double xc; - double w; - double y; - int flag=0; - double sg=0; - double big=4.503599627370496e15; - double biginv=2.22044604925031308085e-16; - double maxgam=171.624376956302725; - double minlog=MathLog(CMath::m_minrealnumber); - double maxlog=MathLog(CMath::m_maxrealnumber); - -//--- check - if(b*x<=1.0 && x<=0.95) - return(IncompleteBetaPowSeries(a,b,x,maxgam)); -//--- change value - w=1.0-x; -//--- check - if(x>a/(a+b)) - { - flag=1; - t=a; - a=b; - b=t; - xc=x; - x=w; - } - else - xc=w; -//--- check - if(flag==1 && b*x<=1.0 && x<=0.95) - { - t=IncompleteBetaPowSeries(a,b,x,maxgam); - //--- check - if(t<=CMath::m_machineepsilon) - return(1.0-CMath::m_machineepsilon); - else - return(1.0-t); - } -//--- change value - y=x*(a+b-2.0)-(a-1.0); -//--- check - if(y<0.0) - w=IncompleteBetaFracExpans(a,b,x,big,biginv); - else - w=IncompleteBetaFracExpans2(a,b,x,big,biginv)/xc; -//--- change values - y=a*MathLog(x); - t=b*MathLog(xc); -//--- check - if(a+b=0 && y<=1,__FUNCTION__+": the error variable")) - return(EMPTY_VALUE); -//--- check - if(y==0) - return(0); -//--- check - if(y==1.0) - return(1); -//--- create variables - double aaa=0; - double bbb=0; - double y0=0; - double d=0; - double yyy=0; - double x=0; - double x0=0.0; - double x1=1.0; - double lgm=0; - double yp=0; - double di=0; - double dithresh=0; - double yl=0.0; - double yh=1.0; - double xt=0; - int i=0; - int rflg=0; - int dir=0; - int nflg=0; - double s=0; - int mainlooppos=0; - int ihalve=1; - int ihalvecycle=2; - int newt=3; - int newtcycle=4; - int breaknewtcycle=5; - int breakihalvecycle=6; -//--- main - while(true) - { - //--- start - if(mainlooppos==0) - { - if(a<=1.0 || b<=1.0) - { - dithresh=1.0e-6; - rflg=0; - aaa=a; - bbb=b; - y0=y; - x=aaa/(aaa+bbb); - yyy=IncompleteBeta(aaa,bbb,x); - mainlooppos=ihalve; - continue; - } - else - dithresh=1.0e-4; - //--- change value - yp=-CNormalDistr::InvNormalDistribution(y); - //--- check - if(y>0.5) - { - rflg=1; - aaa=b; - bbb=a; - y0=1.0-y; - yp=-yp; - } - else - { - rflg=0; - aaa=a; - bbb=b; - y0=y; - } - //--- change values - lgm=(yp*yp-3.0)/6.0; - x=2.0/(1.0/(2.0*aaa-1.0)+1.0/(2.0*bbb-1.0)); - d=yp*MathSqrt(x+lgm)/x-(1.0/(2.0*bbb-1.0)-1.0/(2.0*aaa-1.0))*(lgm+5.0/6.0-2.0/(3.0*x)); - d=2.0*d; - //--- check - if(d3) - di=1.0-(1.0-di)*(1.0-di); - else - { - //--- check - if(dir>1) - di=0.5*di+0.5; - else - di=(y0-yyy)/(yh-yl); - } - } - dir++; - //--- check - if(x0>0.75) - { - //--- check - if(rflg==1) - { - rflg=0; - aaa=a; - bbb=b; - y0=y; - } - else - { - rflg=1; - aaa=b; - bbb=a; - y0=1.0-y; - } - //--- change values - x=1.0-x; - yyy=IncompleteBeta(aaa,bbb,x); - x0=0.0; - yl=0.0; - x1=1.0; - yh=1.0; - mainlooppos=ihalve; - continue; - } - } - else - { - x1=x; - //--- check - if(rflg==1 && x10) - { - dir=0; - di=0.5; - } - else - { - //--- check - if(dir<-3) - di*=di; - else - { - //--- check - if(dir<-1) - di*=0.5; - else - di=(yyy-y0)/(yh-yl); - } - } - dir--; - } - i++; - mainlooppos=ihalvecycle; - continue; - } - else - { - mainlooppos=breakihalvecycle; - continue; - } - } - //--- check - if(mainlooppos==breakihalvecycle) - { - //--- check - if(x0>=1.0) - { - x=1.0-CMath::m_machineepsilon; - break; - } - //--- check - if(x<=0.0) - { - x=0.0; - break; - } - mainlooppos=newt; - continue; - } - //--- check - if(mainlooppos==newt) - { - if(nflg!=0) - break; - //--- change values - nflg=1; - lgm=CGammaFunc::LnGamma(aaa+bbb,s)-CGammaFunc::LnGamma(aaa,s)-CGammaFunc::LnGamma(bbb,s); - i=0; - mainlooppos=newtcycle; - continue; - } - //--- check - if(mainlooppos==newtcycle) - { - //--- check - if(i<=7) - { - //--- check - if(i!=0) - yyy=IncompleteBeta(aaa,bbb,x); - //--- check - if(yyyyh) - { - x=x1; - yyy=yh; - } - else - { - //--- check - if(yyyMathLog(CMath::m_maxrealnumber)) - { - mainlooppos=breaknewtcycle; - continue; - } - //--- change values - d=MathExp(d); - d=(yyy-y0)/d; - xt=x-d; - //--- check - if(xt<=x0) - { - yyy=(x-x0)/(x1-x0); - xt=x0+0.5*yyy*(x-x0); - //--- check - if(xt<=0.0) - { - mainlooppos=breaknewtcycle; - continue; - } - } - //--- check - if(xt>=x1) - { - yyy=(x1-x)/(x1-x0); - xt=x1-0.5*yyy*(x1-x); - //--- check - if(xt>=1.0) - { - mainlooppos=breaknewtcycle; - continue; - } - } - x=xt; - //--- check - if(MathAbs(d/x)<128.0*CMath::m_machineepsilon) - break; - //--- change values - i=i+1; - mainlooppos=newtcycle; - continue; - } - else - { - mainlooppos=breaknewtcycle; - continue; - } - } - //--- check - if(mainlooppos==breaknewtcycle) - { - dithresh=256.0*CMath::m_machineepsilon; - mainlooppos=ihalve; - continue; - } - } -//--- get result - if(rflg!=0) - { - if(x<=CMath::m_machineepsilon) - x=1.0-CMath::m_machineepsilon; - else - x=1.0-x; - } -//--- return result - return(x); - } -//+------------------------------------------------------------------+ -//| Continued fraction expansion #1 for incomplete beta integral | -//+------------------------------------------------------------------+ -static double CIncBetaF::IncompleteBetaFracExpans(const double a,const double b, - const double x,const double big, - const double biginv) - { -//--- create variables - double xk=0; - double pk=0; - double pkm1=1.0; - double pkm2=0.0; - double qk=0; - double qkm1=1.0; - double qkm2=1.0; - double k1=a; - double k2=a+b; - double k3=a; - double k4=a+1.0; - double k5=1.0; - double k6=b-1.0; - double k7=k4; - double k8=a+2.0; - double r=1.0; - double t=0; - double ans=1.0; - double thresh=3.0*CMath::m_machineepsilon; - int n=0; -//--- cycle - do - { - xk=-(x*k1*k2/(k3*k4)); - pk=pkm1+pkm2*xk; - qk=qkm1+qkm2*xk; - pkm2=pkm1; - pkm1=pk; - qkm2=qkm1; - qkm1=qk; - xk=x*k5*k6/(k7*k8); - pk=pkm1+pkm2*xk; - qk=qkm1+qkm2*xk; - pkm2=pkm1; - pkm1=pk; - qkm2=qkm1; - qkm1=qk; - //--- check - if(qk!=0) - r=pk/qk; - //--- check - if(r!=0) - { - t=MathAbs((ans-r)/r); - ans=r; - } - else - t=1.0; - //--- check - if(tbig) - { - pkm2*=biginv; - pkm1*=biginv; - qkm2*=biginv; - qkm1*=biginv; - } - //--- check - if(MathAbs(qk)big) - { - pkm2*=biginv; - pkm1*=biginv; - qkm2*=biginv; - qkm1*=biginv; - } - //--- check - if(MathAbs(qk)z) - { - u=(n-b)*x/n; - t=t*u; - v=t/(a+n); - s=s+v; - n=n+1.0; - } -//--- change values - s+=t1; - s+=ai; - u=a*MathLog(x); -//--- check - if(a+b ( ) p (1-p) | -//| -- ( j ) | -//| j=0 | -//| The terms are not summed directly; instead the incomplete | -//| beta integral is employed, according to the formula | -//| y = bdtr( k, n, p ) = incbet( n-k, k+1, 1-p ). | -//| The arguments must be positive, with p ranging from 0 to 1. | -//| ACCURACY: | -//| Tested at random points (a,b,p), with p between 0 and 1. | -//| a,b Relative error: | -//| arithmetic domain # trials peak rms | -//| For p between 0.001 and 1: | -//| IEEE 0,100 100000 4.3e-15 2.6e-16 | -//+------------------------------------------------------------------+ -static double CBinomialDistr::BinomialDistribution(const int k,const int n, - const double p) - { -//--- check - if(!CAp::Assert(p>=0 && p<=1,__FUNCTION__+": the eroor variable")) - return(EMPTY_VALUE); -//--- check - if(!CAp::Assert(k>=-1 && k<=n,__FUNCTION__+": the eroor variable")) - return(EMPTY_VALUE); -//--- check - if(k==-1) - return(0); -//--- check - if(k==n) - return(1); -//--- create variables - double dk; - double dn=n-k; -//--- check - if(k==0) - dk=MathPow(1.0-p,dn); - else - { - dk=k+1; - dk=CIncBetaF::IncompleteBeta(dn,dk,1.0-p); - } -//--- return result - return(dk); - } -//+------------------------------------------------------------------+ -//| Complemented binomial distribution | -//| Returns the sum of the terms k+1 through n of the Binomial | -//| probability density: | -//| n | -//| -- ( n ) j n-j | -//| > ( ) p (1-p) | -//| -- ( j ) | -//| j=k+1 | -//| The terms are not summed directly; instead the incomplete | -//| beta integral is employed, according to the formula | -//| y = bdtrc( k, n, p ) = incbet( k+1, n-k, p ). | -//| The arguments must be positive, with p ranging from 0 to 1. | -//| ACCURACY: | -//| Tested at random points (a,b,p). | -//| a,b Relative error: | -//| arithmetic domain # trials peak rms | -//| For p between 0.001 and 1: | -//| IEEE 0,100 100000 6.7e-15 8.2e-16 | -//| For p between 0 and .001: | -//| IEEE 0,100 100000 1.5e-13 2.7e-15 | -//+------------------------------------------------------------------+ -static double CBinomialDistr::BinomialComplDistribution(const int k, - const int n, - const double p) - { -//--- check - if(!CAp::Assert(p>=0 && p<=1,__FUNCTION__+": the eroor variable")) - return(EMPTY_VALUE); -//--- check - if(!CAp::Assert(k>=-1 && k<=n,__FUNCTION__+": the eroor variable")) - return(EMPTY_VALUE); -//--- check - if(k==-1) - return(0); -//--- check - if(k==n) - return(1); -//--- create variables - double dk; - double dn=n-k; -//--- check - if(k==0) - dk=MathPow(1.0-p,dn); - else - { - dk=k+1; - dk=CIncBetaF::IncompleteBeta(dn,dk,1.0-p); - } -//--- return result - return(dk); - } -//+------------------------------------------------------------------+ -//| Inverse binomial distribution | -//| Finds the event probability p such that the sum of the | -//| terms 0 through k of the Binomial probability density | -//| is equal to the given cumulative probability y. | -//| This is accomplished using the inverse beta integral | -//| function and the relation | -//| 1 - p = incbi( n-k, k+1, y ). | -//| ACCURACY: | -//| Tested at random points (a,b,p). | -//| a,b Relative error: | -//| arithmetic domain # trials peak rms | -//| For p between 0.001 and 1: | -//| IEEE 0,100 100000 2.3e-14 6.4e-16 | -//| IEEE 0,10000 100000 6.6e-12 1.2e-13 | -//| For p between 10^-6 and 0.001: | -//| IEEE 0,100 100000 2.0e-12 1.3e-14 | -//| IEEE 0,10000 100000 1.5e-12 3.2e-14 | -//+------------------------------------------------------------------+ -static double CBinomialDistr::InvBinomialDistribution(const int k,const int n, - const double y) - { -//--- create variables - double dk=0; - double dn=0; - double p=0; -//--- check - if(!CAp::Assert(k>=0 && k0.8) - p=-CNearUnitYUnit::NUExp1m(CNearUnitYUnit::NULog1p(y-1.0)/dn); - else - p=1.0-MathPow(y,1.0/dn); - } - else - { - dk=k+1; - //--- function call - p=CIncBetaF::IncompleteBeta(dn,dk,0.5); - //--- check - if(p>0.5) - p=CIncBetaF::InvIncompleteBeta(dk,dn,1.0-y); - else - p=1.0-CIncBetaF::InvIncompleteBeta(dn,dk,y); - } -//--- return result - return(p); - } -//+------------------------------------------------------------------+ -//| Chebyshev polynomials | -//+------------------------------------------------------------------+ -class CChebyshev - { -public: - //--- constructor, destructor - CChebyshev(void); - ~CChebyshev(void); - //--- methods - static double ChebyshevCalculate(const int r,const int n,const double x); - static double ChebyshevSum(double &c[],const int r,const int n,const double x); - static void ChebyshevCoefficients(const int n,double &c[]); - static void FromChebyshev(double &a[],const int n,double &b[]); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CChebyshev::CChebyshev(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CChebyshev::~CChebyshev(void) - { - - } -//+------------------------------------------------------------------+ -//| Calculation of the value of the Chebyshev polynomials of the | -//| first and second kinds. | -//| Parameters: | -//| r - polynomial kind, either 1 or 2. | -//| n - degree, n>=0 | -//| x - argument, -1 <= x <= 1 | -//| Result: | -//| the value of the Chebyshev polynomial at x | -//+------------------------------------------------------------------+ -static double CChebyshev::ChebyshevCalculate(const int r,const int n, - const double x) - { -//--- create variables - double result=0; - int i=0; - double a=0; - double b=0; -//--- Prepare A and B - if(r==1) - { - a=1; - b=x; - } - else - { - a=1; - b=2*x; - } -//--- Special cases: N=0 or N=1 - if(n==0) - return(a); -//--- check - if(n==1) - return(b); -//--- General case: N>=2 - for(i=2;i<=n;i++) - { - result=2*x*b-a; - a=b; - b=result; - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Summation of Chebyshev polynomials using Clenshaw?s recurrence | -//| formula. | -//| This routine calculates | -//| c[0]*T0(x) + c[1]*T1(x) + ... + c[N]*TN(x) | -//| or | -//| c[0]*U0(x) + c[1]*U1(x) + ... + c[N]*UN(x) | -//| depending on the R. | -//| Parameters: | -//| r - polynomial kind, either 1 or 2. | -//| n - degree, n>=0 | -//| x - argument | -//| Result: | -//| the value of the Chebyshev polynomial at x | -//+------------------------------------------------------------------+ -static double CChebyshev::ChebyshevSum(double &c[],const int r,const int n, - const double x) - { -//--- create variables - double result=0; - double b1=0; - double b2=0; - int i=0; -//--- initialization - b1=0; - b2=0; -//--- calculation - for(i=n;i>=1;i--) - { - result=2*x*b1-b2+c[i]; - b2=b1; - b1=result; - } -//--- check - if(r==1) - result=-b2+x*b1+c[0]; - else - result=-b2+2*x*b1+c[0]; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Representation of Tn as C[0] + C[1]*X + ... + C[N]*X^N | -//| Input parameters: | -//| N - polynomial degree, n>=0 | -//| Output parameters: | -//| C - coefficients | -//+------------------------------------------------------------------+ -static void CChebyshev::ChebyshevCoefficients(const int n,double &c[]) - { -//--- create a variable - int i=0; -//--- allocation - ArrayResizeAL(c,n+1); - for(i=0;i<=n;i++) - c[i]=0; -//--- check - if(n==0 || n==1) - c[n]=1; - else - { - c[n]=MathExp((n-1)*MathLog(2)); - //--- calculation - for(i=0;i<=n/2-1;i++) - c[n-2*(i+1)]=-(c[n-2*i]*(n-2*i)*(n-2*i-1)/4/(i+1)/(n-i-1)); - } - } -//+------------------------------------------------------------------+ -//| Conversion of a series of Chebyshev polynomials to a power | -//| series. | -//| Represents A[0]*T0(x) + A[1]*T1(x) + ... + A[N]*Tn(x) as | -//| B[0] + B[1]*X + ... + B[N]*X^N. | -//| Input parameters: | -//| A - Chebyshev series coefficients | -//| N - degree, N>=0 | -//| Output parameters | -//| B - power series coefficients | -//+------------------------------------------------------------------+ -static void CChebyshev::FromChebyshev(double &a[],const int n,double &b[]) - { -//--- create variables - int i=0; - int k=0; - double e=0; - double d=0; -//--- allocation - ArrayResizeAL(b,n+1); -//--- initialization - for(i=0;i<=n;i++) - b[i]=0; -//--- calculation - d=0; - i=0; - do - { - k=i; - //--- cycle - do - { - e=b[k]; - b[k]=0; - //--- check - if(i<=1 && k==i) - b[k]=1; - else - { - //--- check - if(i!=0) - b[k]=2*d; - //--- check - if(k>i+1) - b[k]=b[k]-b[k-2]; - } - //--- change values - d=e; - k=k+1; - } - while(k<=n); - //--- change values - d=b[i]; - e=0; - k=i; - //--- calculation - while(k<=n) - { - e=e+b[k]*a[k]; - k=k+2; - } - //--- change values - b[i]=e; - i=i+1; - } - while(i<=n); - } -//+------------------------------------------------------------------+ -//| Chi-square distribution | -//+------------------------------------------------------------------+ -class CChiSquareDistr - { -public: - //--- constructor, destructor - CChiSquareDistr(void); - ~CChiSquareDistr(void); - //--- methods - static double ChiSquareDistribution(const double v,const double x); - static double ChiSquareComplDistribution(const double v,const double x); - static double InvChiSquareDistribution(const double v,const double y); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CChiSquareDistr::CChiSquareDistr(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CChiSquareDistr::~CChiSquareDistr(void) - { - - } -//+------------------------------------------------------------------+ -//| Chi-square distribution | -//| Returns the area under the left hand tail (from 0 to x) | -//| of the Chi square probability density function with | -//| v degrees of freedom. | -//| x | -//| - | -//| 1 | | v/2-1 -t/2 | -//| P( x | v ) = ----------- | t e dt | -//| v/2 - | | | -//| 2 | (v/2) - | -//| 0 | -//| where x is the Chi-square variable. | -//| The incomplete gamma integral is used, according to the | -//| formula | -//| y = chdtr( v, x ) = igam( v/2.0, x/2.0 ). | -//| The arguments must both be positive. | -//| ACCURACY: | -//| See incomplete gamma function | -//+------------------------------------------------------------------+ -static double CChiSquareDistr::ChiSquareDistribution(const double v, - const double x) - { -//--- check - if(!CAp::Assert(x>=0 && v>=1,__FUNCTION__+": the error variable")) - return(EMPTY_VALUE); -//--- return result - return(CIncGammaF::IncompleteGamma(v/2.0,x/2.0)); - } -//+------------------------------------------------------------------+ -//| Complemented Chi-square distribution | -//| Returns the area under the right hand tail (from x to | -//| infinity) of the Chi square probability density function | -//| with v degrees of freedom: | -//| inf. | -//| - | -//| 1 | | v/2-1 -t/2 | -//| P( x | v ) = ----------- | t e dt | -//| v/2 - | | | -//| 2 | (v/2) - | -//| x | -//| where x is the Chi-square variable. | -//| The incomplete gamma integral is used, according to the | -//| formula | -//| y = chdtr( v, x ) = igamc( v/2.0, x/2.0 ). | -//| The arguments must both be positive. | -//| ACCURACY: | -//| See incomplete gamma function | -//+------------------------------------------------------------------+ -static double CChiSquareDistr::ChiSquareComplDistribution(const double v, - const double x) - { -//--- check - if(!CAp::Assert(x>=0.0 && v>=1.0,__FUNCTION__+": domain error")) - return(EMPTY_VALUE); -//--- return result - return(CIncGammaF::IncompleteGammaC(v/2.0,x/2.0)); - } -//+------------------------------------------------------------------+ -//| Inverse of complemented Chi-square distribution | -//| Finds the Chi-square argument x such that the integral | -//| from x to infinity of the Chi-square density is equal | -//| to the given cumulative probability y. | -//| This is accomplished using the inverse gamma integral | -//| function and the relation | -//| x/2 = igami( df/2, y ); | -//| ACCURACY: | -//| See inverse incomplete gamma function | -//+------------------------------------------------------------------+ -static double CChiSquareDistr::InvChiSquareDistribution(const double v, - const double y) - { -//--- check - if(!CAp::Assert((y>=0.0 && y<=1.0) && v>=1.0,__FUNCTION__+": domain error")) - return(EMPTY_VALUE); -//--- return result - return(2*CIncGammaF::InvIncompleteGammaC(0.5*v,y)); - } -//+------------------------------------------------------------------+ -//| Dawson integral | -//+------------------------------------------------------------------+ -class CDawson - { -public: - //--- constructor, destructor - CDawson(void); - ~CDawson(void); - //--- method - static double DawsonIntegral(double x); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CDawson::CDawson(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CDawson::~CDawson(void) - { - - } -//+------------------------------------------------------------------+ -//| Dawson's Integral | -//| Approximates the integral | -//| x | -//| - | -//| 2 | | 2 | -//| dawsn(x) = exp( -x ) | exp( t ) dt | -//| | | | -//| - | -//| 0 | -//| Three different rational approximations are employed, for | -//| the intervals 0 to 3.25; 3.25 to 6.25; and 6.25 up. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0,10 10000 6.9e-16 1.0e-16 | -//+------------------------------------------------------------------+ -static double CDawson::DawsonIntegral(double x) - { -//--- create variables - double result=0; - double x2=0; - double y=0; - int sg=0; - double an=0; - double ad=0; - double bn=0; - double bd=0; - double cn=0; - double cd=0; -//--- initialization - sg=1; -//--- check - if(x<0.0) - { - sg=-1; - x=-x; - } -//--- check - if(x<3.25) - { - //--- calculation - x2=x*x; - an=1.13681498971755972054E-11; - an=an*x2+8.49262267667473811108E-10; - an=an*x2+1.94434204175553054283E-8; - an=an*x2+9.53151741254484363489E-7; - an=an*x2+3.07828309874913200438E-6; - an=an*x2+3.52513368520288738649E-4; - an=an*x2+-8.50149846724410912031E-4; - an=an*x2+4.22618223005546594270E-2; - an=an*x2+-9.17480371773452345351E-2; - an=an*x2+9.99999999999999994612E-1; - ad=2.40372073066762605484E-11; - ad=ad*x2+1.48864681368493396752E-9; - ad=ad*x2+5.21265281010541664570E-8; - ad=ad*x2+1.27258478273186970203E-6; - ad=ad*x2+2.32490249820789513991E-5; - ad=ad*x2+3.25524741826057911661E-4; - ad=ad*x2+3.48805814657162590916E-3; - ad=ad*x2+2.79448531198828973716E-2; - ad=ad*x2+1.58874241960120565368E-1; - ad=ad*x2+5.74918629489320327824E-1; - ad=ad*x2+1.00000000000000000539E0; - y=x*an/ad; - //--- return result - return(sg*y); - } - x2=1.0/(x*x); -//--- check - if(x<6.25) - { - //--- calculation - bn=5.08955156417900903354E-1; - bn=bn*x2-2.44754418142697847934E-1; - bn=bn*x2+9.41512335303534411857E-2; - bn=bn*x2-2.18711255142039025206E-2; - bn=bn*x2+3.66207612329569181322E-3; - bn=bn*x2-4.23209114460388756528E-4; - bn=bn*x2+3.59641304793896631888E-5; - bn=bn*x2-2.14640351719968974225E-6; - bn=bn*x2+9.10010780076391431042E-8; - bn=bn*x2-2.40274520828250956942E-9; - bn=bn*x2+3.59233385440928410398E-11; - bd=1.00000000000000000000E0; - bd=bd*x2-6.31839869873368190192E-1; - bd=bd*x2+2.36706788228248691528E-1; - bd=bd*x2-5.31806367003223277662E-2; - bd=bd*x2+8.48041718586295374409E-3; - bd=bd*x2-9.47996768486665330168E-4; - bd=bd*x2+7.81025592944552338085E-5; - bd=bd*x2-4.55875153252442634831E-6; - bd=bd*x2+1.89100358111421846170E-7; - bd=bd*x2-4.91324691331920606875E-9; - bd=bd*x2+7.18466403235734541950E-11; - y=1.0/x+x2*bn/(bd*x); - //--- return result - return(sg*0.5*y); - } -//--- check - if(x>1.0E9) - return(sg*0.5/x); -//--- calculation - cn=-5.90592860534773254987E-1; - cn=cn*x2+6.29235242724368800674E-1; - cn=cn*x2-1.72858975380388136411E-1; - cn=cn*x2+1.64837047825189632310E-2; - cn=cn*x2-4.86827613020462700845E-4; - cd=1.00000000000000000000E0; - cd=cd*x2-2.69820057197544900361E0; - cd=cd*x2+1.73270799045947845857E0; - cd=cd*x2-3.93708582281939493482E-1; - cd=cd*x2+3.44278924041233391079E-2; - cd=cd*x2-9.73655226040941223894E-4; - y=1.0/x+x2*cn/(cd*x); -//--- return result - return(sg*0.5*y); - } -//+------------------------------------------------------------------+ -//| Elliptic integral | -//+------------------------------------------------------------------+ -class CElliptic - { -public: - //--- constructor, destructor - CElliptic(void); - ~CElliptic(void); - //--- methods - static double EllipticIntegralK(const double m); - static double EllipticIntegralKhighPrecision(const double m1); - static double IncompleteEllipticIntegralK(double phi,const double m); - static double EllipticIntegralE(double m); - static double IncompleteEllipticIntegralE(const double phi,const double m); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CElliptic::CElliptic(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CElliptic::~CElliptic(void) - { - - } -//+------------------------------------------------------------------+ -//| Complete elliptic integral of the first kind | -//| Approximates the integral | -//| pi/2 | -//| - | -//| | | | -//| | dt | -//| K(m) = | ------------------ | -//| | 2 | -//| | | sqrt( 1 - m sin t ) | -//| - | -//| 0 | -//| using the approximation | -//| P(x) - log x Q(x). | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0,1 30000 2.5e-16 6.8e-17 | -//+------------------------------------------------------------------+ -static double CElliptic::EllipticIntegralK(const double m) - { -//--- return result - return(EllipticIntegralKhighPrecision(1.0-m)); - } -//+------------------------------------------------------------------+ -//| Complete elliptic integral of the first kind | -//| Approximates the integral | -//| pi/2 | -//| - | -//| | | | -//| | dt | -//| K(m) = | ------------------ | -//| | 2 | -//| | | sqrt( 1 - m sin t ) | -//| - | -//| 0 | -//| where m = 1 - m1, using the approximation | -//| P(x) - log x Q(x). | -//| The argument m1 is used rather than m so that the logarithmic | -//| singularity at m = 1 will be shifted to the origin; this | -//| preserves maximum accuracy. | -//| K(0) = pi/2. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0,1 30000 2.5e-16 6.8e-17 | -//+------------------------------------------------------------------+ -static double CElliptic::EllipticIntegralKhighPrecision(const double m1) - { -//--- create variables - double result=0; - double p=0; - double q=0; -//--- check - if(m1<=CMath::m_machineepsilon) - result=1.3862943611198906188E0-0.5*MathLog(m1); - else - { - //--- calculation - p=1.37982864606273237150E-4; - p=p*m1+2.28025724005875567385E-3; - p=p*m1+7.97404013220415179367E-3; - p=p*m1+9.85821379021226008714E-3; - p=p*m1+6.87489687449949877925E-3; - p=p*m1+6.18901033637687613229E-3; - p=p*m1+8.79078273952743772254E-3; - p=p*m1+1.49380448916805252718E-2; - p=p*m1+3.08851465246711995998E-2; - p=p*m1+9.65735902811690126535E-2; - p=p*m1+1.38629436111989062502E0; - q=2.94078955048598507511E-5; - q=q*m1+9.14184723865917226571E-4; - q=q*m1+5.94058303753167793257E-3; - q=q*m1+1.54850516649762399335E-2; - q=q*m1+2.39089602715924892727E-2; - q=q*m1+3.01204715227604046988E-2; - q=q*m1+3.73774314173823228969E-2; - q=q*m1+4.88280347570998239232E-2; - q=q*m1+7.03124996963957469739E-2; - q=q*m1+1.24999999999870820058E-1; - q=q*m1+4.99999999999999999821E-1; - //--- get result - result=p-q*MathLog(m1); - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Incomplete elliptic integral of the first kind F(phi|m) | -//| Approximates the integral | -//| phi | -//| - | -//| | | | -//| | dt | -//| F(phi_\m) = | ------------------ | -//| | 2 | -//| | | sqrt( 1 - m sin t ) | -//| - | -//| 0 | -//| of amplitude phi and modulus m, using the arithmetic - | -//| geometric mean algorithm. | -//| ACCURACY: | -//| Tested at random points with m in [0, 1] and phi as indicated. | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE -10,10 200000 7.4e-16 1.0e-16 | -//+------------------------------------------------------------------+ -static double CElliptic::IncompleteEllipticIntegralK(double phi,const double m) - { -//--- create variables - double a=0; - double b=0; - double c=0; - double e=0; - double temp=0; - double pio2=0; - double t=0; - double k=0; - int d=0; - int md=0; - int s=0; - int npio2=0; -//--- initialization - pio2=1.57079632679489661923; -//--- check - if(m==0.0) - return(phi); -//--- initialization - a=1-m; -//--- check - if(a==0.0) - return(MathLog(MathTan(0.5*(pio2+phi)))); -//--- initialization - npio2=(int)MathFloor(phi/pio2); -//--- check - if(npio2%2!=0) - npio2=npio2+1; -//--- check - if(npio2!=0) - { - k=EllipticIntegralK(1-a); - phi=phi-npio2*pio2; - } - else - k=0; -//--- check - if(phi<0.0) - { - phi=-phi; - s=-1; - } - else - s=0; -//--- calculation - b=MathSqrt(a); - t=MathTan(phi); -//--- check - if(MathAbs(t)>10) - { - e=1.0/(b*t); - //--- check - if(MathAbs(e)<10) - { - e=MathArctan(e); - //--- check - if(npio2==0) - k=EllipticIntegralK(1-a); - //--- function call - temp=k-IncompleteEllipticIntegralK(e,m); - //--- check - if(s<0) - temp=-temp; - //--- return result - return(temp+npio2*k); - } - } -//--- change values - a=1.0; - c=MathSqrt(m); - d=1; - md=0; -//--- cycle - while(MathAbs(c/a)>CMath::m_machineepsilon) - { - //--- calculation - temp=b/a; - phi=phi+MathArctan(t*temp)+md*M_PI; - md=(int)((phi+pio2)/M_PI); - t=t*(1.0+temp)/(1.0-temp*t*t); - c=0.5*(a-b); - temp=MathSqrt(a*b); - a=0.5*(a+b); - b=temp; - d=d+d; - } -//--- change value - temp=(MathArctan(t)+md*M_PI)/(d*a); -//--- check - if(s<0) - temp=-temp; -//--- return result - return(temp+npio2*k); - } -//+------------------------------------------------------------------+ -//| Complete elliptic integral of the second kind | -//| Approximates the integral | -//| pi/2 | -//| - | -//| | | 2 | -//| E(m) = | sqrt( 1 - m sin t ) dt | -//| | | | -//| - | -//| 0 | -//| using the approximation | -//| P(x) - x log x Q(x). | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0, 1 10000 2.1e-16 7.3e-17 | -//+------------------------------------------------------------------+ -static double CElliptic::EllipticIntegralE(double m) - { -//--- create variables - double p=0; - double q=0; -//--- check - if(!CAp::Assert(m>=0.0 && m<=1.0,__FUNCTION__+": m<0 or m>1")) - return(EMPTY_VALUE); -//--- change value - m=1-m; -//--- check - if(m==0.0) - return(1); -//--- calculation - p=1.53552577301013293365E-4; - p=p*m+2.50888492163602060990E-3; - p=p*m+8.68786816565889628429E-3; - p=p*m+1.07350949056076193403E-2; - p=p*m+7.77395492516787092951E-3; - p=p*m+7.58395289413514708519E-3; - p=p*m+1.15688436810574127319E-2; - p=p*m+2.18317996015557253103E-2; - p=p*m+5.68051945617860553470E-2; - p=p*m+4.43147180560990850618E-1; - p=p*m+1.00000000000000000299E0; - q=3.27954898576485872656E-5; - q=q*m+1.00962792679356715133E-3; - q=q*m+6.50609489976927491433E-3; - q=q*m+1.68862163993311317300E-2; - q=q*m+2.61769742454493659583E-2; - q=q*m+3.34833904888224918614E-2; - q=q*m+4.27180926518931511717E-2; - q=q*m+5.85936634471101055642E-2; - q=q*m+9.37499997197644278445E-2; - q=q*m+2.49999999999888314361E-1; -//--- return result - return(p-q*m*MathLog(m)); - } -//+------------------------------------------------------------------+ -//| Incomplete elliptic integral of the second kind | -//| Approximates the integral | -//| phi | -//| - | -//| | | | -//| | 2 | -//| E(phi_\m) = | sqrt( 1 - m sin t ) dt | -//| | | -//| | | | -//| - | -//| 0 | -//| of amplitude phi and modulus m, using the arithmetic - | -//| geometric mean algorithm. | -//| ACCURACY: | -//| Tested at random arguments with phi in [-10, 10] and m in | -//| [0, 1]. | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE -10,10 150000 3.3e-15 1.4e-16 | -//+------------------------------------------------------------------+ -static double CElliptic::IncompleteEllipticIntegralE(const double phi, - const double m) - { -//--- create variables - double pio2=0; - double a=0; - double b=0; - double c=0; - double e=0; - double temp=0; - double lphi=0; - double t=0; - double ebig=0; - int d=0; - int md=0; - int npio2=0; - int s=0; -//--- initialization - pio2=1.57079632679489661923; -//--- check - if(m==0.0) - return(phi); -//--- change values - lphi=phi; - npio2=(int)MathFloor(lphi/pio2); -//--- check - if(npio2%2!=0) - npio2=npio2+1; - lphi=lphi-npio2*pio2; -//--- check - if(lphi<0.0) - { - lphi=-lphi; - s=-1; - } - else - s=1; -//--- change values - a=1.0-m; - ebig=EllipticIntegralE(m); -//--- check - if(a==0.0) - { - temp=MathSin(lphi); - //--- check - if(s<0) - temp=-temp; - //--- return result - return(temp+npio2*ebig); - } -//--- calculation - t=MathTan(lphi); - b=MathSqrt(a); -//--- Thanks to Brian Fitzgerald -//--- for pointing out an instability near odd multiples of pi/2 - if(MathAbs(t)>10) - { - //--- Transform the amplitude - e=1.0/(b*t); - //--- ... but avoid multiple recursions. - if(MathAbs(e)<10) - { - e=MathArctan(e); - temp=ebig+m*MathSin(lphi)*MathSin(e)-IncompleteEllipticIntegralE(e,m); - //--- check - if(s<0) - temp=-temp; - //--- return result - return(temp+npio2*ebig); - } - } -//--- change values - c=MathSqrt(m); - a=1.0; - d=1; - e=0.0; - md=0; -//--- cycle - while(MathAbs(c/a)>CMath::m_machineepsilon) - { - //--- calculation - temp=b/a; - lphi=lphi+MathArctan(t*temp)+md*M_PI; - md=(int)((lphi+pio2)/M_PI); - t=t*(1.0+temp)/(1.0-temp*t*t); - c=0.5*(a-b); - temp=MathSqrt(a*b); - a=0.5*(a+b); - b=temp; - d=d+d; - e=e+c*MathSin(lphi); - } -//--- change value - temp=ebig/EllipticIntegralK(m); - temp=temp*((MathArctan(t)+md*M_PI)/(d*a)); - temp=temp+e; -//--- check - if(s<0) - temp=-temp; -//--- return result - return(temp+npio2*ebig); - } -//+------------------------------------------------------------------+ -//| Exponential integral | -//+------------------------------------------------------------------+ -class CExpIntegrals - { -public: - //--- constructor, destructor - CExpIntegrals(void); - ~CExpIntegrals(void); - //--- methods - static double ExponentialIntegralEi(const double x); - static double ExponentialIntegralEn(const double x,const int n); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CExpIntegrals::CExpIntegrals(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CExpIntegrals::~CExpIntegrals(void) - { - - } -//+------------------------------------------------------------------+ -//| Exponential integral Ei(x) | -//| x | -//| - t | -//| | | e | -//| Ei(x) = -|- --- dt . | -//| | | t | -//| - | -//| -inf | -//| Not defined for x <= 0. | -//| See also expn.c. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0,100 50000 8.6e-16 1.3e-16 | -//+------------------------------------------------------------------+ -static double CExpIntegrals::ExponentialIntegralEi(const double x) - { -//--- create variables - double eul=0; - double f=0; - double f1=0; - double f2=0; - double w=0; -//--- initialization - eul=0.5772156649015328606065; -//--- check - if(x<=0.0) - return(0); -//--- check - if(x<2.0) - { - //--- calculation - f1=-5.350447357812542947283; - f1=f1*x+218.5049168816613393830; - f1=f1*x-4176.572384826693777058; - f1=f1*x+55411.76756393557601232; - f1=f1*x-331338.1331178144034309; - f1=f1*x+1592627.163384945414220; - f2=1.000000000000000000000; - f2=f2*x-52.50547959112862969197; - f2=f2*x+1259.616186786790571525; - f2=f2*x-17565.49581973534652631; - f2=f2*x+149306.2117002725991967; - f2=f2*x-729494.9239640527645655; - f2=f2*x+1592627.163384945429726; - f=f1/f2; - //--- return result - return(eul+MathLog(x)+x*f); - } -//--- check - if(x<4.0) - { - //--- calculation - w=1/x; - f1=1.981808503259689673238E-2; - f1=f1*w-1.271645625984917501326; - f1=f1*w-2.088160335681228318920; - f1=f1*w+2.755544509187936721172; - f1=f1*w-4.409507048701600257171E-1; - f1=f1*w+4.665623805935891391017E-2; - f1=f1*w-1.545042679673485262580E-3; - f1=f1*w+7.059980605299617478514E-5; - f2=1.000000000000000000000; - f2=f2*w+1.476498670914921440652; - f2=f2*w+5.629177174822436244827E-1; - f2=f2*w+1.699017897879307263248E-1; - f2=f2*w+2.291647179034212017463E-2; - f2=f2*w+4.450150439728752875043E-3; - f2=f2*w+1.727439612206521482874E-4; - f2=f2*w+3.953167195549672482304E-5; - f=f1/f2; - //--- return result - return(MathExp(x)*w*(1+w*f)); - } -//--- check - if(x<8.0) - { - //--- calculation - w=1/x; - f1=-1.373215375871208729803; - f1=f1*w-7.084559133740838761406E-1; - f1=f1*w+1.580806855547941010501; - f1=f1*w-2.601500427425622944234E-1; - f1=f1*w+2.994674694113713763365E-2; - f1=f1*w-1.038086040188744005513E-3; - f1=f1*w+4.371064420753005429514E-5; - f1=f1*w+2.141783679522602903795E-6; - f2=1.000000000000000000000; - f2=f2*w+8.585231423622028380768E-1; - f2=f2*w+4.483285822873995129957E-1; - f2=f2*w+7.687932158124475434091E-2; - f2=f2*w+2.449868241021887685904E-2; - f2=f2*w+8.832165941927796567926E-4; - f2=f2*w+4.590952299511353531215E-4; - f2=f2*w+-4.729848351866523044863E-6; - f2=f2*w+2.665195537390710170105E-6; - f=f1/f2; - //--- return result - return(MathExp(x)*w*(1+w*f)); - } -//--- check - if(x<16.0) - { - //--- calculation - w=1/x; - f1=-2.106934601691916512584; - f1=f1*w+1.732733869664688041885; - f1=f1*w-2.423619178935841904839E-1; - f1=f1*w+2.322724180937565842585E-2; - f1=f1*w+2.372880440493179832059E-4; - f1=f1*w-8.343219561192552752335E-5; - f1=f1*w+1.363408795605250394881E-5; - f1=f1*w-3.655412321999253963714E-7; - f1=f1*w+1.464941733975961318456E-8; - f1=f1*w+6.176407863710360207074E-10; - f2=1.000000000000000000000; - f2=f2*w-2.298062239901678075778E-1; - f2=f2*w+1.105077041474037862347E-1; - f2=f2*w-1.566542966630792353556E-2; - f2=f2*w+2.761106850817352773874E-3; - f2=f2*w-2.089148012284048449115E-4; - f2=f2*w+1.708528938807675304186E-5; - f2=f2*w-4.459311796356686423199E-7; - f2=f2*w+1.394634930353847498145E-8; - f2=f2*w+6.150865933977338354138E-10; - f=f1/f2; - //--- return result - return(MathExp(x)*w*(1+w*f)); - } -//--- check - if(x<32.0) - { - //--- calculation - w=1/x; - f1=-2.458119367674020323359E-1; - f1=f1*w-1.483382253322077687183E-1; - f1=f1*w+7.248291795735551591813E-2; - f1=f1*w-1.348315687380940523823E-2; - f1=f1*w+1.342775069788636972294E-3; - f1=f1*w-7.942465637159712264564E-5; - f1=f1*w+2.644179518984235952241E-6; - f1=f1*w-4.239473659313765177195E-8; - f2=1.000000000000000000000; - f2=f2*w-1.044225908443871106315E-1; - f2=f2*w-2.676453128101402655055E-1; - f2=f2*w+9.695000254621984627876E-2; - f2=f2*w-1.601745692712991078208E-2; - f2=f2*w+1.496414899205908021882E-3; - f2=f2*w-8.462452563778485013756E-5; - f2=f2*w+2.728938403476726394024E-6; - f2=f2*w-4.239462431819542051337E-8; - f=f1/f2; - //--- return result - return(MathExp(x)*w*(1+w*f)); - } -//--- check - if(x<64) - { - //--- calculation - w=1/x; - f1=1.212561118105456670844E-1; - f1=f1*w-5.823133179043894485122E-1; - f1=f1*w+2.348887314557016779211E-1; - f1=f1*w-3.040034318113248237280E-2; - f1=f1*w+1.510082146865190661777E-3; - f1=f1*w-2.523137095499571377122E-5; - f2=1.000000000000000000000; - f2=f2*w-1.002252150365854016662; - f2=f2*w+2.928709694872224144953E-1; - f2=f2*w-3.337004338674007801307E-2; - f2=f2*w+1.560544881127388842819E-3; - f2=f2*w-2.523137093603234562648E-5; - f=f1/f2; - //--- return result - return(MathExp(x)*w*(1+w*f)); - } -//--- calculation - w=1/x; - f1=-7.657847078286127362028E-1; - f1=f1*w+6.886192415566705051750E-1; - f1=f1*w-2.132598113545206124553E-1; - f1=f1*w+3.346107552384193813594E-2; - f1=f1*w-3.076541477344756050249E-3; - f1=f1*w+1.747119316454907477380E-4; - f1=f1*w-6.103711682274170530369E-6; - f1=f1*w+1.218032765428652199087E-7; - f1=f1*w-1.086076102793290233007E-9; - f2=1.000000000000000000000; - f2=f2*w-1.888802868662308731041; - f2=f2*w+1.066691687211408896850; - f2=f2*w-2.751915982306380647738E-1; - f2=f2*w+3.930852688233823569726E-2; - f2=f2*w-3.414684558602365085394E-3; - f2=f2*w+1.866844370703555398195E-4; - f2=f2*w-6.345146083130515357861E-6; - f2=f2*w+1.239754287483206878024E-7; - f2=f2*w-1.086076102793126632978E-9; - f=f1/f2; -//--- return result - return(MathExp(x)*w*(1+w*f)); - } -//+------------------------------------------------------------------+ -//| Exponential integral En(x) | -//| Evaluates the exponential integral | -//| inf. | -//| - | -//| | | -xt | -//| | e | -//| E (x) = | ---- dt. | -//| n | n | -//| | | t | -//| - | -//| 1 | -//| Both n and x must be nonnegative. | -//| The routine employs either a power series, a continued | -//| fraction, or an asymptotic formula depending on the | -//| relative values of n and x. | -//| ACCURACY: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE 0, 30 10000 1.7e-15 3.6e-16 | -//+------------------------------------------------------------------+ -static double CExpIntegrals::ExponentialIntegralEn(const double x,const int n) - { -//--- create variables - double result=0; - double r=0; - double t=0; - double yk=0; - double xk=0; - double pk=0; - double pkm1=0; - double pkm2=0; - double qk=0; - double qkm1=0; - double qkm2=0; - double psi=0; - double z=0; - int i=0; - int k=0; - double big=0; - double eul=0; -//--- initialization - eul=0.57721566490153286060; - big=1.44115188075855872*MathPow(10,17); -//--- check - if(((n<0 || x<0.0) || x>170) || (x==0.0 && n<2)) - return(-1); -//--- check - if(x==0.0) - return(1.0/(double)(n-1)); -//--- check - if(n==0) - return(MathExp(-x)/x); -//--- check - if(n>5000) - { - //--- calculation - xk=x+n; - yk=1/(xk*xk); - t=n; - result=yk*t*(6*x*x-8*t*x+t*t); - result=yk*(result+t*(t-2.0*x)); - result=yk*(result+t); - result=(result+1)*MathExp(-x)/xk; - //--- return result - return(result); - } -//--- check - if(x<=1.0) - { - //--- calculation - psi=-eul-MathLog(x); - for(i=1;i<=n-1;i++) - psi=psi+1.0/(double)i; - z=-x; - xk=0; - yk=1; - pk=1-n; - //--- check - if(n==1) - result=0.0; - else - result=1.0/pk; - do - { - //--- change values - xk=xk+1; - yk=yk*z/xk; - pk=pk+1; - //--- check - if(pk!=0.0) - result=result+yk/pk; - //--- check - if(result!=0.0) - t=MathAbs(yk/result); - else - t=1; - } - while(t>=CMath::m_machineepsilon); - t=1; - for(i=1;i<=n-1;i++) - t=t*z/i; - //--- return result - return(psi*t-result); - } - else - { - //--- calculation - k=1; - pkm2=1; - qkm2=x; - pkm1=1.0; - qkm1=x+n; - result=pkm1/qkm1; - do - { - k=k+1; - //--- check - if(k%2==1) - { - yk=1; - xk=n+(double)(k-1)/2.0; - } - else - { - yk=x; - xk=(double)k/2.0; - } - //--- change values - pk=pkm1*yk+pkm2*xk; - qk=qkm1*yk+qkm2*xk; - //--- check - if(qk!=0.0) - { - r=pk/qk; - t=MathAbs((result-r)/r); - result=r; - } - else - t=1; - //--- change values - pkm2=pkm1; - pkm1=pk; - qkm2=qkm1; - qkm1=qk; - //--- check - if(MathAbs(pk)>big) - { - //--- change values - pkm2=pkm2/big; - pkm1=pkm1/big; - qkm2=qkm2/big; - qkm1=qkm1/big; - } - } - while(t>=CMath::m_machineepsilon); - result=result*MathExp(-x); - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| F distribution | -//+------------------------------------------------------------------+ -class CFDistr - { -public: - //--- constructor, destructor - CFDistr(void); - ~CFDistr(void); - //--- methods - static double FDistribution(const int a,const int b,const double x); - static double FComplDistribution(const int a,const int b,const double x); - static double InvFDistribution(const int a,const int b,const double y); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CFDistr::CFDistr(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CFDistr::~CFDistr(void) - { - - } -//+------------------------------------------------------------------+ -//| F distribution | -//| Returns the area from zero to x under the F density | -//| function (also known as Snedcor's density or the | -//| variance ratio density). This is the density | -//| of x = (u1/df1)/(u2/df2), where u1 and u2 are random | -//| variables having Chi square distributions with df1 | -//| and df2 degrees of freedom, respectively. | -//| The incomplete beta integral is used, according to the | -//| formula | -//| P(x) = incbet( df1/2, df2/2, (df1*x/(df2 + df1*x) ). | -//| The arguments a and b are greater than zero, and x is | -//| nonnegative. | -//| ACCURACY: | -//| Tested at random points (a,b,x). | -//| x a,b Relative error: | -//| arithmetic domain domain # trials peak rms | -//| IEEE 0,1 0,100 100000 9.8e-15 1.7e-15 | -//| IEEE 1,5 0,100 100000 6.5e-15 3.5e-16 | -//| IEEE 0,1 1,10000 100000 2.2e-11 3.3e-12 | -//| IEEE 1,5 1,10000 100000 1.1e-11 1.7e-13 | -//+------------------------------------------------------------------+ -static double CFDistr::FDistribution(const int a,const int b,const double x) - { -//--- check - if(!CAp::Assert(a>=1 && b>=1 && x>=0,__FUNCTION__+": the error variable")) - return(EMPTY_VALUE); -//--- create a variable - double w=0; -//--- calculation - w=a*x; - w/=b+w; -//--- return result - return(CIncBetaF::IncompleteBeta(0.5*a,0.5*b,w)); - } -//+------------------------------------------------------------------+ -//| Complemented F distribution | -//| Returns the area from x to infinity under the F density | -//| function (also known as Snedcor's density or the | -//| variance ratio density). | -//| inf. | -//| - | -//| 1 | | a-1 b-1 | -//| 1-P(x) = ------ | t (1-t) dt | -//| B(a,b) | | | -//| - | -//| x | -//| The incomplete beta integral is used, according to the | -//| formula | -//| P(x) = incbet( df2/2, df1/2, (df2/(df2 + df1*x) ). | -//| ACCURACY: | -//| Tested at random points (a,b,x) in the indicated intervals. | -//| x a,b Relative error: | -//| arithmetic domain domain # trials peak rms | -//| IEEE 0,1 1,100 100000 3.7e-14 5.9e-16 | -//| IEEE 1,5 1,100 100000 8.0e-15 1.6e-15 | -//| IEEE 0,1 1,10000 100000 1.8e-11 3.5e-13 | -//| IEEE 1,5 1,10000 100000 2.0e-11 3.0e-12 | -//+------------------------------------------------------------------+ -static double CFDistr::FComplDistribution(const int a,const int b,const double x) - { -//--- create a variable - double w=0; -//--- check - if(!CAp::Assert((a>=1 && b>=1) && x>=0.0,__FUNCTION__+": domain error")) - return(EMPTY_VALUE); -//--- calculation - w=b/(b+a*x); -//--- return result - return(CIncBetaF::IncompleteBeta(0.5*b,0.5*a,w)); - } -//+------------------------------------------------------------------+ -//| Inverse of complemented F distribution | -//| Finds the F density argument x such that the integral | -//| from x to infinity of the F density is equal to the | -//| given probability p. | -//| This is accomplished using the inverse beta integral | -//| function and the relations | -//| z = incbi( df2/2, df1/2, p ) | -//| x = df2 (1-z) / (df1 z). | -//| Note: the following relations hold for the inverse of | -//| the uncomplemented F distribution: | -//| z = incbi( df1/2, df2/2, p ) | -//| x = df2 z / (df1 (1-z)). | -//| ACCURACY: | -//| Tested at random points (a,b,p). | -//| a,b Relative error: | -//| arithmetic domain # trials peak rms | -//| For p between .001 and 1: | -//| IEEE 1,100 100000 8.3e-15 4.7e-16 | -//| IEEE 1,10000 100000 2.1e-11 1.4e-13 | -//| For p between 10^-6 and 10^-3: | -//| IEEE 1,100 50000 1.3e-12 8.4e-15 | -//| IEEE 1,10000 50000 3.0e-12 4.8e-14 | -//+------------------------------------------------------------------+ -static double CFDistr::InvFDistribution(const int a,const int b,const double y) - { -//--- create variables - double result=0; - double w=0; -//--- check - if(!CAp::Assert(((a>=1 && b>=1) && y>0.0) && y<=1.0,__FUNCTION__+": domain error")) - return(EMPTY_VALUE); -//--- Compute probability for x=0.5 - w=CIncBetaF::IncompleteBeta(0.5*b,0.5*a,0.5); -//--- If that is greater than y,then the solution w < .5 -//--- Otherwise,solve at 1-y to remove cancellation in (b - b*w) - if(w>y || y<0.001) - { - //--- calculation - w=CIncBetaF::InvIncompleteBeta(0.5*b,0.5*a,y); - result=(b-b*w)/(a*w); - } - else - { - //--- calculation - w=CIncBetaF::InvIncompleteBeta(0.5*a,0.5*b,1.0-y); - result=b*w/(a*(1.0-w)); - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Fresnel integral | -//+------------------------------------------------------------------+ -class CFresnel - { -public: - //--- constructor, destructor - CFresnel(void); - ~CFresnel(void); - //--- method - static void FresnelIntegral(double x,double &c,double &s); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CFresnel::CFresnel(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CFresnel::~CFresnel(void) - { - - } -//+------------------------------------------------------------------+ -//| Fresnel integral | -//| Evaluates the Fresnel integrals | -//| x | -//| - | -//| | | | -//| C(x) = | cos(pi/2 t**2) dt, | -//| | | | -//| - | -//| 0 | -//| x | -//| - | -//| | | | -//| S(x) = | sin(pi/2 t**2) dt. | -//| | | | -//| - | -//| 0 | -//| The integrals are evaluated by a power series for x < 1. | -//| For x >= 1 auxiliary functions f(x) and g(x) are employed | -//| such that | -//| C(x) = 0.5 + f(x) sin( pi/2 x**2 ) - g(x) cos( pi/2 x**2 ) | -//| S(x) = 0.5 - f(x) cos( pi/2 x**2 ) - g(x) sin( pi/2 x**2 ) | -//| ACCURACY: | -//| Relative error. | -//| Arithmetic function domain # trials peak rms | -//| IEEE S(x) 0, 10 10000 2.0e-15 3.2e-16| -//| IEEE C(x) 0, 10 10000 1.8e-15 3.3e-16| -//+------------------------------------------------------------------+ -static void CFresnel::FresnelIntegral(double x,double &c,double &s) - { -//--- create variables - double xxa=0; - double f=0; - double g=0; - double cc=0; - double ss=0; - double t=0; - double u=0; - double x2=0; - double sn=0; - double sd=0; - double cn=0; - double cd=0; - double fn=0; - double fd=0; - double gn=0; - double gd=0; - double mpi=0; - double mpio2=0; -//--- initialization - mpi=3.14159265358979323846; - mpio2=1.57079632679489661923; - xxa=x; - x=MathAbs(xxa); - x2=x*x; -//--- check - if(x2<2.5625) - { - //--- calculation - t=x2*x2; - sn=-2.99181919401019853726E3; - sn=sn*t+7.08840045257738576863E5; - sn=sn*t-6.29741486205862506537E7; - sn=sn*t+2.54890880573376359104E9; - sn=sn*t-4.42979518059697779103E10; - sn=sn*t+3.18016297876567817986E11; - sd=1.00000000000000000000E0; - sd=sd*t+2.81376268889994315696E2; - sd=sd*t+4.55847810806532581675E4; - sd=sd*t+5.17343888770096400730E6; - sd=sd*t+4.19320245898111231129E8; - sd=sd*t+2.24411795645340920940E10; - sd=sd*t+6.07366389490084639049E11; - cn=-4.98843114573573548651E-8; - cn=cn*t+9.50428062829859605134E-6; - cn=cn*t-6.45191435683965050962E-4; - cn=cn*t+1.88843319396703850064E-2; - cn=cn*t-2.05525900955013891793E-1; - cn=cn*t+9.99999999999999998822E-1; - cd=3.99982968972495980367E-12; - cd=cd*t+9.15439215774657478799E-10; - cd=cd*t+1.25001862479598821474E-7; - cd=cd*t+1.22262789024179030997E-5; - cd=cd*t+8.68029542941784300606E-4; - cd=cd*t+4.12142090722199792936E-2; - cd=cd*t+1.00000000000000000118E0; - s=MathSign(xxa)*x*x2*sn/sd; - c=MathSign(xxa)*x*cn/cd; - //--- exit the function - return; - } -//--- check - if(x>36974.0) - { - //--- calculation - c=MathSign(xxa)*0.5; - s=MathSign(xxa)*0.5; - //--- exit the function - return; - } -//--- calculation - x2=x*x; - t=mpi*x2; - u=1/(t*t); - t=1/t; - fn=4.21543555043677546506E-1; - fn=fn*u+1.43407919780758885261E-1; - fn=fn*u+1.15220955073585758835E-2; - fn=fn*u+3.45017939782574027900E-4; - fn=fn*u+4.63613749287867322088E-6; - fn=fn*u+3.05568983790257605827E-8; - fn=fn*u+1.02304514164907233465E-10; - fn=fn*u+1.72010743268161828879E-13; - fn=fn*u+1.34283276233062758925E-16; - fn=fn*u+3.76329711269987889006E-20; - fd=1.00000000000000000000E0; - fd=fd*u+7.51586398353378947175E-1; - fd=fd*u+1.16888925859191382142E-1; - fd=fd*u+6.44051526508858611005E-3; - fd=fd*u+1.55934409164153020873E-4; - fd=fd*u+1.84627567348930545870E-6; - fd=fd*u+1.12699224763999035261E-8; - fd=fd*u+3.60140029589371370404E-11; - fd=fd*u+5.88754533621578410010E-14; - fd=fd*u+4.52001434074129701496E-17; - fd=fd*u+1.25443237090011264384E-20; - gn=5.04442073643383265887E-1; - gn=gn*u+1.97102833525523411709E-1; - gn=gn*u+1.87648584092575249293E-2; - gn=gn*u+6.84079380915393090172E-4; - gn=gn*u+1.15138826111884280931E-5; - gn=gn*u+9.82852443688422223854E-8; - gn=gn*u+4.45344415861750144738E-10; - gn=gn*u+1.08268041139020870318E-12; - gn=gn*u+1.37555460633261799868E-15; - gn=gn*u+8.36354435630677421531E-19; - gn=gn*u+1.86958710162783235106E-22; - gd=1.00000000000000000000E0; - gd=gd*u+1.47495759925128324529E0; - gd=gd*u+3.37748989120019970451E-1; - gd=gd*u+2.53603741420338795122E-2; - gd=gd*u+8.14679107184306179049E-4; - gd=gd*u+1.27545075667729118702E-5; - gd=gd*u+1.04314589657571990585E-7; - gd=gd*u+4.60680728146520428211E-10; - gd=gd*u+1.10273215066240270757E-12; - gd=gd*u+1.38796531259578871258E-15; - gd=gd*u+8.39158816283118707363E-19; - gd=gd*u+1.86958710162783236342E-22; -//--- get result - f=1-u*fn/fd; - g=t*gn/gd; - t=mpio2*x2; - cc=MathCos(t); - ss=MathSin(t); - t=mpi*x; - c=0.5+(f*ss-g*cc)/t; - s=0.5-(f*cc+g*ss)/t; - c=c*MathSign(xxa); - s=s*MathSign(xxa); - } -//+------------------------------------------------------------------+ -//| Hermite polynomial | -//+------------------------------------------------------------------+ -class CHermite - { -public: - //--- constructor, destructor - CHermite(void); - ~CHermite(void); - //--- methods - static double HermiteCalculate(const int n,const double x); - static double HermiteSum(double &c[],const int n,const double x); - static void HermiteCoefficients(const int n,double &c[]); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CHermite::CHermite(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CHermite::~CHermite(void) - { - - } -//+------------------------------------------------------------------+ -//| Calculation of the value of the Hermite polynomial. | -//| Parameters: | -//| n - degree, n>=0 | -//| x - argument | -//| Result: | -//| the value of the Hermite polynomial Hn at x | -//+------------------------------------------------------------------+ -static double CHermite::HermiteCalculate(const int n,const double x) - { -//--- create variables - double result=0; - int i=0; - double a=0; - double b=0; -//--- Prepare A and B - a=1; - b=2*x; -//--- Special cases: N=0 or N=1 - if(n==0) - return(a); -//--- check - if(n==1) - return(b); -//--- General case: N>=2 - for(i=2;i<=n;i++) - { - result=2*x*b-2*(i-1)*a; - a=b; - b=result; - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Summation of Hermite polynomials using Clenshaw?s recurrence | -//| formula. | -//| This routine calculates | -//| c[0]*H0(x) + c[1]*H1(x) + ... + c[N]*HN(x) | -//| Parameters: | -//| n - degree, n>=0 | -//| x - argument | -//| Result: | -//| the value of the Hermite polynomial at x | -//+------------------------------------------------------------------+ -static double CHermite::HermiteSum(double &c[],const int n,const double x) - { -//--- create variables - double result=0; - double b1=0; - double b2=0; - int i=0; -//--- initialization - b1=0; - b2=0; -//--- calculation - for(i=n;i>=0;i--) - { - result=2*(x*b1-(i+1)*b2)+c[i]; - b2=b1; - b1=result; - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Representation of Hn as C[0] + C[1]*X + ... + C[N]*X^N | -//| Input parameters: | -//| N - polynomial degree, n>=0 | -//| Output parameters: | -//| C - coefficients | -//+------------------------------------------------------------------+ -static void CHermite::HermiteCoefficients(const int n,double &c[]) - { -//--- create a variable - int i=0; -//--- allocation - ArrayResizeAL(c,n+1); -//--- initialization - for(i=0;i<=n;i++) - c[i]=0; -//--- calculation - c[n]=MathExp(n*MathLog(2)); - for(i=0;i<=n/2-1;i++) - c[n-2*(i+1)]=-(c[n-2*i]*(n-2*i)*(n-2*i-1)/4/(i+1)); - } -//+------------------------------------------------------------------+ -//| Jacobian elliptic functions | -//+------------------------------------------------------------------+ -class CJacobianElliptic - { -public: - //--- constructor, destructor - CJacobianElliptic(void); - ~CJacobianElliptic(void); - //--- method - static void JacobianEllipticFunctions(const double u,const double m,double &sn,double &cn,double &dn,double &ph); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CJacobianElliptic::CJacobianElliptic(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CJacobianElliptic::~CJacobianElliptic(void) - { - - } -//+------------------------------------------------------------------+ -//| Jacobian Elliptic Functions | -//| Evaluates the Jacobian elliptic functions sn(u|m), cn(u|m), | -//| and dn(u|m) of parameter m between 0 and 1, and real | -//| argument u. | -//| These functions are periodic, with quarter-period on the | -//| real axis equal to the complete elliptic integral | -//| ellpk(1.0-m). | -//| Relation to incomplete elliptic integral: | -//| If u = ellik(phi,m), then sn(u|m) = sin(phi), | -//| and cn(u|m) = cos(phi). Phi is called the amplitude of u. | -//| Computation is by means of the arithmetic-geometric mean | -//| algorithm, except when m is within 1e-9 of 0 or 1. In the | -//| latter case with m close to 1, the approximation applies | -//| only for phi < pi/2. | -//| ACCURACY: | -//| Tested at random points with u between 0 and 10, m between | -//| 0 and 1. | -//| Absolute error (* = relative error): | -//| arithmetic function # trials peak rms | -//| IEEE phi 10000 9.2e-16* 1.4e-16* | -//| IEEE sn 50000 4.1e-15 4.6e-16 | -//| IEEE cn 40000 3.6e-15 4.4e-16 | -//| IEEE dn 10000 1.3e-12 1.8e-14 | -//| Peak error observed in consistency check using addition | -//| theorem for sn(u+v) was 4e-16 (absolute). Also tested by | -//| the above relation to the incomplete elliptic integral. | -//| Accuracy deteriorates when u is large. | -//+------------------------------------------------------------------+ -static void CJacobianElliptic::JacobianEllipticFunctions(const double u, - const double m, - double &sn,double &cn, - double &dn,double &ph) - { -//--- create variables - double ai=0; - double b=0; - double phi=0; - double t=0; - double twon=0; - int i=0; -//--- create arrays - double a[]; - double c[]; -//--- initialization - sn=0; - cn=0; - dn=0; - ph=0; -//--- check - if(!CAp::Assert(m>=0.0 && m<=1.0,__FUNCTION__+": m<0 or m>1")) - return; -//--- allocation - ArrayResizeAL(a,9); - ArrayResizeAL(c,9); -//--- check - if(m<1.0e-9) - { - //--- calculation - t=MathSin(u); - b=MathCos(u); - ai=0.25*m*(u-t*b); - sn=t-ai*b; - cn=b+ai*t; - ph=u-ai; - dn=1.0-0.5*m*t*t; - //--- exit the function - return; - } -//--- check - if(m>=0.9999999999) - { - //--- calculation - ai=0.25*(1.0-m); - b=MathCosh(u); - t=MathTanh(u); - phi=1.0/b; - twon=b*MathSinh(u); - sn=t+ai*(twon-u)/(b*b); - ph=2.0*MathArctan(MathExp(u))-1.57079632679489661923+ai*(twon-u)/b; - ai=ai*t*phi; - cn=phi-ai*(twon-u); - dn=phi+ai*(twon+u); - //--- exit the function - return; - } -//--- change values - a[0]=1.0; - b=MathSqrt(1.0-m); - c[0]=MathSqrt(m); - twon=1.0; - i=0; -//--- cycle - while(MathAbs(c[i]/a[i])>CMath::m_machineepsilon) - { - //--- check - if(i>7) - { - //--- check - if(!CAp::Assert(false,__FUNCTION__+": overflow")) - return; - //--- break the cycle - break; - } - //--- calculation - ai=a[i]; - i=i+1; - c[i]=0.5*(ai-b); - t=MathSqrt(ai*b); - a[i]=0.5*(ai+b); - b=t; - twon=twon*2.0; - } - phi=twon*a[i]*u; -//--- cycle - do - { - //--- calculation - t=c[i]*MathSin(phi)/a[i]; - b=phi; - phi=(MathArcsin(t)+phi)/2.0; - i=i-1; - } - while(i!=0); -//--- get result - sn=MathSin(phi); - t=MathCos(phi); - cn=t; - dn=t/MathCos(phi-b); - ph=phi; - } -//+------------------------------------------------------------------+ -//| Laguerre polynomial | -//+------------------------------------------------------------------+ -class CLaguerre - { -public: - //--- constructor, destructor - CLaguerre(void); - ~CLaguerre(void); - //--- methods - static double LaguerreCalculate(const int n,const double x); - static double LaguerreSum(double &c[],const int n,const double x); - static void LaguerreCoefficients(const int n,double &c[]); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CLaguerre::CLaguerre(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CLaguerre::~CLaguerre(void) - { - - } -//+------------------------------------------------------------------+ -//| Calculation of the value of the Laguerre polynomial. | -//| Parameters: | -//| n - degree, n>=0 | -//| x - argument | -//| Result: | -//| the value of the Laguerre polynomial Ln at x | -//+------------------------------------------------------------------+ -static double CLaguerre::LaguerreCalculate(const int n,const double x) - { -//--- create variables - double result=0; - double a=0; - double b=0; - double i=0; -//--- initialization - result=1; - a=1; - b=1-x; -//--- check - if(n==1) - result=b; -//--- initialization - i=2; -//--- cycle - while(i<=n) - { - //--- calculation - result=((2*i-1-x)*b-(i-1)*a)/i; - a=b; - b=result; - i=i+1; - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Summation of Laguerre polynomials using Clenshaw?s recurrence | -//| formula. | -//| This routine calculates c[0]*L0(x) + c[1]*L1(x) + ... + | -//| + c[N]*LN(x) | -//| Parameters: | -//| n - degree, n>=0 | -//| x - argument | -//| Result: | -//| the value of the Laguerre polynomial at x | -//+------------------------------------------------------------------+ -static double CLaguerre::LaguerreSum(double &c[],const int n,const double x) - { -//--- create variables - double result=0; - double b1=0; - double b2=0; - int i=0; -//--- initialization - b1=0; - b2=0; - result=0; -//--- calculation - for(i=n;i>=0;i--) - { - result=(2*i+1-x)*b1/(i+1)-(i+1)*b2/(i+2)+c[i]; - b2=b1; - b1=result; - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Representation of Ln as C[0] + C[1]*X + ... + C[N]*X^N | -//| Input parameters: | -//| N - polynomial degree, n>=0 | -//| Output parameters: | -//| C - coefficients | -//+------------------------------------------------------------------+ -static void CLaguerre::LaguerreCoefficients(const int n,double &c[]) - { -//--- create a variable - int i=0; -//--- allocation - ArrayResizeAL(c,n+1); -//--- initialization - c[0]=1; -//--- calculation - for(i=0;i<=n-1;i++) - c[i+1]=-(c[i]*(n-i)/(i+1)/(i+1)); - } -//+------------------------------------------------------------------+ -//| Legendre polynomial | -//+------------------------------------------------------------------+ -class CLegendre - { -public: - //--- constructor, destructor - CLegendre(void); - ~CLegendre(void); - //--- methods - static double LegendreCalculate(const int n,const double x); - static double LegendreSum(double &c[],const int n,const double x); - static void LegendreCoefficients(const int n,double &c[]); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CLegendre::CLegendre(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CLegendre::~CLegendre(void) - { - - } -//+------------------------------------------------------------------+ -//| Calculation of the value of the Legendre polynomial Pn. | -//| Parameters: | -//| n - degree, n>=0 | -//| x - argument | -//| Result: | -//| the value of the Legendre polynomial Pn at x | -//+------------------------------------------------------------------+ -static double CLegendre::LegendreCalculate(const int n,const double x) - { -//--- create variables - double result=0; - double a=0; - double b=0; - int i=0; -//--- initialization - result=1; - a=1; - b=x; -//--- check - if(n==0) - return(a); -//--- check - if(n==1) - return(b); -//--- calculation - for(i=2;i<=n;i++) - { - result=((2*i-1)*x*b-(i-1)*a)/i; - a=b; - b=result; - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Summation of Legendre polynomials using Clenshaw?s recurrence | -//| formula. | -//| This routine calculates | -//| c[0]*P0(x) + c[1]*P1(x) + ... + c[N]*PN(x) | -//| Parameters: | -//| n - degree, n>=0 | -//| x - argument | -//| Result: | -//| the value of the Legendre polynomial at x | -//+------------------------------------------------------------------+ -static double CLegendre::LegendreSum(double &c[],const int n,const double x) - { -//--- create variables - double result=0; - double b1=0; - double b2=0; - int i=0; -//--- initialization - b1=0; - b2=0; - result=0; -//--- calculation - for(i=n;i>=0;i--) - { - result=(2*i+1)*x*b1/(i+1)-(i+1)*b2/(i+2)+c[i]; - b2=b1; - b1=result; - } -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Representation of Pn as C[0] + C[1]*X + ... + C[N]*X^N | -//| Input parameters: | -//| N - polynomial degree, n>=0 | -//| Output parameters: | -//| C - coefficients | -//+------------------------------------------------------------------+ -static void CLegendre::LegendreCoefficients(const int n,double &c[]) - { -//--- create a variable - int i=0; -//--- allocation - ArrayResizeAL(c,n+1); -//--- initialization - for(i=0;i<=n;i++) - c[i]=0; - c[n]=1; -//--- calculation - for(i=1;i<=n;i++) - c[n]=c[n]*(n+i)/2/i; - for(i=0;i<=n/2-1;i++) - c[n-2*(i+1)]=-(c[n-2*i]*(n-2*i)*(n-2*i-1)/2/(i+1)/(2*(n-i)-1)); - } -//+------------------------------------------------------------------+ -//| Poisson distribution | -//+------------------------------------------------------------------+ -class CPoissonDistr - { -public: - //--- constructor, destructor - CPoissonDistr(void); - ~CPoissonDistr(void); - //--- methods - static double PoissonDistribution(const int k,const double m); - static double PoissonComplDistribution(const int k,const double m); - static double InvPoissonDistribution(const int k,const double y); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CPoissonDistr::CPoissonDistr(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CPoissonDistr::~CPoissonDistr(void) - { - - } -//+------------------------------------------------------------------+ -//| Poisson distribution | -//| Returns the sum of the first k+1 terms of the Poisson | -//| distribution: | -//| k j | -//| -- -m m | -//| > e -- | -//| -- j! | -//| j=0 | -//| The terms are not summed directly; instead the incomplete | -//| gamma integral is employed, according to the relation | -//| y = pdtr( k, m ) = igamc( k+1, m ). | -//| The arguments must both be positive. | -//| ACCURACY: | -//| See incomplete gamma function | -//+------------------------------------------------------------------+ -static double CPoissonDistr::PoissonDistribution(const int k,const double m) - { -//--- check - if(!CAp::Assert(k>=0 && m>0.0,__FUNCTION__+": domain error")) - return(EMPTY_VALUE); -//--- return result - return(CIncGammaF::IncompleteGammaC(k+1,m)); - } -//+------------------------------------------------------------------+ -//| Complemented Poisson distribution | -//| Returns the sum of the terms k+1 to infinity of the Poisson | -//| distribution: | -//| inf. j | -//| -- -m m | -//| > e -- | -//| -- j! | -//| j=k+1 | -//| The terms are not summed directly; instead the incomplete | -//| gamma integral is employed, according to the formula | -//| y = pdtrc( k, m ) = igam( k+1, m ). | -//| The arguments must both be positive. | -//| ACCURACY: | -//| See incomplete gamma function | -//+------------------------------------------------------------------+ -static double CPoissonDistr::PoissonComplDistribution(const int k,const double m) - { -//--- check - if(!CAp::Assert(k>=0 && m>0.0,__FUNCTION__+": domain error")) - return(EMPTY_VALUE); -//--- return result - return(CIncGammaF::IncompleteGamma(k+1,m)); - } -//+------------------------------------------------------------------+ -//| Inverse Poisson distribution | -//| Finds the Poisson variable x such that the integral | -//| from 0 to x of the Poisson density is equal to the | -//| given probability y. | -//| This is accomplished using the inverse gamma integral | -//| function and the relation | -//| m = igami( k+1, y ). | -//| ACCURACY: | -//| See inverse incomplete gamma function | -//+------------------------------------------------------------------+ -static double CPoissonDistr::InvPoissonDistribution(const int k,const double y) - { -//--- check - if(!CAp::Assert((k>=0 && y>=0.0) && y<1.0,__FUNCTION__+": domain error")) - return(EMPTY_VALUE); -//--- return result - return(CIncGammaF::InvIncompleteGammaC(k+1,y)); - } -//+------------------------------------------------------------------+ -//| Psi function | -//+------------------------------------------------------------------+ -class CPsiF - { -public: - //--- constructor, destructor - CPsiF(void); - ~CPsiF(void); - //--- method - static double Psi(double x); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CPsiF::CPsiF(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CPsiF::~CPsiF(void) - { - - } -//+------------------------------------------------------------------+ -//| Psi (digamma) function | -//| d - | -//| psi(x) = -- ln | (x) | -//| dx | -//| is the logarithmic derivative of the gamma function. | -//| For integer x, | -//| n-1 | -//| - | -//| psi(n) = -EUL + > 1/k. | -//| - | -//| k=1 | -//| This formula is used for 0 < n <= 10. If x is negative, it | -//| is transformed to a positive argument by the reflection | -//| formula psi(1-x) = psi(x) + pi cot(pi x). | -//| For general positive x, the argument is made greater than 10 | -//| using the recurrence psi(x+1) = psi(x) + 1/x. | -//| Then the following asymptotic expansion is applied: | -//| inf. B | -//| - 2k | -//| psi(x) = log(x) - 1/2x - > ------- | -//| - 2k | -//| k=1 2k x | -//| where the B2k are Bernoulli numbers. | -//| ACCURACY: | -//| Relative error (except absolute when |psi| < 1): | -//| arithmetic domain # trials peak rms | -//| IEEE 0,30 30000 1.3e-15 1.4e-16 | -//| IEEE -30,0 40000 1.5e-15 2.2e-16 | -//+------------------------------------------------------------------+ -static double CPsiF::Psi(double x) - { -//--- create variables - double result=0; - double p=0; - double q=0; - double nz=0; - double s=0; - double w=0; - double y=0; - double z=0; - double polv=0; - int i=0; - int n=0; - int negative=0; -//--- initialization - negative=0; - nz=0.0; -//--- check - if(x<=0.0) - { - negative=1; - q=x; - p=(int)MathFloor(q); - //--- check - if(p==q) - { - //--- check - if(!CAp::Assert(false,__FUNCTION__+": singularity in Psi(x)")) - return(EMPTY_VALUE); - //--- return result - return(CMath::m_maxrealnumber); - } - nz=q-p; - //--- check - if(nz!=0.5) - { - //--- check - if(nz>0.5) - { - p=p+1.0; - nz=q-p; - } - //--- change value - nz=M_PI/MathTan(M_PI*nz); - } - else - nz=0.0; - x=1.0-x; - } -//--- check - if(x<=10.0 && x==(double)((int)MathFloor(x))) - { - y=0.0; - n=(int)MathFloor(x); - //--- calculation - for(i=1;i<=n-1;i++) - { - w=i; - y=y+1.0/w; - } - y=y-0.57721566490153286061; - } - else - { - //--- change values - s=x; - w=0.0; - //--- cycle - while(s<10.0) - { - w=w+1.0/s; - s=s+1.0; - } - //--- check - if(s<1.0E17) - { - //--- calculation - z=1.0/(s*s); - polv=8.33333333333333333333E-2; - polv=polv*z-2.10927960927960927961E-2; - polv=polv*z+7.57575757575757575758E-3; - polv=polv*z-4.16666666666666666667E-3; - polv=polv*z+3.96825396825396825397E-3; - polv=polv*z-8.33333333333333333333E-3; - polv=polv*z+8.33333333333333333333E-2; - y=z*polv; - } - else - y=0.0; - //--- change value - y=MathLog(s)-0.5/s-y-w; - } -//--- check - if(negative!=0) - y=y-nz; -//--- return result - return(y); - } -//+------------------------------------------------------------------+ -//| Student's t distribution | -//+------------------------------------------------------------------+ -class CStudenttDistr - { -public: - //--- constructor, destructor - CStudenttDistr(void); - ~CStudenttDistr(void); - //--- methods - static double StudenttDistribution(const int k,const double t); - static double InvStudenttDistribution(const int k,double p); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CStudenttDistr::CStudenttDistr(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CStudenttDistr::~CStudenttDistr(void) - { - - } -//+------------------------------------------------------------------+ -//| Student's t distribution | -//| Computes the integral from minus infinity to t of the Student | -//| t distribution with integer k > 0 degrees of freedom: | -//| t | -//| - | -//| | | | -//| - | 2 -(k+1)/2 | -//| | ( (k+1)/2 ) | ( x ) | -//| ---------------------- | ( 1 + --- ) dx | -//| - | ( k ) | -//| sqrt( k pi ) | ( k/2 ) | | -//| | | | -//| - | -//| -inf. | -//| Relation to incomplete beta integral: | -//| 1 - stdtr(k,t) = 0.5 * incbet( k/2, 1/2, z ) | -//| where | -//| z = k/(k + t**2). | -//| For t < -2, this is the method of computation. For higher t, | -//| a direct method is derived from integration by parts. | -//| Since the function is symmetric about t=0, the area under the | -//| right tail of the density is found by calling the function | -//| with -t instead of t. | -//| ACCURACY: | -//| Tested at random 1 <= k <= 25. The "domain" refers to t. | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE -100,-2 50000 5.9e-15 1.4e-15 | -//| IEEE -2,100 500000 2.7e-15 4.9e-17 | -//+------------------------------------------------------------------+ -static double CStudenttDistr::StudenttDistribution(const int k,const double t) - { -//--- check - if(!CAp::Assert(k>0,__FUNCTION__+": the error variable")) - return(EMPTY_VALUE); -//--- check - if(t==0) - return(0.5); -//--- create variables - double x=0; - double rk=0; - double z=0; - double f=0; - double tz=0; - double p=0; - double xsqk=0; - int j=0; -//--- check - if(t<-2.0) - { - rk=k; - z=rk/(rk+t*t); - //--- return result - return(0.5*CIncBetaF::IncompleteBeta(0.5*rk,0.5,z)); - } -//--- check - if(t<0) - x=-t; - else - x=t; -//--- change values - rk=k; - z=1.0+x*x/rk; -//--- check - if(k%2!=0) - { - xsqk=x/MathSqrt(rk); - p=MathArctan(xsqk); - //--- check - if(k>1) - { - f=1.0; - tz=1.0; - j=3; - //--- cycle - while(jCMath::m_machineepsilon) - { - //--- calculation - tz*=(j-1)/(z*j); - f+=tz; - j+=2; - } - p+=f*xsqk/z; - } - p*=2.0/M_PI; - } - else - { - f=1.0; - tz=1.0; - j=2; - //--- cycle - while(jCMath::m_machineepsilon) - { - //--- calculation - tz*=(j-1)/(z*j); - f+=tz; - j+=2; - } - p=f*x/MathSqrt(z*rk); - } -//--- check - if(t<0) - p=-p; -//--- return result - return(0.5+0.5*p); - } -//+------------------------------------------------------------------+ -//| Functional inverse of Student's t distribution | -//| Given probability p, finds the argument t such that stdtr(k,t) | -//| is equal to p. | -//| ACCURACY: | -//| Tested at random 1 <= k <= 100. The "domain" refers to p: | -//| Relative error: | -//| arithmetic domain # trials peak rms | -//| IEEE .001,.999 25000 5.7e-15 8.0e-16 | -//| IEEE 10^-6,.001 25000 2.0e-12 2.9e-14 | -//+------------------------------------------------------------------+ -static double CStudenttDistr::InvStudenttDistribution(const int k,double p) - { -//--- create variables - double t=0; - double rk=k; - double z=0; - int rflg=0; - CIncBetaF ibetaf; -//--- check - if(!CAp::Assert(k>0 && p>0 && p<1,__FUNCTION__+": the error variable")) - return(EMPTY_VALUE); -//--- check - if(p>0.25 && p<0.75) - { - //--- check - if(p==0.5) - return(0); - //--- change values - z=1.0-2.0*p; - z=CIncBetaF::InvIncompleteBeta(0.5,0.5*rk,MathAbs(z)); - t=MathSqrt(rk*z/(1.0-z)); - //--- check - if(p<0.5) - t=-t; - //--- return result - return(t); - } -//--- 0=0.5) - { - p=1.0-p; - rflg=1; - } -//--- change value - z=CIncBetaF::InvIncompleteBeta(0.5*rk,0.5,2.0*p); -//--- check - if(CMath::m_maxrealnumber*z 8 auxiliary functions f(x) and g(x) are employed | -//| such that | -//| Ci(x) = f(x) sin(x) - g(x) cos(x) | -//| Si(x) = pi/2 - f(x) cos(x) - g(x) sin(x) | -//| ACCURACY: | -//| Test interval = [0,50]. | -//| Absolute error, except relative when > 1: | -//| arithmetic function # trials peak rms | -//| IEEE Si 30000 4.4e-16 7.3e-17 | -//| IEEE Ci 30000 6.9e-16 5.1e-17 | -//+------------------------------------------------------------------+ -static void CTrigIntegrals::SineCosineIntegrals(double x,double &si,double &ci) - { -//--- create variables - double z=0; - double c=0; - double s=0; - double f=0; - double g=0; - int sg=0; - double sn=0; - double sd=0; - double cn=0; - double cd=0; - double fn=0; - double fd=0; - double gn=0; - double gd=0; -//--- initialization - si=0; - ci=0; -//--- check - if(x<0.0) - { - sg=-1; - x=-x; - } - else - sg=0; -//--- check - if(x==0.0) - { - si=0; - ci=-CMath::m_maxrealnumber; - //--- exit the function - return; - } -//--- check - if(x>1.0E9) - { - si=1.570796326794896619-MathCos(x)/x; - ci=MathSin(x)/x; - //--- exit the function - return; - } -//--- check - if(x<=4.0) - { - //--- calculation - z=x*x; - sn=-8.39167827910303881427E-11; - sn=sn*z+4.62591714427012837309E-8; - sn=sn*z-9.75759303843632795789E-6; - sn=sn*z+9.76945438170435310816E-4; - sn=sn*z-4.13470316229406538752E-2; - sn=sn*z+1.00000000000000000302E0; - sd=2.03269266195951942049E-12; - sd=sd*z+1.27997891179943299903E-9; - sd=sd*z+4.41827842801218905784E-7; - sd=sd*z+9.96412122043875552487E-5; - sd=sd*z+1.42085239326149893930E-2; - sd=sd*z+9.99999999999999996984E-1; - s=x*sn/sd; - cn=2.02524002389102268789E-11; - cn=cn*z-1.35249504915790756375E-8; - cn=cn*z+3.59325051419993077021E-6; - cn=cn*z-4.74007206873407909465E-4; - cn=cn*z+2.89159652607555242092E-2; - cn=cn*z-1.00000000000000000080E0; - cd=4.07746040061880559506E-12; - cd=cd*z+3.06780997581887812692E-9; - cd=cd*z+1.23210355685883423679E-6; - cd=cd*z+3.17442024775032769882E-4; - cd=cd*z+5.10028056236446052392E-2; - cd=cd*z+4.00000000000000000080E0; - c=z*cn/cd; - //--- check - if(sg!=0) - s=-s; - //--- calculation - si=s; - ci=0.57721566490153286061+MathLog(x)+c; - //--- exit the function - return; - } -//--- change values - s=MathSin(x); - c=MathCos(x); - z=1.0/(x*x); -//--- check - if(x<8.0) - { - //--- calculation - fn=4.23612862892216586994E0; - fn=fn*z+5.45937717161812843388E0; - fn=fn*z+1.62083287701538329132E0; - fn=fn*z+1.67006611831323023771E-1; - fn=fn*z+6.81020132472518137426E-3; - fn=fn*z+1.08936580650328664411E-4; - fn=fn*z+5.48900223421373614008E-7; - fd=1.00000000000000000000E0; - fd=fd*z+8.16496634205391016773E0; - fd=fd*z+7.30828822505564552187E0; - fd=fd*z+1.86792257950184183883E0; - fd=fd*z+1.78792052963149907262E-1; - fd=fd*z+7.01710668322789753610E-3; - fd=fd*z+1.10034357153915731354E-4; - fd=fd*z+5.48900252756255700982E-7; - f=fn/(x*fd); - gn=8.71001698973114191777E-2; - gn=gn*z+6.11379109952219284151E-1; - gn=gn*z+3.97180296392337498885E-1; - gn=gn*z+7.48527737628469092119E-2; - gn=gn*z+5.38868681462177273157E-3; - gn=gn*z+1.61999794598934024525E-4; - gn=gn*z+1.97963874140963632189E-6; - gn=gn*z+7.82579040744090311069E-9; - gd=1.00000000000000000000E0; - gd=gd*z+1.64402202413355338886E0; - gd=gd*z+6.66296701268987968381E-1; - gd=gd*z+9.88771761277688796203E-2; - gd=gd*z+6.22396345441768420760E-3; - gd=gd*z+1.73221081474177119497E-4; - gd=gd*z+2.02659182086343991969E-6; - gd=gd*z+7.82579218933534490868E-9; - g=z*gn/gd; - } - else - { - //--- calculation - fn=4.55880873470465315206E-1; - fn=fn*z+7.13715274100146711374E-1; - fn=fn*z+1.60300158222319456320E-1; - fn=fn*z+1.16064229408124407915E-2; - fn=fn*z+3.49556442447859055605E-4; - fn=fn*z+4.86215430826454749482E-6; - fn=fn*z+3.20092790091004902806E-8; - fn=fn*z+9.41779576128512936592E-11; - fn=fn*z+9.70507110881952024631E-14; - fd=1.00000000000000000000E0; - fd=fd*z+9.17463611873684053703E-1; - fd=fd*z+1.78685545332074536321E-1; - fd=fd*z+1.22253594771971293032E-2; - fd=fd*z+3.58696481881851580297E-4; - fd=fd*z+4.92435064317881464393E-6; - fd=fd*z+3.21956939101046018377E-8; - fd=fd*z+9.43720590350276732376E-11; - fd=fd*z+9.70507110881952025725E-14; - f=fn/(x*fd); - gn=6.97359953443276214934E-1; - gn=gn*z+3.30410979305632063225E-1; - gn=gn*z+3.84878767649974295920E-2; - gn=gn*z+1.71718239052347903558E-3; - gn=gn*z+3.48941165502279436777E-5; - gn=gn*z+3.47131167084116673800E-7; - gn=gn*z+1.70404452782044526189E-9; - gn=gn*z+3.85945925430276600453E-12; - gn=gn*z+3.14040098946363334640E-15; - gd=1.00000000000000000000E0; - gd=gd*z+1.68548898811011640017E0; - gd=gd*z+4.87852258695304967486E-1; - gd=gd*z+4.67913194259625806320E-2; - gd=gd*z+1.90284426674399523638E-3; - gd=gd*z+3.68475504442561108162E-5; - gd=gd*z+3.57043223443740838771E-7; - gd=gd*z+1.72693748966316146736E-9; - gd=gd*z+3.87830166023954706752E-12; - gd=gd*z+3.14040098946363335242E-15; - g=z*gn/gd; - } - si=1.570796326794896619-f*c-g*s; -//--- check - if(sg!=0) - si=-si; -//--- get result - ci=f*s-g*c; - } -//+------------------------------------------------------------------+ -//| Hyperbolic sine and cosine integrals | -//| Approximates the integrals | -//| x | -//| - | -//| | | cosh t - 1 | -//| Chi(x) = eul + ln x + | ----------- dt, | -//| | | t | -//| - | -//| 0 | -//| x | -//| - | -//| | | sinh t | -//| Shi(x) = | ------ dt | -//| | | t | -//| - | -//| 0 | -//| where eul = 0.57721566490153286061 is Euler's constant. | -//| The integrals are evaluated by power series for x < 8 | -//| and by Chebyshev expansions for x between 8 and 88. | -//| For large x, both functions approach exp(x)/2x. | -//| Arguments greater than 88 in magnitude return MAXNUM. | -//| ACCURACY: | -//| Test interval 0 to 88. | -//| Relative error: | -//| arithmetic function # trials peak rms | -//| IEEE Shi 30000 6.9e-16 1.6e-16 | -//| Absolute error, except relative when |Chi| > 1: | -//| IEEE Chi 30000 8.4e-16 1.4e-16 | -//+------------------------------------------------------------------+ -static void CTrigIntegrals::HyperbolicSineCosineIntegrals(double x, - double &shi, - double &chi) - { -//--- create variables - double k=0; - double z=0; - double c=0; - double s=0; - double a=0; - int sg=0; - double b0=0; - double b1=0; - double b2=0; -//--- initialization - shi=0; - chi=0; -//--- check - if(x<0.0) - { - sg=-1; - x=-x; - } - else - sg=0; -//--- check - if(x==0.0) - { - shi=0; - chi=-CMath::m_maxrealnumber; - //--- exit the function - return; - } -//--- check - if(x<8.0) - { - //--- initialization - z=x*x; - a=1.0; - s=1.0; - c=0.0; - k=2.0; - do - { - //--- calculation - a=a*z/k; - c=c+a/k; - k=k+1.0; - a=a/k; - s=s+a/k; - k=k+1.0; - } - while(MathAbs(a/s)>=CMath::m_machineepsilon); - s=s*x; - } - else - { - //--- check - if(x<18.0) - { - //--- calculation - a=(576.0/x-52.0)/10.0; - k=MathExp(x)/x; - b0=1.83889230173399459482E-17; - b1=0.0; - //--- function calls - ChebIterationShiChi(a,-9.55485532279655569575E-17,b0,b1,b2); - ChebIterationShiChi(a,2.04326105980879882648E-16,b0,b1,b2); - ChebIterationShiChi(a,1.09896949074905343022E-15,b0,b1,b2); - ChebIterationShiChi(a,-1.31313534344092599234E-14,b0,b1,b2); - ChebIterationShiChi(a,5.93976226264314278932E-14,b0,b1,b2); - ChebIterationShiChi(a,-3.47197010497749154755E-14,b0,b1,b2); - ChebIterationShiChi(a,-1.40059764613117131000E-12,b0,b1,b2); - ChebIterationShiChi(a,9.49044626224223543299E-12,b0,b1,b2); - ChebIterationShiChi(a,-1.61596181145435454033E-11,b0,b1,b2); - ChebIterationShiChi(a,-1.77899784436430310321E-10,b0,b1,b2); - ChebIterationShiChi(a,1.35455469767246947469E-9,b0,b1,b2); - ChebIterationShiChi(a,-1.03257121792819495123E-9,b0,b1,b2); - ChebIterationShiChi(a,-3.56699611114982536845E-8,b0,b1,b2); - ChebIterationShiChi(a,1.44818877384267342057E-7,b0,b1,b2); - ChebIterationShiChi(a,7.82018215184051295296E-7,b0,b1,b2); - ChebIterationShiChi(a,-5.39919118403805073710E-6,b0,b1,b2); - ChebIterationShiChi(a,-3.12458202168959833422E-5,b0,b1,b2); - ChebIterationShiChi(a,8.90136741950727517826E-5,b0,b1,b2); - ChebIterationShiChi(a,2.02558474743846862168E-3,b0,b1,b2); - ChebIterationShiChi(a,2.96064440855633256972E-2,b0,b1,b2); - ChebIterationShiChi(a,1.11847751047257036625E0,b0,b1,b2); - //--- calculation - s=k*0.5*(b0-b2); - b0=-8.12435385225864036372E-18; - b1=0.0; - //--- function calls - ChebIterationShiChi(a,2.17586413290339214377E-17,b0,b1,b2); - ChebIterationShiChi(a,5.22624394924072204667E-17,b0,b1,b2); - ChebIterationShiChi(a,-9.48812110591690559363E-16,b0,b1,b2); - ChebIterationShiChi(a,5.35546311647465209166E-15,b0,b1,b2); - ChebIterationShiChi(a,-1.21009970113732918701E-14,b0,b1,b2); - ChebIterationShiChi(a,-6.00865178553447437951E-14,b0,b1,b2); - ChebIterationShiChi(a,7.16339649156028587775E-13,b0,b1,b2); - ChebIterationShiChi(a,-2.93496072607599856104E-12,b0,b1,b2); - ChebIterationShiChi(a,-1.40359438136491256904E-12,b0,b1,b2); - ChebIterationShiChi(a,8.76302288609054966081E-11,b0,b1,b2); - ChebIterationShiChi(a,-4.40092476213282340617E-10,b0,b1,b2); - ChebIterationShiChi(a,-1.87992075640569295479E-10,b0,b1,b2); - ChebIterationShiChi(a,1.31458150989474594064E-8,b0,b1,b2); - ChebIterationShiChi(a,-4.75513930924765465590E-8,b0,b1,b2); - ChebIterationShiChi(a,-2.21775018801848880741E-7,b0,b1,b2); - ChebIterationShiChi(a,1.94635531373272490962E-6,b0,b1,b2); - ChebIterationShiChi(a,4.33505889257316408893E-6,b0,b1,b2); - ChebIterationShiChi(a,-6.13387001076494349496E-5,b0,b1,b2); - ChebIterationShiChi(a,-3.13085477492997465138E-4,b0,b1,b2); - ChebIterationShiChi(a,4.97164789823116062801E-4,b0,b1,b2); - ChebIterationShiChi(a,2.64347496031374526641E-2,b0,b1,b2); - ChebIterationShiChi(a,1.11446150876699213025E0,b0,b1,b2); - c=k*0.5*(b0-b2); - } - else - { - //--- check - if(x<=88.0) - { - //--- calculation - a=(6336.0/x-212.0)/70.0; - k=MathExp(x)/x; - b0=-1.05311574154850938805E-17; - b1=0.0; - //--- function calls - ChebIterationShiChi(a,2.62446095596355225821E-17,b0,b1,b2); - ChebIterationShiChi(a,8.82090135625368160657E-17,b0,b1,b2); - ChebIterationShiChi(a,-3.38459811878103047136E-16,b0,b1,b2); - ChebIterationShiChi(a,-8.30608026366935789136E-16,b0,b1,b2); - ChebIterationShiChi(a,3.93397875437050071776E-15,b0,b1,b2); - ChebIterationShiChi(a,1.01765565969729044505E-14,b0,b1,b2); - ChebIterationShiChi(a,-4.21128170307640802703E-14,b0,b1,b2); - ChebIterationShiChi(a,-1.60818204519802480035E-13,b0,b1,b2); - ChebIterationShiChi(a,3.34714954175994481761E-13,b0,b1,b2); - ChebIterationShiChi(a,2.72600352129153073807E-12,b0,b1,b2); - ChebIterationShiChi(a,1.66894954752839083608E-12,b0,b1,b2); - ChebIterationShiChi(a,-3.49278141024730899554E-11,b0,b1,b2); - ChebIterationShiChi(a,-1.58580661666482709598E-10,b0,b1,b2); - ChebIterationShiChi(a,-1.79289437183355633342E-10,b0,b1,b2); - ChebIterationShiChi(a,1.76281629144264523277E-9,b0,b1,b2); - ChebIterationShiChi(a,1.69050228879421288846E-8,b0,b1,b2); - ChebIterationShiChi(a,1.25391771228487041649E-7,b0,b1,b2); - ChebIterationShiChi(a,1.16229947068677338732E-6,b0,b1,b2); - ChebIterationShiChi(a,1.61038260117376323993E-5,b0,b1,b2); - ChebIterationShiChi(a,3.49810375601053973070E-4,b0,b1,b2); - ChebIterationShiChi(a,1.28478065259647610779E-2,b0,b1,b2); - ChebIterationShiChi(a,1.03665722588798326712E0,b0,b1,b2); - //--- calculation - s=k*0.5*(b0-b2); - b0=8.06913408255155572081E-18; - b1=0.0; - //--- function calls - ChebIterationShiChi(a,-2.08074168180148170312E-17,b0,b1,b2); - ChebIterationShiChi(a,-5.98111329658272336816E-17,b0,b1,b2); - ChebIterationShiChi(a,2.68533951085945765591E-16,b0,b1,b2); - ChebIterationShiChi(a,4.52313941698904694774E-16,b0,b1,b2); - ChebIterationShiChi(a,-3.10734917335299464535E-15,b0,b1,b2); - ChebIterationShiChi(a,-4.42823207332531972288E-15,b0,b1,b2); - ChebIterationShiChi(a,3.49639695410806959872E-14,b0,b1,b2); - ChebIterationShiChi(a,6.63406731718911586609E-14,b0,b1,b2); - ChebIterationShiChi(a,-3.71902448093119218395E-13,b0,b1,b2); - ChebIterationShiChi(a,-1.27135418132338309016E-12,b0,b1,b2); - ChebIterationShiChi(a,2.74851141935315395333E-12,b0,b1,b2); - ChebIterationShiChi(a,2.33781843985453438400E-11,b0,b1,b2); - ChebIterationShiChi(a,2.71436006377612442764E-11,b0,b1,b2); - ChebIterationShiChi(a,-2.56600180000355990529E-10,b0,b1,b2); - ChebIterationShiChi(a,-1.61021375163803438552E-9,b0,b1,b2); - ChebIterationShiChi(a,-4.72543064876271773512E-9,b0,b1,b2); - ChebIterationShiChi(a,-3.00095178028681682282E-9,b0,b1,b2); - ChebIterationShiChi(a,7.79387474390914922337E-8,b0,b1,b2); - ChebIterationShiChi(a,1.06942765566401507066E-6,b0,b1,b2); - ChebIterationShiChi(a,1.59503164802313196374E-5,b0,b1,b2); - ChebIterationShiChi(a,3.49592575153777996871E-4,b0,b1,b2); - ChebIterationShiChi(a,1.28475387530065247392E-2,b0,b1,b2); - ChebIterationShiChi(a,1.03665693917934275131E0,b0,b1,b2); - c=k*0.5*(b0-b2); - } - else - { - //--- check - if(sg!=0) - shi=-CMath::m_maxrealnumber; - else - shi=CMath::m_maxrealnumber; - chi=CMath::m_maxrealnumber; - //--- exit the function - return; - } - } - } -//--- check - if(sg!=0) - s=-s; -//--- get result - shi=s; - chi=0.57721566490153286061+MathLog(x)+c; - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static void CTrigIntegrals::ChebIterationShiChi(const double x,const double c, - double &b0,double &b1,double &b2) - { -//--- change values - b2=b1; - b1=b0; - b0=x*b1-b2+c; - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Alglib/statistics.mqh b/Include/Math/Alglib/statistics.mqh deleted file mode 100644 index b458586..0000000 --- a/Include/Math/Alglib/statistics.mqh +++ /dev/null @@ -1,13972 +0,0 @@ -//+------------------------------------------------------------------+ -//| statistics.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 "ap.mqh" -#include "alglibinternal.mqh" -#include "linalg.mqh" -#include "specialfunctions.mqh" -//+------------------------------------------------------------------+ -//| basic statistics methods | -//+------------------------------------------------------------------+ -class CBaseStat - { -public: - CBaseStat(void); - ~CBaseStat(void); - //--- basic parameters - static bool SampleMoments(const double &cx[],const int n,double &mean,double &variance,double &skewness,double &kurtosis); - static bool SampleAdev(const double &cx[],const int n,double &adev); - static bool SampleMedian(const double &cx[],const int n,double &median); - static bool SamplePercentile(const double &cx[],const int n,const double p,double &v); - //--- covariance and correlation - static double Cov2(const double &cx[],const double &cy[],const int n); - static double PearsonCorr2(const double &cx[],const double &cy[],const int n); - static double SpearmanCorr2(const double &cx[],const double &cy[],const int n); - static bool CovM(const CMatrixDouble &cx,const int n,const int m,CMatrixDouble &c); - static bool PearsonCorrM(const CMatrixDouble &cx,const int n,const int m,CMatrixDouble &c); - static bool SpearmanCorrM(const CMatrixDouble &cx,const int n,const int m,CMatrixDouble &c); - static bool CovM2(const CMatrixDouble &cx,const CMatrixDouble &cy,const int n,const int m1,const int m2,CMatrixDouble &c); - static bool PearsonCorrM2(const CMatrixDouble &cx,const CMatrixDouble &cy,const int n,const int m1,const int m2,CMatrixDouble &c); - static bool SpearmanCorrM2(const CMatrixDouble &cx,const CMatrixDouble &cy,const int n,const int m1,const int m2,CMatrixDouble &c); - //--- obsolete functions - static double PearsonCorrelation(const double &x[],const double &y[],const int n); - static double SpearmanRankCorrelation(const double &x[],const double &y[],const int n); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CBaseStat::CBaseStat(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CBaseStat::~CBaseStat(void) - { - - } -//+------------------------------------------------------------------+ -//| Calculation of the distribution moments: mean, variance, | -//| skewness, kurtosis. | -//| INPUT PARAMETERS: | -//| X - sample | -//| N - N>=0, sample size: | -//| * if given, only leading N elements of X are | -//| processed | -//| * if not given, automatically determined from | -//| size of X | -//| OUTPUT PARAMETERS | -//| Mean - mean. | -//| Variance- variance. | -//| Skewness- skewness (if variance<>0; zero otherwise). | -//| Kurtosis- kurtosis (if variance<>0; zero otherwise). | -//+------------------------------------------------------------------+ -static bool CBaseStat::SampleMoments(const double &cx[],const int n,double &mean, - double &variance,double &skewness,double &kurtosis) - { -//--- check - if(!CAp::Assert(n>=0,__FUNCTION__+": the error variable")) - return(false); -//--- check - if(!CAp::Assert(CAp::Len(cx)>=n,__FUNCTION__+": length(x)=0, sample size: | -//| * if given, only leading N elements of X are | -//| processed | -//| * if not given, automatically determined from size | -//| of X | -//| Output parameters: | -//| ADev- ADev | -//+------------------------------------------------------------------+ -static bool CBaseStat::SampleAdev(const double &cx[],const int n, - double &adev) - { -//--- check - if(!CAp::Assert(n>=0,__FUNCTION__+": the error variable")) - return(false); -//--- check - if(!CAp::Assert(CAp::Len(cx)>=n,__FUNCTION__+": length(x)=0, sample size: | -//| * if given, only leading N elements of X are | -//| processed | -//| * if not given, automatically determined from size | -//| of X | -//| Output parameters: | -//| Median | -//+------------------------------------------------------------------+ -static bool CBaseStat::SampleMedian(const double &cx[],const int n, - double &median) - { -//--- check - if(!CAp::Assert(n>=0,__FUNCTION__+": the error variable")) - return(false); -//--- check - if(!CAp::Assert(CAp::Len(cx)>=n,__FUNCTION__+": length(x)=3. -//--- Choose X[(N-1)/2] - int i=0; - int ir=n-1; - int j=0; - int l=0; - int midp=0; - int k=(n-1)/2; - double a=0; - double tval=0; -//--- create copy - double x[]; - ArrayResizeAL(x,n); - for(int ii=0;ii=3 - while(true) - { - //--- check - if(ir<=l+1) - { - //--- 1 or 2 elements in partition - if(ir==l+1 && x[ir]x[ir]) - { - //--- swap - tval=x[l]; - x[l]=x[ir]; - x[ir]=tval; - } - //--- check - if(x[l+1]>x[ir]) - { - //--- swap - tval=x[l+1]; - x[l+1]=x[ir]; - x[ir]=tval; - } - //--- check - if(x[l]>x[l+1]) - { - //--- swap - tval=x[l]; - x[l]=x[l+1]; - x[l+1]=tval; - } - //--- change values - i=l+1; - j=ir; - a=x[l+1]; - //--- cycle - while(true) - { - //--- i++ - do - i++; - while(x[i]a); - //--- check - if(j=k) - ir=j-1; - //--- check - if(j<=k) - l=i; - } - } -//--- If N is odd, return result - if(n%2==1) - { - median=x[k]; - return(true); - } - a=x[n-1]; - for(i=k+1;i=0, sample size: | -//| * if given, only leading N elements of X are | -//| processed | -//| * if not given, automatically determined from size | -//| of X | -//| P - percentile (0<=P<=1) | -//| Output parameters: | -//| V - percentile | -//+------------------------------------------------------------------+ -static bool CBaseStat::SamplePercentile(const double &cx[],const int n, - const double p,double &v) - { -//--- check - if(!CAp::Assert(n>=0,__FUNCTION__+": the error variable")) - return(false); -//--- check - if(!CAp::Assert(CAp::Len(cx)>=n,__FUNCTION__+": length(x)=0 && p<=1,__FUNCTION__+": incorrect p")) - return(false); -//--- check - if(p==0) - { - v=cx[0]; - return(true); - } -//--- check - if(p==1) - { - v=cx[n-1]; - return(true); - } -//--- initialization - int i1=0; - double t=0; - double rbuf[]; - v=0; -//--- create copy - double x[]; - ArrayResizeAL(x,n); - for(int ii=0;ii=0, sample size: | -//| * if given, only N leading elements of X/Y are | -//| processed | -//| * if not given, automatically determined from | -//| input sizes | -//| Result: | -//| covariance (zero for N=0 or N=1) | -//+------------------------------------------------------------------+ -static double CBaseStat::Cov2(const double &cx[],const double &cy[], - const int n) - { -//--- check - if(!CAp::Assert(n>=0,__FUNCTION__+": the error variable")) - return(EMPTY_VALUE); -//--- check - if(!CAp::Assert(CAp::Len(cx)>=n,__FUNCTION__+": length(x)=n,__FUNCTION__+": length(y)=0, sample size: | -//| * if given, only N leading elements of X/Y are | -//| processed | -//| * if not given, automatically determined from | -//| input sizes | -//| Result: | -//| Pearson product-moment correlation coefficient | -//| (zero for N=0 or N=1) | -//+------------------------------------------------------------------+ -static double CBaseStat::PearsonCorr2(const double &cx[],const double &cy[], - const int n) - { -//--- check - if(!CAp::Assert(n>=0,__FUNCTION__+": the error variable")) - return(EMPTY_VALUE); -//--- check - if(!CAp::Assert(CAp::Len(cx)>=n,__FUNCTION__+": length(x)=n,__FUNCTION__+": length(y)=0, sample size: | -//| * if given, only N leading elements of X/Y are | -//| processed | -//| * if not given, automatically determined from | -//| input sizes | -//| Result: | -//| Spearman's rank correlation coefficient | -//| (zero for N=0 or N=1) | -//+------------------------------------------------------------------+ -static double CBaseStat::SpearmanCorr2(const double &cx[],const double &cy[], - const int n) - { -//--- check - if(!CAp::Assert(n>=0,__FUNCTION__+": the error variable")) - return(EMPTY_VALUE); -//--- check - if(!CAp::Assert(CAp::Len(cx)>=n,__FUNCTION__+": length(x)=n,__FUNCTION__+": length(y)=0, number of observations: | -//| * if given, only leading N rows of X are used | -//| * if not given, automatically determined from input | -//| size | -//| M - M>0, number of variables: | -//| * if given, only leading M columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| OUTPUT PARAMETERS: | -//| C - array[M,M], covariance matrix (zero if N=0 or N=1) | -//+------------------------------------------------------------------+ -static bool CBaseStat::CovM(const CMatrixDouble &cx,const int n,const int m, - CMatrixDouble &c) - { -//--- check - if(!CAp::Assert(n>=0,__FUNCTION__+": the error variable")) - return(false); -//--- check - if(!CAp::Assert(m>=1,__FUNCTION__+": the error variable")) - return(false); -//--- check - if(!CAp::Assert(CAp::Rows(cx)>=n,__FUNCTION__+": rows(x)=m || n==0,__FUNCTION__+": cols(x)=0, number of observations: | -//| * if given, only leading N rows of X are used | -//| * if not given, automatically determined from input | -//| size | -//| M - M>0, number of variables: | -//| * if given, only leading M columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| OUTPUT PARAMETERS: | -//| C - array[M,M], correlation matrix (zero if N=0 or N=1) | -//+------------------------------------------------------------------+ -static bool CBaseStat::PearsonCorrM(const CMatrixDouble &cx,const int n, - const int m,CMatrixDouble &c) - { -//--- check - if(!CAp::Assert(n>=0,__FUNCTION__+": the error variable")) - return(false); -//--- check - if(!CAp::Assert(m>=1,__FUNCTION__+": the error variable")) - return(false); -//--- check - if(!CAp::Assert(CAp::Rows(cx)>=n,__FUNCTION__+": rows(x)=m || n==0,__FUNCTION__+": cols(x)=0, number of observations: | -//| * if given, only leading N rows of X are used | -//| * if not given, automatically determined from input | -//| size | -//| M - M>0, number of variables: | -//| * if given, only leading M columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| OUTPUT PARAMETERS: | -//| C - array[M,M], correlation matrix (zero if N=0 or N=1) | -//+------------------------------------------------------------------+ -static bool CBaseStat::SpearmanCorrM(const CMatrixDouble &cx,const int n, - const int m,CMatrixDouble &c) - { -//--- check - if(!CAp::Assert(n>=0,__FUNCTION__+": the error variable")) - return(false); -//--- check - if(!CAp::Assert(m>=1,__FUNCTION__+": the error variable")) - return(false); -//--- check - if(!CAp::Assert(CAp::Rows(cx)>=n,__FUNCTION__+": rows(x)=m || n==0,__FUNCTION__+": cols(x)=0, number of observations: | -//| * if given, only leading N rows of X/Y are used | -//| * if not given, automatically determined from input | -//| sizes | -//| M1 - M1>0, number of variables in X: | -//| * if given, only leading M1 columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| M2 - M2>0, number of variables in Y: | -//| * if given, only leading M1 columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| OUTPUT PARAMETERS: | -//| C - array[M1,M2], cross-covariance matrix (zero if N=0 or| -//| N=1) | -//+------------------------------------------------------------------+ -static bool CBaseStat::CovM2(const CMatrixDouble &cx,const CMatrixDouble &cy, - const int n,const int m1,const int m2, - CMatrixDouble &c) - { -//--- check - if(!CAp::Assert(n>=0,__FUNCTION__+": the error variable")) - return(false); -//--- check - if(!CAp::Assert(m1>=1,__FUNCTION__+": the error variable")) - return(false); -//--- check - if(!CAp::Assert(m2>=1,__FUNCTION__+": the error variable")) - return(false); -//--- check - if(!CAp::Assert(CAp::Rows(cx)>=n,__FUNCTION__+": rows(x)=m1 || n==0,__FUNCTION__+": cols(x)=n,__FUNCTION__+": rows(y)=m2 || n==0,__FUNCTION__+": cols(y)=0, number of observations: | -//| * if given, only leading N rows of X/Y are used | -//| * if not given, automatically determined from input | -//| sizes | -//| M1 - M1>0, number of variables in X: | -//| * if given, only leading M1 columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| M2 - M2>0, number of variables in Y: | -//| * if given, only leading M1 columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| OUTPUT PARAMETERS: | -//| C - array[M1,M2], cross-correlation matrix (zero if N=0 | -//| or N=1) | -//+------------------------------------------------------------------+ -static bool CBaseStat::PearsonCorrM2(const CMatrixDouble &cx,const CMatrixDouble &cy, - const int n,const int m1,const int m2, - CMatrixDouble &c) - { -//--- check - if(!CAp::Assert(n>=0,__FUNCTION__+": the error variable")) - return(false); -//--- check - if(!CAp::Assert(m1>=1,__FUNCTION__+": the error variable")) - return(false); -//--- check - if(!CAp::Assert(m2>=1,__FUNCTION__+": the error variable")) - return(false); -//--- check - if(!CAp::Assert(CAp::Rows(cx)>=n,__FUNCTION__+": rows(x)=m1 || n==0,__FUNCTION__+": cols(x)=n,__FUNCTION__+": rows(y)=m2 || n==0,__FUNCTION__+": cols(y)=0, number of observations: | -//| * if given, only leading N rows of X/Y are used | -//| * if not given, automatically determined from input | -//| sizes | -//| M1 - M1>0, number of variables in X: | -//| * if given, only leading M1 columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| M2 - M2>0, number of variables in Y: | -//| * if given, only leading M1 columns of X are used | -//| * if not given, automatically determined from input | -//| size | -//| OUTPUT PARAMETERS: | -//| C - array[M1,M2], cross-correlation matrix (zero if N=0 | -//| or N=1) | -//+------------------------------------------------------------------+ -static bool CBaseStat::SpearmanCorrM2(const CMatrixDouble &cx,const CMatrixDouble &cy, - const int n,const int m1,const int m2, - CMatrixDouble &c) - { -//--- check - if(!CAp::Assert(n>=0,__FUNCTION__+": the error variable")) - return(false); -//--- check - if(!CAp::Assert(m1>=1,__FUNCTION__+": the error variable")) - return(false); -//--- check - if(!CAp::Assert(m2>=1,__FUNCTION__+": the error variable")) - return(false); -//--- check - if(!CAp::Assert(CAp::Rows(cx)>=n,__FUNCTION__+": rows(x)=m1 || n==0,__FUNCTION__+": cols(x)=n,__FUNCTION__+": rows(y)=m2 || n==0,__FUNCTION__+": cols(y)=3.580e+00) - return(8.304e-03); -//--- check - if(s>=2.322e+00) - return(4.163e-02); -//--- check - if(s>=1.704e+00) - return(6.641e-02); -//--- check - if(s>=1.303e+00) - return(1.164e-01); -//--- check - if(s>=1.003e+00) - return(1.748e-01); -//--- check - if(s>=7.584e-01) - return(2.249e-01); -//--- check - if(s>=5.468e-01) - return(2.581e-01); -//--- check - if(s>=3.555e-01) - return(3.413e-01); -//--- check - if(s>=1.759e-01) - return(3.911e-01); -//--- check - if(s>=1.741e-03) - return(4.747e-01); -//--- check - if(s>=0.000e+00) - return(5.248e-01); -//--- return result - return(0); - } -//+------------------------------------------------------------------+ -//| Tail(S, 6) | -//+------------------------------------------------------------------+ -static double CCorrTests::SpearmanTail6(const double s) - { -//--- check - if(s<1.001e+00) - return(CStudenttDistr::StudenttDistribution(4,-s)); -//--- check - if(s>=5.663e+00) - return(1.366e-03); -//--- check - if(s>=3.834e+00) - return(8.350e-03); -//--- check - if(s>=2.968e+00) - return(1.668e-02); -//--- check - if(s>=2.430e+00) - return(2.921e-02); -//--- check - if(s>=2.045e+00) - return(5.144e-02); -//--- check - if(s>=1.747e+00) - return(6.797e-02); -//--- check - if(s>=1.502e+00) - return(8.752e-02); -//--- check - if(s>=1.295e+00) - return(1.210e-01); -//--- check - if(s>=1.113e+00) - return(1.487e-01); -//--- check - if(s>=1.001e+00) - return(1.780e-01); -//--- return result - return(0); - } -//+------------------------------------------------------------------+ -//| Tail(S, 7) | -//+------------------------------------------------------------------+ -static double CCorrTests::SpearmanTail7(const double s) - { -//--- check - if(s<1.001e+00) - return(CStudenttDistr::StudenttDistribution(5,-s)); -//--- check - if(s>=8.159e+00) - return(2.081e-04); -//--- check - if(s>=5.620e+00) - return(1.393e-03); -//--- check - if(s>=4.445e+00) - return(3.398e-03); -//--- check - if(s>=3.728e+00) - return(6.187e-03); -//--- check - if(s>=3.226e+00) - return(1.200e-02); -//--- check - if(s>=2.844e+00) - return(1.712e-02); -//--- check - if(s>=2.539e+00) - return(2.408e-02); -//--- check - if(s>=2.285e+00) - return(3.320e-02); -//--- check - if(s>=2.068e+00) - return(4.406e-02); -//--- check - if(s>=1.879e+00) - return(5.478e-02); -//--- check - if(s>=1.710e+00) - return(6.946e-02); -//--- check - if(s>=1.559e+00) - return(8.331e-02); -//--- check - if(s>=1.420e+00) - return(1.001e-01); -//--- check - if(s>=1.292e+00) - return(1.180e-01); -//--- check - if(s>=1.173e+00) - return(1.335e-01); -//--- check - if(s>=1.062e+00) - return(1.513e-01); -//--- check - if(s>=1.001e+00) - return(1.770e-01); -//--- return result - return(0); - } -//+------------------------------------------------------------------+ -//| Tail(S, 8) | -//+------------------------------------------------------------------+ -static double CCorrTests::SpearmanTail8(const double s) - { -//--- check - if(s<2.001e+00) - return(CStudenttDistr::StudenttDistribution(6,-s)); -//--- check - if(s>=1.103e+01) - return(2.194e-05); -//--- check - if(s>=7.685e+00) - return(2.008e-04); -//--- check - if(s>=6.143e+00) - return(5.686e-04); -//--- check - if(s>=5.213e+00) - return(1.138e-03); -//--- check - if(s>=4.567e+00) - return(2.310e-03); -//--- check - if(s>=4.081e+00) - return(3.634e-03); -//--- check - if(s>=3.697e+00) - return(5.369e-03); -//--- check - if(s>=3.381e+00) - return(7.708e-03); -//--- check - if(s>=3.114e+00) - return(1.087e-02); -//--- check - if(s>=2.884e+00) - return(1.397e-02); -//--- check - if(s>=2.682e+00) - return(1.838e-02); -//--- check - if(s>=2.502e+00) - return(2.288e-02); -//--- check - if(s>=2.340e+00) - return(2.883e-02); -//--- check - if(s>=2.192e+00) - return(3.469e-02); -//--- check - if(s>=2.057e+00) - return(4.144e-02); -//--- check - if(s>=2.001e+00) - return(4.804e-02); -//--- return result - return(0); - } -//+------------------------------------------------------------------+ -//| Tail(S, 9) | -//+------------------------------------------------------------------+ -static double CCorrTests::SpearmanTail9(const double s) - { -//--- check - if(s<2.001e+00) - return(CStudenttDistr::StudenttDistribution(7,-s)); -//--- check - if(s>=9.989e+00) - return(2.306e-05); -//--- check - if(s>=8.069e+00) - return(8.167e-05); -//--- check - if(s>=6.890e+00) - return(1.744e-04); -//--- check - if(s>=6.077e+00) - return(3.625e-04); -//--- check - if(s>=5.469e+00) - return(6.450e-04); -//--- check - if(s>=4.991e+00) - return(1.001e-03); -//--- check - if(s>=4.600e+00) - return(1.514e-03); -//--- check - if(s>=4.272e+00) - return(2.213e-03); -//--- check - if(s>=3.991e+00) - return(2.990e-03); -//--- check - if(s>=3.746e+00) - return(4.101e-03); -//--- check - if(s>=3.530e+00) - return(5.355e-03); -//--- check - if(s>=3.336e+00) - return(6.887e-03); -//--- check - if(s>=3.161e+00) - return(8.598e-03); -//--- check - if(s>=3.002e+00) - return(1.065e-02); -//--- check - if(s>=2.855e+00) - return(1.268e-02); -//--- check - if(s>=2.720e+00) - return(1.552e-02); -//--- check - if(s>=2.595e+00) - return(1.836e-02); -//--- check - if(s>=2.477e+00) - return(2.158e-02); -//--- check - if(s>=2.368e+00) - return(2.512e-02); -//--- check - if(s>=2.264e+00) - return(2.942e-02); -//--- check - if(s>=2.166e+00) - return(3.325e-02); -//--- check - if(s>=2.073e+00) - return(3.800e-02); -//--- check - if(s>=2.001e+00) - return(4.285e-02); -//--- return result - return(0); - } -//+------------------------------------------------------------------+ -//| Pearson's correlation coefficient significance test | -//| This test checks hypotheses about whether X and Y are samples of| -//| two continuous distributions having zero correlation or whether | -//| their correlation is non-zero. | -//| The following tests are performed: | -//| * two-tailed test (null hypothesis - X and Y have zero | -//| correlation) | -//| * left-tailed test (null hypothesis - the correlation | -//| coefficient is greater than or equal to 0) | -//| * right-tailed test (null hypothesis - the correlation | -//| coefficient is less than or equal to 0). | -//| Requirements: | -//| * the number of elements in each sample is not less than 5 | -//| * normality of distributions of X and Y. | -//| Input parameters: | -//| R - Pearson's correlation coefficient for X and Y | -//| N - number of elements in samples, N>=5. | -//| Output parameters: | -//| BothTails - p-value for two-tailed test. | -//| If BothTails is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| LeftTail - p-value for left-tailed test. | -//| If LeftTail is less than the given | -//| significance level, the null hypothesis is | -//| rejected. | -//| RightTail - p-value for right-tailed test. | -//| If RightTail is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//+------------------------------------------------------------------+ -static void CCorrTests::PearsonCorrSignific(const double r,const int n, - double &bothTails,double &leftTail, - double &rightTail) - { -//--- Some special cases - if(r>=1) - { - bothTails=0.0; - leftTail=1.0; - rightTail=0.0; - return; - } -//--- check - if(r<=-1) - { - bothTails=0.0; - leftTail=0.0; - rightTail=1.0; - return; - } -//--- check - if(n<5) - { - bothTails=1.0; - leftTail=1.0; - rightTail=1.0; - return; - } -//--- create variables - double t; - double p; -//--- calculation - t=r*MathSqrt((n-2)/(1-CMath::Sqr(r))); - p=CStudenttDistr::StudenttDistribution(n-2,t); - bothTails=2*MathMin(p,1-p); - leftTail=p; - rightTail=1-p; - } -//+------------------------------------------------------------------+ -//| Spearman's rank correlation coefficient significance test | -//| This test checks hypotheses about whether X and Y are samples of | -//| two continuous distributions having zero correlation or whether | -//| their correlation is non-zero. | -//| The following tests are performed: | -//| * two-tailed test (null hypothesis - X and Y have zero | -//| correlation) | -//| * left-tailed test (null hypothesis - the correlation | -//| coefficient is greater than or equal to 0) | -//| * right-tailed test (null hypothesis - the correlation | -//| coefficient is less than or equal to 0). | -//| Requirements: | -//| * the number of elements in each sample is not less than 5. | -//| The test is non-parametric and doesn't require distributions X | -//| and Y to be normal. | -//| Input parameters: | -//| R - Spearman's rank correlation coefficient for X and Y | -//| N - number of elements in samples, N>=5. | -//| Output parameters: | -//| BothTails - p-value for two-tailed test. | -//| If BothTails is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| LeftTail - p-value for left-tailed test. | -//| If LeftTail is less than the given | -//| significance level, the null hypothesis is | -//| rejected. | -//| RightTail - p-value for right-tailed test. | -//| If RightTail is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//+------------------------------------------------------------------+ -static void CCorrTests::SpearmanRankCorrSignific(const double r,const int n, - double &bothTails,double &leftTail, - double &rightTail) - { -//--- Special case - if(n<5) - { - bothTails=1.0; - leftTail=1.0; - rightTail=1.0; - return; - } -//--- create variables - double t; - double p; -//--- General case - if(r>=1) - t=1.0E10; - else - { - //--- check - if(r<=-1) - t=-1.0E10; - else - t=r*MathSqrt((n-2)/(1-CMath::Sqr(r))); - } -//--- check - if(t<0) - { - p=SpearmanTail(t,n); - bothTails=2*p; - leftTail=p; - rightTail=1-p; - } - else - { - p=SpearmanTail(-t,n); - bothTails=2*p; - leftTail=1-p; - rightTail=p; - } - } -//+------------------------------------------------------------------+ -//| Jarque-Bera test | -//+------------------------------------------------------------------+ -class CJarqueBera - { -private: - static bool JarqueBeraStat(const double &x[],const int n,double &s); - static double JarqueBeraApprox(const int n,const double s); - static void JBCheb(double x,double c,double &tj,double &tj1,double &r); - static double JBTbl5(const double s); - static double JBTbl6(const double s); - static double JBTbl7(const double s); - static double JBTbl8(const double s); - static double JBTbl9(const double s); - static double JBTbl10(const double s); - static double JBTbl11(const double s); - static double JBTbl12(const double s); - static double JBTbl13(const double s); - static double JBTbl14(const double s); - static double JBTbl15(const double s); - static double JBTbl16(const double s); - static double JBTbl17(const double s); - static double JBTbl18(const double s); - static double JBTbl19(const double s); - static double JBTbl20(const double s); - static double JBTbl30(const double s); - static double JBTbl50(const double s); - static double JBTbl65(const double s); - static double JBTbl100(const double s); - static double JBTbl130(const double s); - static double JBTbl200(const double s); - static double JBTbl301(const double s); - static double JBTbl501(const double s); - static double JBTbl701(const double s); - static double JBTbl1401(const double s); -public: - //--- constructor, destructor - CJarqueBera(void); - ~CJarqueBera(void); - //--- method - static bool JarqueBeraTest(const double &x[],const int n,double &p); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CJarqueBera::CJarqueBera(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CJarqueBera::~CJarqueBera(void) - { - - } -//+------------------------------------------------------------------+ -//| Jarque-Bera test | -//| This test checks hypotheses about the fact that a given sample X | -//| is a sample of normal random variable. | -//| Requirements: | -//| * the number of elements in the sample is not less than 5. | -//| Input parameters: | -//| X - sample. Array whose index goes from 0 to N-1. | -//| N - size of the sample. N>=5 | -//| Output parameters: | -//| BothTails - p-value for two-tailed test. | -//| If BothTails is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| LeftTail - p-value for left-tailed test. | -//| If LeftTail is less than the given | -//| significance level, the null hypothesis is | -//| rejected. | -//| RightTail - p-value for right-tailed test. | -//| If RightTail is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| Accuracy of the approximation used (5<=N<=1951): | -//| p-value relative error (5<=N<=1951) | -//| [1, 0.1] < 1% | -//| [0.1, 0.01] < 2% | -//| [0.01, 0.001] < 6% | -//| [0.001, 0] wasn't measured | -//| For N>1951 accuracy wasn't measured but it shouldn't be sharply | -//| different from table values. | -//+------------------------------------------------------------------+ -static bool CJarqueBera::JarqueBeraTest(const double &x[],const int n, - double &p) - { -//--- create a variable - double s; -//--- N is too small - if(n<5) - { - p=1.0; - return(true); - } -//--- N is large enough - if(!JarqueBeraStat(x,n,s)) - return(false); - p=JarqueBeraApprox(n,s); -//--- successful execution - return(true); - } -//+------------------------------------------------------------------+ -//| Jarque-Bera statistics | -//+------------------------------------------------------------------+ -static bool CJarqueBera::JarqueBeraStat(const double &x[],const int n, - double &s) - { -//--- check - if(!CAp::Assert(n>1,__FUNCTION__+": the error variable")) - return(false); -//--- create variables - int i=0; - double v=0; - double v1=0; - double v2=0; - double stddev=0; - double mean=0; - double variance=0; - double skewness=0; - double kurtosis=0; -//--- Mean - for(i=0;i=5 && n<=20) - { - //--- check - if(n==5) - return(MathExp(JBTbl5(x))); - //--- check - if(n==6) - return(MathExp(JBTbl6(x))); - //--- check - if(n==7) - return(MathExp(JBTbl7(x))); - //--- check - if(n==8) - return(MathExp(JBTbl8(x))); - //--- check - if(n==9) - return(MathExp(JBTbl9(x))); - //--- check - if(n==10) - return(MathExp(JBTbl10(x))); - //--- check - if(n==11) - return(MathExp(JBTbl11(x))); - //--- check - if(n==12) - return(MathExp(JBTbl12(x))); - //--- check - if(n==13) - return(MathExp(JBTbl13(x))); - //--- check - if(n==14) - return(MathExp(JBTbl14(x))); - //--- check - if(n==15) - return(MathExp(JBTbl15(x))); - //--- check - if(n==16) - return(MathExp(JBTbl16(x))); - //--- check - if(n==17) - return(MathExp(JBTbl17(x))); - //--- check - if(n==18) - return(MathExp(JBTbl18(x))); - //--- check - if(n==19) - return(MathExp(JBTbl19(x))); - //--- check - if(n==20) - return(MathExp(JBTbl20(x))); - } -//--- N = 20, 30, 50 are tabulated. -//--- In-between values are interpolated -//--- using interpolating polynomial of the second degree. - if(n>20 && n<=50) - { - t1=-1.0/20.0; - t2=-1.0/30.0; - t3=-1.0/50.0; - t=-1.0/n; - //--- tabulation - f1=JBTbl20(x); - f2=JBTbl30(x); - f3=JBTbl50(x); - //--- interpolating - f12=((t-t2)*f1+(t1-t)*f2)/(t1-t2); - f23=((t-t3)*f2+(t2-t)*f3)/(t2-t3); - result=((t-t3)*f12+(t1-t)*f23)/(t1-t3); - //--- check - if(result>0) - result=0; - //--- return result - return(MathExp(result)); - } -//--- N = 50, 65, 100 are tabulated. -//--- In-between values are interpolated -//--- using interpolating polynomial of the second degree. - if(n>50 && n<=100) - { - t1=-1.0/50.0; - t2=-1.0/65.0; - t3=-1.0/100.0; - t=-1.0/n; - //--- tabulation - f1=JBTbl50(x); - f2=JBTbl65(x); - f3=JBTbl100(x); - //--- interpolating - f12=((t-t2)*f1+(t1-t)*f2)/(t1-t2); - f23=((t-t3)*f2+(t2-t)*f3)/(t2-t3); - result=((t-t3)*f12+(t1-t)*f23)/(t1-t3); - //--- check - if(result>0) - result=0; - //--- return result - return(MathExp(result)); - } -//--- N = 100, 130, 200 are tabulated. -//--- In-between values are interpolated -//--- using interpolating polynomial of the second degree. - if(n>100 && n<=200) - { - t1=-(1.0/100.0); - t2=-(1.0/130.0); - t3=-(1.0/200.0); - t=-(1.0/n); - //--- tabulation - f1=JBTbl100(x); - f2=JBTbl130(x); - f3=JBTbl200(x); - //--- interpolating - f12=((t-t2)*f1+(t1-t)*f2)/(t1-t2); - f23=((t-t3)*f2+(t2-t)*f3)/(t2-t3); - result=((t-t3)*f12+(t1-t)*f23)/(t1-t3); - //--- check - if(result>0) - result=0; - //--- return result - return(MathExp(result)); - } -//--- N = 200, 301, 501 are tabulated. -//--- In-between values are interpolated -//--- using interpolating polynomial of the second degree. - if(n>200 && n<=501) - { - t1=-(1.0/200.0); - t2=-(1.0/301.0); - t3=-(1.0/501.0); - t=-(1.0/n); - //--- tabulation - f1=JBTbl200(x); - f2=JBTbl301(x); - f3=JBTbl501(x); - //--- interpolating - f12=((t-t2)*f1+(t1-t)*f2)/(t1-t2); - f23=((t-t3)*f2+(t2-t)*f3)/(t2-t3); - result=((t-t3)*f12+(t1-t)*f23)/(t1-t3); - //--- check - if(result>0) - result=0; - //--- return result - return(MathExp(result)); - } -//--- N = 501, 701, 1401 are tabulated. -//--- In-between values are interpolated -//--- using interpolating polynomial of the second degree. - if(n>501 && n<=1401) - { - t1=-(1.0/501.0); - t2=-(1.0/701.0); - t3=-(1.0/1401.0); - t=-(1.0/n); - //--- tabulation - f1=JBTbl501(x); - f2=JBTbl701(x); - f3=JBTbl1401(x); - //--- interpolating - f12=((t-t2)*f1+(t1-t)*f2)/(t1-t2); - f23=((t-t3)*f2+(t2-t)*f3)/(t2-t3); - result=((t-t3)*f12+(t1-t)*f23)/(t1-t3); - //--- check - if(result>0) - result=0; - //--- return result - return(MathExp(result)); - } -//--- get result - result=-(0.5*x)+(JBTbl1401(x)+0.5*x)*MathSqrt((double)1401/(double)n); -//--- check - if(result>0) - result=0; -//--- return result - return(MathExp(result)); - } -//+------------------------------------------------------------------+ -//| Internal subroutine | -//+------------------------------------------------------------------+ -static void CJarqueBera::JBCheb(double x,double c,double &tj,double &tj1, - double &r) - { -//--- create variables - double t; -//--- change values - r+=c*tj; - t=2*x*tj1-tj; - tj=tj1; - tj1=t; - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 5 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl5(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=0.4000) - { - x=2*s/0.400000-1; - tj=1; - tj1=x; - JBCheb(x,-1.097885e-20,tj,tj1,result); - JBCheb(x,-2.854501e-20,tj,tj1,result); - JBCheb(x,-1.756616e-20,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=1.1000) - { - x=2*(s-0.400000)/0.700000-1; - tj=1; - tj1=x; - JBCheb(x,-1.324545e+00,tj,tj1,result); - JBCheb(x,-1.075941e+00,tj,tj1,result); - JBCheb(x,-9.772272e-01,tj,tj1,result); - JBCheb(x,3.175686e-01,tj,tj1,result); - JBCheb(x,-1.576162e-01,tj,tj1,result); - JBCheb(x,1.126861e-01,tj,tj1,result); - JBCheb(x,-3.434425e-02,tj,tj1,result); - JBCheb(x,-2.790359e-01,tj,tj1,result); - JBCheb(x,2.809178e-02,tj,tj1,result); - JBCheb(x,-5.479704e-01,tj,tj1,result); - JBCheb(x,3.717040e-02,tj,tj1,result); - JBCheb(x,-5.294170e-01,tj,tj1,result); - JBCheb(x,2.880632e-02,tj,tj1,result); - JBCheb(x,-3.023344e-01,tj,tj1,result); - JBCheb(x,1.601531e-02,tj,tj1,result); - JBCheb(x,-7.920403e-02,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(5.188419e+02*(s-1.100000e+00))-4.767297e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 6 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl6(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=0.2500) - { - x=2*(s-0.000000)/0.250000-1; - tj=1; - tj1=x; - JBCheb(x,-2.274707e-04,tj,tj1,result); - JBCheb(x,-5.700471e-04,tj,tj1,result); - JBCheb(x,-3.425764e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=1.3000) - { - x=2*(s-0.250000)/1.050000-1; - tj=1; - tj1=x; - JBCheb(x,-1.339000e+00,tj,tj1,result); - JBCheb(x,-2.011104e+00,tj,tj1,result); - JBCheb(x,-8.168177e-01,tj,tj1,result); - JBCheb(x,-1.085666e-01,tj,tj1,result); - JBCheb(x,7.738606e-02,tj,tj1,result); - JBCheb(x,7.022876e-02,tj,tj1,result); - JBCheb(x,3.462402e-02,tj,tj1,result); - JBCheb(x,6.908270e-03,tj,tj1,result); - JBCheb(x,-8.230772e-03,tj,tj1,result); - JBCheb(x,-1.006996e-02,tj,tj1,result); - JBCheb(x,-5.410222e-03,tj,tj1,result); - JBCheb(x,-2.893768e-03,tj,tj1,result); - JBCheb(x,8.114564e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=1.8500) - { - x=2*(s-1.300000)/0.550000-1; - tj=1; - tj1=x; - JBCheb(x,-6.794311e+00,tj,tj1,result); - JBCheb(x,-3.578700e+00,tj,tj1,result); - JBCheb(x,-1.394664e+00,tj,tj1,result); - JBCheb(x,-7.928290e-01,tj,tj1,result); - JBCheb(x,-4.813273e-01,tj,tj1,result); - JBCheb(x,-3.076063e-01,tj,tj1,result); - JBCheb(x,-1.835380e-01,tj,tj1,result); - JBCheb(x,-1.013013e-01,tj,tj1,result); - JBCheb(x,-5.058903e-02,tj,tj1,result); - JBCheb(x,-1.856915e-02,tj,tj1,result); - JBCheb(x,-6.710887e-03,tj,tj1,result); - //--- - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(1.770029e+02*(s-1.850000e+00))-1.371015e+01; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 7 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl7(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=1.4000) - { - x=2*(s-0.000000)/1.400000-1; - tj=1; - tj1=x; - JBCheb(x,-1.093681e+00,tj,tj1,result); - JBCheb(x,-1.695911e+00,tj,tj1,result); - JBCheb(x,-7.473192e-01,tj,tj1,result); - JBCheb(x,-1.203236e-01,tj,tj1,result); - JBCheb(x,6.590379e-02,tj,tj1,result); - JBCheb(x,6.291876e-02,tj,tj1,result); - JBCheb(x,3.132007e-02,tj,tj1,result); - JBCheb(x,9.411147e-03,tj,tj1,result); - JBCheb(x,-1.180067e-03,tj,tj1,result); - JBCheb(x,-3.487610e-03,tj,tj1,result); - JBCheb(x,-2.436561e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=3.0000) - { - x=2*(s-1.400000)/1.600000-1; - tj=1; - tj1=x; - JBCheb(x,-5.947854e+00,tj,tj1,result); - JBCheb(x,-2.772675e+00,tj,tj1,result); - JBCheb(x,-4.707912e-01,tj,tj1,result); - JBCheb(x,-1.691171e-01,tj,tj1,result); - JBCheb(x,-4.132795e-02,tj,tj1,result); - JBCheb(x,-1.481310e-02,tj,tj1,result); - JBCheb(x,2.867536e-03,tj,tj1,result); - JBCheb(x,8.772327e-04,tj,tj1,result); - JBCheb(x,5.033387e-03,tj,tj1,result); - JBCheb(x,-1.378277e-03,tj,tj1,result); - JBCheb(x,-2.497964e-03,tj,tj1,result); - JBCheb(x,-3.636814e-03,tj,tj1,result); - JBCheb(x,-9.581640e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=3.2000) - { - x=2*(s-3.000000)/0.200000-1; - tj=1; - tj1=x; - JBCheb(x,-7.511008e+00,tj,tj1,result); - JBCheb(x,-8.140472e-01,tj,tj1,result); - JBCheb(x,1.682053e+00,tj,tj1,result); - JBCheb(x,-2.568561e-02,tj,tj1,result); - JBCheb(x,-1.933930e+00,tj,tj1,result); - JBCheb(x,-8.140472e-01,tj,tj1,result); - JBCheb(x,-3.895025e+00,tj,tj1,result); - JBCheb(x,-8.140472e-01,tj,tj1,result); - JBCheb(x,-1.933930e+00,tj,tj1,result); - JBCheb(x,-2.568561e-02,tj,tj1,result); - JBCheb(x,1.682053e+00,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(1.824116e+03*(s-3.200000e+00))-1.440330e+01; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 8 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl8(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=1.3000) - { - x=2*(s-0.000000)/1.300000-1; - tj=1; - tj1=x; - JBCheb(x,-7.199015e-01,tj,tj1,result); - JBCheb(x,-1.095921e+00,tj,tj1,result); - JBCheb(x,-4.736828e-01,tj,tj1,result); - JBCheb(x,-1.047438e-01,tj,tj1,result); - JBCheb(x,-2.484320e-03,tj,tj1,result); - JBCheb(x,7.937923e-03,tj,tj1,result); - JBCheb(x,4.810470e-03,tj,tj1,result); - JBCheb(x,2.139780e-03,tj,tj1,result); - JBCheb(x,6.708443e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=2.0000) - { - x=2*(s-1.300000)/0.700000-1; - tj=1; - tj1=x; - JBCheb(x,-3.378966e+00,tj,tj1,result); - JBCheb(x,-7.802461e-01,tj,tj1,result); - JBCheb(x,1.547593e-01,tj,tj1,result); - JBCheb(x,-6.241042e-02,tj,tj1,result); - JBCheb(x,1.203274e-02,tj,tj1,result); - JBCheb(x,5.201990e-03,tj,tj1,result); - JBCheb(x,-5.125597e-03,tj,tj1,result); - JBCheb(x,1.584426e-03,tj,tj1,result); - JBCheb(x,2.546069e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=5.0000) - { - x=2*(s-2.000000)/3.000000-1; - tj=1; - tj1=x; - JBCheb(x,-6.828366e+00,tj,tj1,result); - JBCheb(x,-3.137533e+00,tj,tj1,result); - JBCheb(x,-5.016671e-01,tj,tj1,result); - JBCheb(x,-1.745637e-01,tj,tj1,result); - JBCheb(x,-5.189801e-02,tj,tj1,result); - JBCheb(x,-1.621610e-02,tj,tj1,result); - JBCheb(x,-6.741122e-03,tj,tj1,result); - JBCheb(x,-4.516368e-03,tj,tj1,result); - JBCheb(x,3.552085e-04,tj,tj1,result); - JBCheb(x,2.787029e-03,tj,tj1,result); - JBCheb(x,5.359774e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(5.087028e+00*(s-5.000000e+00))-1.071300e+01; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 9 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl9(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=1.3000) - { - x=2*(s-0.000000)/1.300000-1; - tj=1; - tj1=x; - JBCheb(x,-6.279320e-01,tj,tj1,result); - JBCheb(x,-9.277151e-01,tj,tj1,result); - JBCheb(x,-3.669339e-01,tj,tj1,result); - JBCheb(x,-7.086149e-02,tj,tj1,result); - JBCheb(x,-1.333816e-03,tj,tj1,result); - JBCheb(x,3.871249e-03,tj,tj1,result); - JBCheb(x,2.007048e-03,tj,tj1,result); - JBCheb(x,7.482245e-04,tj,tj1,result); - JBCheb(x,2.355615e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=2.0000) - { - x=2*(s-1.300000)/0.700000-1; - tj=1; - tj1=x; - JBCheb(x,-2.981430e+00,tj,tj1,result); - JBCheb(x,-7.972248e-01,tj,tj1,result); - JBCheb(x,1.747737e-01,tj,tj1,result); - JBCheb(x,-3.808530e-02,tj,tj1,result); - JBCheb(x,-7.888305e-03,tj,tj1,result); - JBCheb(x,9.001302e-03,tj,tj1,result); - JBCheb(x,-1.378767e-03,tj,tj1,result); - JBCheb(x,-1.108510e-03,tj,tj1,result); - JBCheb(x,5.915372e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=7.0000) - { - x=2*(s-2.000000)/5.000000-1; - tj=1; - tj1=x; - JBCheb(x,-6.387463e+00,tj,tj1,result); - JBCheb(x,-2.845231e+00,tj,tj1,result); - JBCheb(x,-1.809956e-01,tj,tj1,result); - JBCheb(x,-7.543461e-02,tj,tj1,result); - JBCheb(x,-4.880397e-03,tj,tj1,result); - JBCheb(x,-1.160074e-02,tj,tj1,result); - JBCheb(x,-7.356527e-03,tj,tj1,result); - JBCheb(x,-4.394428e-03,tj,tj1,result); - JBCheb(x,9.619892e-04,tj,tj1,result); - JBCheb(x,-2.758763e-04,tj,tj1,result); - JBCheb(x,4.790977e-05,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(2.020952e+00*(s-7.000000e+00))-9.516623e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 10 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl10(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=1.2000) - { - x=2*(s-0.000000)/1.200000-1; - tj=1; - tj1=x; - JBCheb(x,-4.590993e-01,tj,tj1,result); - JBCheb(x,-6.562730e-01,tj,tj1,result); - JBCheb(x,-2.353934e-01,tj,tj1,result); - JBCheb(x,-4.069933e-02,tj,tj1,result); - JBCheb(x,-1.849151e-03,tj,tj1,result); - JBCheb(x,8.931406e-04,tj,tj1,result); - JBCheb(x,3.636295e-04,tj,tj1,result); - JBCheb(x,1.178340e-05,tj,tj1,result); - JBCheb(x,-8.917749e-05,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=2.0000) - { - x=2*(s-1.200000)/0.800000-1; - tj=1; - tj1=x; - JBCheb(x,-2.537658e+00,tj,tj1,result); - JBCheb(x,-9.962401e-01,tj,tj1,result); - JBCheb(x,1.838715e-01,tj,tj1,result); - JBCheb(x,1.055792e-02,tj,tj1,result); - JBCheb(x,-2.580316e-02,tj,tj1,result); - JBCheb(x,1.781701e-03,tj,tj1,result); - JBCheb(x,3.770362e-03,tj,tj1,result); - JBCheb(x,-4.838983e-04,tj,tj1,result); - JBCheb(x,-6.999052e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=7.0000) - { - x=2*(s-2.000000)/5.000000-1; - tj=1; - tj1=x; - JBCheb(x,-5.337524e+00,tj,tj1,result); - JBCheb(x,-1.877029e+00,tj,tj1,result); - JBCheb(x,4.734650e-02,tj,tj1,result); - JBCheb(x,-4.249254e-02,tj,tj1,result); - JBCheb(x,3.320250e-03,tj,tj1,result); - JBCheb(x,-6.432266e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(8.711035e-01*(s-7.000000e+00))-7.212811e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 11 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl11(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=1.2000) - { - x=2*(s-0.000000)/1.200000-1; - tj=1; - tj1=x; - JBCheb(x,-4.339517e-01,tj,tj1,result); - JBCheb(x,-6.051558e-01,tj,tj1,result); - JBCheb(x,-2.000992e-01,tj,tj1,result); - JBCheb(x,-3.022547e-02,tj,tj1,result); - JBCheb(x,-9.808401e-04,tj,tj1,result); - JBCheb(x,5.592870e-04,tj,tj1,result); - JBCheb(x,3.575081e-04,tj,tj1,result); - JBCheb(x,2.086173e-04,tj,tj1,result); - JBCheb(x,6.089011e-05,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=2.2500) - { - x=2*(s-1.200000)/1.050000-1; - tj=1; - tj1=x; - JBCheb(x,-2.523221e+00,tj,tj1,result); - JBCheb(x,-1.068388e+00,tj,tj1,result); - JBCheb(x,2.179661e-01,tj,tj1,result); - JBCheb(x,-1.555524e-03,tj,tj1,result); - JBCheb(x,-3.238964e-02,tj,tj1,result); - JBCheb(x,7.364320e-03,tj,tj1,result); - JBCheb(x,4.895771e-03,tj,tj1,result); - JBCheb(x,-1.762774e-03,tj,tj1,result); - JBCheb(x,-8.201340e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=8.0000) - { - x=2*(s-2.250000)/5.750000-1; - tj=1; - tj1=x; - JBCheb(x,-5.212179e+00,tj,tj1,result); - JBCheb(x,-1.684579e+00,tj,tj1,result); - JBCheb(x,8.299519e-02,tj,tj1,result); - JBCheb(x,-3.606261e-02,tj,tj1,result); - JBCheb(x,7.310869e-03,tj,tj1,result); - JBCheb(x,-3.320115e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(5.715445e-01*(s-8.000000e+00))-6.845834e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 12 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl12(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=1.0000) - { - x=2*(s-0.000000)/1.000000-1; - tj=1; - tj1=x; - JBCheb(x,-2.736742e-01,tj,tj1,result); - JBCheb(x,-3.657836e-01,tj,tj1,result); - JBCheb(x,-1.047209e-01,tj,tj1,result); - JBCheb(x,-1.319599e-02,tj,tj1,result); - JBCheb(x,-5.545631e-04,tj,tj1,result); - JBCheb(x,9.280445e-05,tj,tj1,result); - JBCheb(x,2.815679e-05,tj,tj1,result); - JBCheb(x,-2.213519e-05,tj,tj1,result); - JBCheb(x,1.256838e-05,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=3.0000) - { - x=2*(s-1.000000)/2.000000-1; - tj=1; - tj1=x; - JBCheb(x,-2.573947e+00,tj,tj1,result); - JBCheb(x,-1.515287e+00,tj,tj1,result); - JBCheb(x,3.611880e-01,tj,tj1,result); - JBCheb(x,-3.271311e-02,tj,tj1,result); - JBCheb(x,-6.495815e-02,tj,tj1,result); - JBCheb(x,4.141186e-02,tj,tj1,result); - JBCheb(x,7.180886e-04,tj,tj1,result); - JBCheb(x,-1.388211e-02,tj,tj1,result); - JBCheb(x,4.890761e-03,tj,tj1,result); - JBCheb(x,3.233175e-03,tj,tj1,result); - JBCheb(x,-2.946156e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=12.0000) - { - x=2*(s-3.000000)/9.000000-1; - tj=1; - tj1=x; - JBCheb(x,-5.947819e+00,tj,tj1,result); - JBCheb(x,-2.034157e+00,tj,tj1,result); - JBCheb(x,6.878986e-02,tj,tj1,result); - JBCheb(x,-4.078603e-02,tj,tj1,result); - JBCheb(x,6.990977e-03,tj,tj1,result); - JBCheb(x,-2.866215e-03,tj,tj1,result); - JBCheb(x,3.897866e-03,tj,tj1,result); - JBCheb(x,2.512252e-03,tj,tj1,result); - JBCheb(x,2.073743e-03,tj,tj1,result); - JBCheb(x,3.022621e-03,tj,tj1,result); - JBCheb(x,1.501343e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(2.877243e-01*(s-1.200000e+01))-7.936839e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 13 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl13(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=1.0000) - { - x=2*(s-0.000000)/1.000000-1; - tj=1; - tj1=x; - JBCheb(x,-2.713276e-01,tj,tj1,result); - JBCheb(x,-3.557541e-01,tj,tj1,result); - JBCheb(x,-9.459092e-02,tj,tj1,result); - JBCheb(x,-1.044145e-02,tj,tj1,result); - JBCheb(x,-2.546132e-04,tj,tj1,result); - JBCheb(x,1.002374e-04,tj,tj1,result); - JBCheb(x,2.349456e-05,tj,tj1,result); - JBCheb(x,-7.025669e-05,tj,tj1,result); - JBCheb(x,-1.590242e-05,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=3.0000) - { - x=2*(s-1.000000)/2.000000-1; - tj=1; - tj1=x; - JBCheb(x,-2.454383e+00,tj,tj1,result); - JBCheb(x,-1.467539e+00,tj,tj1,result); - JBCheb(x,3.270774e-01,tj,tj1,result); - JBCheb(x,-8.075763e-03,tj,tj1,result); - JBCheb(x,-6.611647e-02,tj,tj1,result); - JBCheb(x,2.990785e-02,tj,tj1,result); - JBCheb(x,8.109212e-03,tj,tj1,result); - JBCheb(x,-1.135031e-02,tj,tj1,result); - JBCheb(x,5.915919e-04,tj,tj1,result); - JBCheb(x,3.522390e-03,tj,tj1,result); - JBCheb(x,-1.144701e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=13.0000) - { - x=2*(s-3.000000)/10.000000-1; - tj=1; - tj1=x; - JBCheb(x,-5.736127e+00,tj,tj1,result); - JBCheb(x,-1.920809e+00,tj,tj1,result); - JBCheb(x,1.175858e-01,tj,tj1,result); - JBCheb(x,-4.002049e-02,tj,tj1,result); - JBCheb(x,1.158966e-02,tj,tj1,result); - JBCheb(x,-3.157781e-03,tj,tj1,result); - JBCheb(x,2.762172e-03,tj,tj1,result); - JBCheb(x,5.780347e-04,tj,tj1,result); - JBCheb(x,-1.193310e-03,tj,tj1,result); - JBCheb(x,-2.442421e-05,tj,tj1,result); - JBCheb(x,2.547756e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(2.799944e-01*(s-1.300000e+01))-7.566269e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 14 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl14(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=1.0000) - { - x=2*(s-0.000000)/1.000000-1; - tj=1; - tj1=x; - JBCheb(x,-2.698527e-01,tj,tj1,result); - JBCheb(x,-3.479081e-01,tj,tj1,result); - JBCheb(x,-8.640733e-02,tj,tj1,result); - JBCheb(x,-8.466899e-03,tj,tj1,result); - JBCheb(x,-1.469485e-04,tj,tj1,result); - JBCheb(x,2.150009e-05,tj,tj1,result); - JBCheb(x,1.965975e-05,tj,tj1,result); - JBCheb(x,-4.710210e-05,tj,tj1,result); - JBCheb(x,-1.327808e-05,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=3.0000) - { - x=2*(s-1.000000)/2.000000-1; - tj=1; - tj1=x; - JBCheb(x,-2.350359e+00,tj,tj1,result); - JBCheb(x,-1.421365e+00,tj,tj1,result); - JBCheb(x,2.960468e-01,tj,tj1,result); - JBCheb(x,1.149167e-02,tj,tj1,result); - JBCheb(x,-6.361109e-02,tj,tj1,result); - JBCheb(x,1.976022e-02,tj,tj1,result); - JBCheb(x,1.082700e-02,tj,tj1,result); - JBCheb(x,-8.563328e-03,tj,tj1,result); - JBCheb(x,-1.453123e-03,tj,tj1,result); - JBCheb(x,2.917559e-03,tj,tj1,result); - JBCheb(x,-1.151067e-05,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=15.0000) - { - x=2*(s-3.000000)/12.000000-1; - tj=1; - tj1=x; - JBCheb(x,-5.746892e+00,tj,tj1,result); - JBCheb(x,-2.010441e+00,tj,tj1,result); - JBCheb(x,1.566146e-01,tj,tj1,result); - JBCheb(x,-5.129690e-02,tj,tj1,result); - JBCheb(x,1.929724e-02,tj,tj1,result); - JBCheb(x,-2.524227e-03,tj,tj1,result); - JBCheb(x,3.192933e-03,tj,tj1,result); - JBCheb(x,-4.254730e-04,tj,tj1,result); - JBCheb(x,1.620685e-03,tj,tj1,result); - JBCheb(x,7.289618e-04,tj,tj1,result); - JBCheb(x,-2.112350e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(2.590621e-01*(s-1.500000e+01))-7.632238e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 15 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl15(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=2.0000) - { - x=2*(s-0.000000)/2.000000-1; - tj=1; - tj1=x; - JBCheb(x,-1.043660e+00,tj,tj1,result); - JBCheb(x,-1.361653e+00,tj,tj1,result); - JBCheb(x,-3.009497e-01,tj,tj1,result); - JBCheb(x,4.951784e-02,tj,tj1,result); - JBCheb(x,4.377903e-02,tj,tj1,result); - JBCheb(x,1.003253e-02,tj,tj1,result); - JBCheb(x,-1.271309e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=5.0000) - { - x=2*(s-2.000000)/3.000000-1; - tj=1; - tj1=x; - JBCheb(x,-3.582778e+00,tj,tj1,result); - JBCheb(x,-8.349578e-01,tj,tj1,result); - JBCheb(x,9.476514e-02,tj,tj1,result); - JBCheb(x,-2.717385e-02,tj,tj1,result); - JBCheb(x,1.222591e-02,tj,tj1,result); - JBCheb(x,-6.635124e-03,tj,tj1,result); - JBCheb(x,2.815993e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=17.0000) - { - x=2*(s-5.000000)/12.000000-1; - tj=1; - tj1=x; - JBCheb(x,-6.115476e+00,tj,tj1,result); - JBCheb(x,-1.655936e+00,tj,tj1,result); - JBCheb(x,8.404310e-02,tj,tj1,result); - JBCheb(x,-2.663794e-02,tj,tj1,result); - JBCheb(x,8.868618e-03,tj,tj1,result); - JBCheb(x,1.381447e-03,tj,tj1,result); - JBCheb(x,9.444801e-04,tj,tj1,result); - JBCheb(x,-1.581503e-04,tj,tj1,result); - JBCheb(x,-9.468696e-04,tj,tj1,result); - JBCheb(x,1.728509e-03,tj,tj1,result); - JBCheb(x,1.206470e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(1.927937e-01*(s-1.700000e+01))-7.700983e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 16 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl16(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=2.0000) - { - x=2*(s-0.000000)/2.000000-1; - tj=1; - tj1=x; - JBCheb(x,-1.002570e+00,tj,tj1,result); - JBCheb(x,-1.298141e+00,tj,tj1,result); - JBCheb(x,-2.832803e-01,tj,tj1,result); - JBCheb(x,3.877026e-02,tj,tj1,result); - JBCheb(x,3.539436e-02,tj,tj1,result); - JBCheb(x,8.439658e-03,tj,tj1,result); - JBCheb(x,-4.756911e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=5.0000) - { - x=2*(s-2.000000)/3.000000-1; - tj=1; - tj1=x; - JBCheb(x,-3.486198e+00,tj,tj1,result); - JBCheb(x,-8.242944e-01,tj,tj1,result); - JBCheb(x,1.020002e-01,tj,tj1,result); - JBCheb(x,-3.130531e-02,tj,tj1,result); - JBCheb(x,1.512373e-02,tj,tj1,result); - JBCheb(x,-8.054876e-03,tj,tj1,result); - JBCheb(x,3.556839e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=20.0000) - { - x=2*(s-5.000000)/15.000000-1; - tj=1; - tj1=x; - JBCheb(x,-6.241608e+00,tj,tj1,result); - JBCheb(x,-1.832655e+00,tj,tj1,result); - JBCheb(x,1.340545e-01,tj,tj1,result); - JBCheb(x,-3.361143e-02,tj,tj1,result); - JBCheb(x,1.283219e-02,tj,tj1,result); - JBCheb(x,3.484549e-03,tj,tj1,result); - JBCheb(x,1.805968e-03,tj,tj1,result); - JBCheb(x,-2.057243e-03,tj,tj1,result); - JBCheb(x,-1.454439e-03,tj,tj1,result); - JBCheb(x,-2.177513e-03,tj,tj1,result); - JBCheb(x,-1.819209e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(2.391580e-01*(s-2.000000e+01))-7.963205e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 17 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl17(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=3.0000) - { - x=2*(s-0.000000)/3.000000-1; - tj=1; - tj1=x; - JBCheb(x,-1.566973e+00,tj,tj1,result); - JBCheb(x,-1.810330e+00,tj,tj1,result); - JBCheb(x,-4.840039e-02,tj,tj1,result); - JBCheb(x,2.337294e-01,tj,tj1,result); - JBCheb(x,-5.383549e-04,tj,tj1,result); - JBCheb(x,-5.556515e-02,tj,tj1,result); - JBCheb(x,-8.656965e-03,tj,tj1,result); - JBCheb(x,1.404569e-02,tj,tj1,result); - JBCheb(x,6.447867e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=6.0000) - { - x=2*(s-3.000000)/3.000000-1; - tj=1; - tj1=x; - JBCheb(x,-3.905684e+00,tj,tj1,result); - JBCheb(x,-6.222920e-01,tj,tj1,result); - JBCheb(x,4.146667e-02,tj,tj1,result); - JBCheb(x,-4.809176e-03,tj,tj1,result); - JBCheb(x,1.057028e-03,tj,tj1,result); - JBCheb(x,-1.211838e-04,tj,tj1,result); - JBCheb(x,-4.099683e-04,tj,tj1,result); - JBCheb(x,1.161105e-04,tj,tj1,result); - JBCheb(x,2.225465e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=24.0000) - { - x=2*(s-6.000000)/18.000000-1; - tj=1; - tj1=x; - JBCheb(x,-6.594282e+00,tj,tj1,result); - JBCheb(x,-1.917838e+00,tj,tj1,result); - JBCheb(x,1.455980e-01,tj,tj1,result); - JBCheb(x,-2.999589e-02,tj,tj1,result); - JBCheb(x,5.604263e-03,tj,tj1,result); - JBCheb(x,-3.484445e-03,tj,tj1,result); - JBCheb(x,-1.819937e-03,tj,tj1,result); - JBCheb(x,-2.930390e-03,tj,tj1,result); - JBCheb(x,2.771761e-04,tj,tj1,result); - JBCheb(x,-6.232581e-04,tj,tj1,result); - JBCheb(x,-7.029083e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(2.127771e-01*(s-2.400000e+01))-8.400197e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 18 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl18(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=3.0000) - { - x=2*(s-0.000000)/3.000000-1; - tj=1; - tj1=x; - JBCheb(x,-1.526802e+00,tj,tj1,result); - JBCheb(x,-1.762373e+00,tj,tj1,result); - JBCheb(x,-5.598890e-02,tj,tj1,result); - JBCheb(x,2.189437e-01,tj,tj1,result); - JBCheb(x,5.971721e-03,tj,tj1,result); - JBCheb(x,-4.823067e-02,tj,tj1,result); - JBCheb(x,-1.064501e-02,tj,tj1,result); - JBCheb(x,1.014932e-02,tj,tj1,result); - JBCheb(x,5.953513e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=6.0000) - { - x=2*(s-3.000000)/3.000000-1; - tj=1; - tj1=x; - JBCheb(x,-3.818669e+00,tj,tj1,result); - JBCheb(x,-6.070918e-01,tj,tj1,result); - JBCheb(x,4.277196e-02,tj,tj1,result); - JBCheb(x,-4.879817e-03,tj,tj1,result); - JBCheb(x,6.887357e-04,tj,tj1,result); - JBCheb(x,1.638451e-05,tj,tj1,result); - JBCheb(x,1.502800e-04,tj,tj1,result); - JBCheb(x,-3.165796e-05,tj,tj1,result); - JBCheb(x,5.034960e-05,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=20.0000) - { - x=2*(s-6.000000)/14.000000-1; - tj=1; - tj1=x; - JBCheb(x,-6.010656e+00,tj,tj1,result); - JBCheb(x,-1.496296e+00,tj,tj1,result); - JBCheb(x,1.002227e-01,tj,tj1,result); - JBCheb(x,-2.338250e-02,tj,tj1,result); - JBCheb(x,4.137036e-03,tj,tj1,result); - JBCheb(x,-2.586202e-03,tj,tj1,result); - JBCheb(x,-9.736384e-04,tj,tj1,result); - JBCheb(x,1.332251e-03,tj,tj1,result); - JBCheb(x,1.877982e-03,tj,tj1,result); - JBCheb(x,-1.160963e-05,tj,tj1,result); - JBCheb(x,-2.547247e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(1.684623e-01*(s-2.000000e+01))-7.428883e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 19 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl19(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=3.0000) - { - x=2*(s-0.000000)/3.000000-1; - tj=1; - tj1=x; - JBCheb(x,-1.490213e+00,tj,tj1,result); - JBCheb(x,-1.719633e+00,tj,tj1,result); - JBCheb(x,-6.459123e-02,tj,tj1,result); - JBCheb(x,2.034878e-01,tj,tj1,result); - JBCheb(x,1.113868e-02,tj,tj1,result); - JBCheb(x,-4.030922e-02,tj,tj1,result); - JBCheb(x,-1.054022e-02,tj,tj1,result); - JBCheb(x,7.525623e-03,tj,tj1,result); - JBCheb(x,5.277360e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=6.0000) - { - x=2*(s-3.000000)/3.000000-1; - tj=1; - tj1=x; - JBCheb(x,-3.744750e+00,tj,tj1,result); - JBCheb(x,-5.977749e-01,tj,tj1,result); - JBCheb(x,4.223716e-02,tj,tj1,result); - JBCheb(x,-5.363889e-03,tj,tj1,result); - JBCheb(x,5.711774e-04,tj,tj1,result); - JBCheb(x,-5.557257e-04,tj,tj1,result); - JBCheb(x,4.254794e-04,tj,tj1,result); - JBCheb(x,9.034207e-05,tj,tj1,result); - JBCheb(x,5.498107e-05,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=20.0000) - { - x=2*(s-6.000000)/14.000000-1; - tj=1; - tj1=x; - JBCheb(x,-5.872768e+00,tj,tj1,result); - JBCheb(x,-1.430689e+00,tj,tj1,result); - JBCheb(x,1.136575e-01,tj,tj1,result); - JBCheb(x,-1.726627e-02,tj,tj1,result); - JBCheb(x,3.421110e-03,tj,tj1,result); - JBCheb(x,-1.581510e-03,tj,tj1,result); - JBCheb(x,-5.559520e-04,tj,tj1,result); - JBCheb(x,-6.838208e-04,tj,tj1,result); - JBCheb(x,8.428839e-04,tj,tj1,result); - JBCheb(x,-7.170682e-04,tj,tj1,result); - JBCheb(x,-6.006647e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(1.539373e-01*(s-2.000000e+01))-7.206941e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 20 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl20(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=4.0000) - { - x=2*(s-0.000000)/4.000000-1; - tj=1; - tj1=x; - JBCheb(x,-1.854794e+00,tj,tj1,result); - JBCheb(x,-1.948947e+00,tj,tj1,result); - JBCheb(x,1.632184e-01,tj,tj1,result); - JBCheb(x,2.139397e-01,tj,tj1,result); - JBCheb(x,-1.006237e-01,tj,tj1,result); - JBCheb(x,-3.810031e-02,tj,tj1,result); - JBCheb(x,3.573620e-02,tj,tj1,result); - JBCheb(x,9.951242e-03,tj,tj1,result); - JBCheb(x,-1.274092e-02,tj,tj1,result); - JBCheb(x,-3.464196e-03,tj,tj1,result); - JBCheb(x,4.882139e-03,tj,tj1,result); - JBCheb(x,1.575144e-03,tj,tj1,result); - JBCheb(x,-1.822804e-03,tj,tj1,result); - JBCheb(x,-7.061348e-04,tj,tj1,result); - JBCheb(x,5.908404e-04,tj,tj1,result); - JBCheb(x,1.978353e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=15.0000) - { - x=2*(s-4.000000)/11.000000-1; - tj=1; - tj1=x; - JBCheb(x,-5.030989e+00,tj,tj1,result); - JBCheb(x,-1.327151e+00,tj,tj1,result); - JBCheb(x,1.346404e-01,tj,tj1,result); - JBCheb(x,-2.840051e-02,tj,tj1,result); - JBCheb(x,7.578551e-03,tj,tj1,result); - JBCheb(x,-9.813886e-04,tj,tj1,result); - JBCheb(x,5.905973e-05,tj,tj1,result); - JBCheb(x,-5.358489e-04,tj,tj1,result); - JBCheb(x,-3.450795e-04,tj,tj1,result); - JBCheb(x,-6.941157e-04,tj,tj1,result); - JBCheb(x,-7.432418e-04,tj,tj1,result); - JBCheb(x,-2.070537e-04,tj,tj1,result); - JBCheb(x,9.375654e-04,tj,tj1,result); - JBCheb(x,5.367378e-04,tj,tj1,result); - JBCheb(x,9.890859e-04,tj,tj1,result); - JBCheb(x,6.679782e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=25.0000) - { - x=2*(s-15.000000)/10.000000-1; - tj=1; - tj1=x; - JBCheb(x,-7.015854e+00,tj,tj1,result); - JBCheb(x,-7.487737e-01,tj,tj1,result); - JBCheb(x,2.244254e-02,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(1.318007e-01*(s-2.500000e+01))-7.742185e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 30 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl30(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=4.0000) - { - x=2*(s-0.000000)/4.000000-1; - tj=1; - tj1=x; - JBCheb(x,-1.630822e+00,tj,tj1,result); - JBCheb(x,-1.724298e+00,tj,tj1,result); - JBCheb(x,7.872756e-02,tj,tj1,result); - JBCheb(x,1.658268e-01,tj,tj1,result); - JBCheb(x,-3.573597e-02,tj,tj1,result); - JBCheb(x,-2.994157e-02,tj,tj1,result); - JBCheb(x,5.994825e-03,tj,tj1,result); - JBCheb(x,7.394303e-03,tj,tj1,result); - JBCheb(x,-5.785029e-04,tj,tj1,result); - JBCheb(x,-1.990264e-03,tj,tj1,result); - JBCheb(x,-1.037838e-04,tj,tj1,result); - JBCheb(x,6.755546e-04,tj,tj1,result); - JBCheb(x,1.774473e-04,tj,tj1,result); - JBCheb(x,-2.821395e-04,tj,tj1,result); - JBCheb(x,-1.392603e-04,tj,tj1,result); - JBCheb(x,1.353313e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=15.0000) - { - x=2*(s-4.000000)/11.000000-1; - tj=1; - tj1=x; - JBCheb(x,-4.539322e+00,tj,tj1,result); - JBCheb(x,-1.197018e+00,tj,tj1,result); - JBCheb(x,1.396848e-01,tj,tj1,result); - JBCheb(x,-2.804293e-02,tj,tj1,result); - JBCheb(x,6.867928e-03,tj,tj1,result); - JBCheb(x,-2.768758e-03,tj,tj1,result); - JBCheb(x,5.211792e-04,tj,tj1,result); - JBCheb(x,4.925799e-04,tj,tj1,result); - JBCheb(x,5.046235e-04,tj,tj1,result); - JBCheb(x,-9.536469e-05,tj,tj1,result); - JBCheb(x,-6.489642e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=25.0000) - { - x=2*(s-15.000000)/10.000000-1; - tj=1; - tj1=x; - JBCheb(x,-6.263462e+00,tj,tj1,result); - JBCheb(x,-6.177316e-01,tj,tj1,result); - JBCheb(x,2.590637e-02,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(1.028212e-01*(s-2.500000e+01))-6.855288e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 50 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl50(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=4.0000) - { - x=2*(s-0.000000)/4.000000-1; - tj=1; - tj1=x; - JBCheb(x,-1.436279e+00,tj,tj1,result); - JBCheb(x,-1.519711e+00,tj,tj1,result); - JBCheb(x,1.148699e-02,tj,tj1,result); - JBCheb(x,1.001204e-01,tj,tj1,result); - JBCheb(x,-3.207620e-03,tj,tj1,result); - JBCheb(x,-1.034778e-02,tj,tj1,result); - JBCheb(x,-1.220322e-03,tj,tj1,result); - JBCheb(x,1.033260e-03,tj,tj1,result); - JBCheb(x,2.588280e-04,tj,tj1,result); - JBCheb(x,-1.851653e-04,tj,tj1,result); - JBCheb(x,-1.287733e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=15.0000) - { - x=2*(s-4.000000)/11.000000-1; - tj=1; - tj1=x; - JBCheb(x,-4.234645e+00,tj,tj1,result); - JBCheb(x,-1.189127e+00,tj,tj1,result); - JBCheb(x,1.429738e-01,tj,tj1,result); - JBCheb(x,-3.058822e-02,tj,tj1,result); - JBCheb(x,9.086776e-03,tj,tj1,result); - JBCheb(x,-1.445783e-03,tj,tj1,result); - JBCheb(x,1.311671e-03,tj,tj1,result); - JBCheb(x,-7.261298e-04,tj,tj1,result); - JBCheb(x,6.496987e-04,tj,tj1,result); - JBCheb(x,2.605249e-04,tj,tj1,result); - JBCheb(x,8.162282e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=25.0000) - { - x=2*(s-15.000000)/10.000000-1; - tj=1; - tj1=x; - JBCheb(x,-5.921095e+00,tj,tj1,result); - JBCheb(x,-5.888603e-01,tj,tj1,result); - JBCheb(x,3.080113e-02,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(9.313116e-02*(s-2.500000e+01))-6.479154e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 65 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl65(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=4.0000) - { - x=2*(s-0.000000)/4.000000-1; - tj=1; - tj1=x; - JBCheb(x,-1.360024e+00,tj,tj1,result); - JBCheb(x,-1.434631e+00,tj,tj1,result); - JBCheb(x,-6.514580e-03,tj,tj1,result); - JBCheb(x,7.332038e-02,tj,tj1,result); - JBCheb(x,1.158197e-03,tj,tj1,result); - JBCheb(x,-5.121233e-03,tj,tj1,result); - JBCheb(x,-1.051056e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=15.0000) - { - x=2*(s-4.000000)/11.000000-1; - tj=1; - tj1=x; - JBCheb(x,-4.148601e+00,tj,tj1,result); - JBCheb(x,-1.214233e+00,tj,tj1,result); - JBCheb(x,1.487977e-01,tj,tj1,result); - JBCheb(x,-3.424720e-02,tj,tj1,result); - JBCheb(x,1.116715e-02,tj,tj1,result); - JBCheb(x,-4.043152e-03,tj,tj1,result); - JBCheb(x,1.718149e-03,tj,tj1,result); - JBCheb(x,-1.313701e-03,tj,tj1,result); - JBCheb(x,3.097305e-04,tj,tj1,result); - JBCheb(x,2.181031e-04,tj,tj1,result); - JBCheb(x,1.256975e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=25.0000) - { - x=2*(s-15.000000)/10.000000-1; - tj=1; - tj1=x; - JBCheb(x,-5.858951e+00,tj,tj1,result); - JBCheb(x,-5.895179e-01,tj,tj1,result); - JBCheb(x,2.933237e-02,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(9.443768e-02*(s-2.500000e+01))-6.419137e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 100 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl100(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=4.0000) - { - x=2*(s-0.000000)/4.000000-1; - tj=1; - tj1=x; - JBCheb(x,-1.257021e+00,tj,tj1,result); - JBCheb(x,-1.313418e+00,tj,tj1,result); - JBCheb(x,-1.628931e-02,tj,tj1,result); - JBCheb(x,4.264287e-02,tj,tj1,result); - JBCheb(x,1.518487e-03,tj,tj1,result); - JBCheb(x,-1.499826e-03,tj,tj1,result); - JBCheb(x,-4.836044e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=15.0000) - { - x=2*(s-4.000000)/11.000000-1; - tj=1; - tj1=x; - JBCheb(x,-4.056508e+00,tj,tj1,result); - JBCheb(x,-1.279690e+00,tj,tj1,result); - JBCheb(x,1.665746e-01,tj,tj1,result); - JBCheb(x,-4.290012e-02,tj,tj1,result); - JBCheb(x,1.487632e-02,tj,tj1,result); - JBCheb(x,-5.704465e-03,tj,tj1,result); - JBCheb(x,2.211669e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=25.0000) - { - x=2*(s-15.000000)/10.000000-1; - tj=1; - tj1=x; - JBCheb(x,-5.866099e+00,tj,tj1,result); - JBCheb(x,-6.399767e-01,tj,tj1,result); - JBCheb(x,2.498208e-02,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(1.080097e-01*(s-2.500000e+01))-6.481094e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 130 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl130(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=4.0000) - { - x=2*(s-0.000000)/4.000000-1; - tj=1; - tj1=x; - JBCheb(x,-1.207999e+00,tj,tj1,result); - JBCheb(x,-1.253864e+00,tj,tj1,result); - JBCheb(x,-1.618032e-02,tj,tj1,result); - JBCheb(x,3.112729e-02,tj,tj1,result); - JBCheb(x,1.210546e-03,tj,tj1,result); - JBCheb(x,-4.732602e-04,tj,tj1,result); - JBCheb(x,-2.410527e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=15.0000) - { - x=2*(s-4.000000)/11.000000-1; - tj=1; - tj1=x; - JBCheb(x,-4.026324e+00,tj,tj1,result); - JBCheb(x,-1.331990e+00,tj,tj1,result); - JBCheb(x,1.779129e-01,tj,tj1,result); - JBCheb(x,-4.674749e-02,tj,tj1,result); - JBCheb(x,1.669077e-02,tj,tj1,result); - JBCheb(x,-5.679136e-03,tj,tj1,result); - JBCheb(x,8.833221e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=25.0000) - { - x=2*(s-15.000000)/10.000000-1; - tj=1; - tj1=x; - JBCheb(x,-5.893951e+00,tj,tj1,result); - JBCheb(x,-6.475304e-01,tj,tj1,result); - JBCheb(x,3.116734e-02,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(1.045722e-01*(s-2.500000e+01))-6.510314e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 200 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl200(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=4.0000) - { - x=2*(s-0.000000)/4.000000-1; - tj=1; - tj1=x; - JBCheb(x,-1.146155e+00,tj,tj1,result); - JBCheb(x,-1.177398e+00,tj,tj1,result); - JBCheb(x,-1.297970e-02,tj,tj1,result); - JBCheb(x,1.869745e-02,tj,tj1,result); - JBCheb(x,1.717288e-04,tj,tj1,result); - JBCheb(x,-1.982108e-04,tj,tj1,result); - JBCheb(x,6.427636e-05,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=15.0000) - { - x=2*(s-4.000000)/11.000000-1; - tj=1; - tj1=x; - JBCheb(x,-4.034235e+00,tj,tj1,result); - JBCheb(x,-1.455006e+00,tj,tj1,result); - JBCheb(x,1.942996e-01,tj,tj1,result); - JBCheb(x,-4.973795e-02,tj,tj1,result); - JBCheb(x,1.418812e-02,tj,tj1,result); - JBCheb(x,-3.156778e-03,tj,tj1,result); - JBCheb(x,4.896705e-05,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=25.0000) - { - x=2*(s-15.000000)/10.000000-1; - tj=1; - tj1=x; - JBCheb(x,-6.086071e+00,tj,tj1,result); - JBCheb(x,-7.152176e-01,tj,tj1,result); - JBCheb(x,3.725393e-02,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(1.132404e-01*(s-2.500000e+01))-6.764034e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 301 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl301(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=4.0000) - { - x=2*(s-0.000000)/4.000000-1; - tj=1; - tj1=x; - JBCheb(x,-1.104290e+00,tj,tj1,result); - JBCheb(x,-1.125800e+00,tj,tj1,result); - JBCheb(x,-9.595847e-03,tj,tj1,result); - JBCheb(x,1.219666e-02,tj,tj1,result); - JBCheb(x,1.502210e-04,tj,tj1,result); - JBCheb(x,-6.414543e-05,tj,tj1,result); - JBCheb(x,6.754115e-05,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=15.0000) - { - x=2*(s-4.000000)/11.000000-1; - tj=1; - tj1=x; - JBCheb(x,-4.065955e+00,tj,tj1,result); - JBCheb(x,-1.582060e+00,tj,tj1,result); - JBCheb(x,2.004472e-01,tj,tj1,result); - JBCheb(x,-4.709092e-02,tj,tj1,result); - JBCheb(x,1.105779e-02,tj,tj1,result); - JBCheb(x,1.197391e-03,tj,tj1,result); - JBCheb(x,-8.386780e-04,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=25.0000) - { - x=2*(s-15.000000)/10.000000-1; - tj=1; - tj1=x; - JBCheb(x,-6.311384e+00,tj,tj1,result); - JBCheb(x,-7.918763e-01,tj,tj1,result); - JBCheb(x,3.626584e-02,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(1.293626e-01*(s-2.500000e+01))-7.066995e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 501 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl501(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=4.0000) - { - x=2*(s-0.000000)/4.000000-1; - tj=1; - tj1=x; - JBCheb(x,-1.067426e+00,tj,tj1,result); - JBCheb(x,-1.079765e+00,tj,tj1,result); - JBCheb(x,-5.463005e-03,tj,tj1,result); - JBCheb(x,6.875659e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - if(s<=15.0000) - { - x=2*(s-4.000000)/11.000000-1; - tj=1; - tj1=x; - JBCheb(x,-4.127574e+00,tj,tj1,result); - JBCheb(x,-1.740694e+00,tj,tj1,result); - JBCheb(x,2.044502e-01,tj,tj1,result); - JBCheb(x,-3.746714e-02,tj,tj1,result); - JBCheb(x,3.810594e-04,tj,tj1,result); - JBCheb(x,1.197111e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=25.0000) - { - x=2*(s-15.000000)/10.000000-1; - tj=1; - tj1=x; - JBCheb(x,-6.628194e+00,tj,tj1,result); - JBCheb(x,-8.846221e-01,tj,tj1,result); - JBCheb(x,4.386405e-02,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(1.418332e-01*(s-2.500000e+01))-7.468952e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 701 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl701(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=4.0000) - { - x=2*(s-0.000000)/4.000000-1; - tj=1; - tj1=x; - JBCheb(x,-1.050999e+00,tj,tj1,result); - JBCheb(x,-1.059769e+00,tj,tj1,result); - JBCheb(x,-3.922680e-03,tj,tj1,result); - JBCheb(x,4.847054e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=15.0000) - { - x=2*(s-4.000000)/11.000000-1; - tj=1; - tj1=x; - JBCheb(x,-4.192182e+00,tj,tj1,result); - JBCheb(x,-1.860007e+00,tj,tj1,result); - JBCheb(x,1.963942e-01,tj,tj1,result); - JBCheb(x,-2.838711e-02,tj,tj1,result); - JBCheb(x,-2.893112e-04,tj,tj1,result); - JBCheb(x,2.159788e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=25.0000) - { - x=2*(s-15.000000)/10.000000-1; - tj=1; - tj1=x; - JBCheb(x,-6.917851e+00,tj,tj1,result); - JBCheb(x,-9.817020e-01,tj,tj1,result); - JBCheb(x,5.383727e-02,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(1.532706e-01*(s-2.500000e+01))-7.845715e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tabulation at the size of the array is 1401 | -//+------------------------------------------------------------------+ -static double CJarqueBera::JBTbl1401(const double s) - { -//--- create variables - double result=0; - double x; - double tj; - double tj1; -//--- check - if(s<=4.0000) - { - x=2*(s-0.000000)/4.000000-1; - tj=1; - tj1=x; - JBCheb(x,-1.026266e+00,tj,tj1,result); - JBCheb(x,-1.030061e+00,tj,tj1,result); - JBCheb(x,-1.259222e-03,tj,tj1,result); - JBCheb(x,2.536254e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=15.0000) - { - x=2*(s-4.000000)/11.000000-1; - tj=1; - tj1=x; - JBCheb(x,-4.329849e+00,tj,tj1,result); - JBCheb(x,-2.095443e+00,tj,tj1,result); - JBCheb(x,1.759363e-01,tj,tj1,result); - JBCheb(x,-7.751359e-03,tj,tj1,result); - JBCheb(x,-6.124368e-03,tj,tj1,result); - JBCheb(x,-1.793114e-03,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } -//--- check - if(s<=25.0000) - { - x=2*(s-15.000000)/10.000000-1; - tj=1; - tj1=x; - JBCheb(x,-7.544330e+00,tj,tj1,result); - JBCheb(x,-1.225382e+00,tj,tj1,result); - JBCheb(x,5.392349e-02,tj,tj1,result); - //--- check - if(result>0) - result=0; - //--- return result - return(result); - } - result=-(2.019375e-01*(s-2.500000e+01))-8.715788e+00; -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Mann-Whitney U-test | -//+------------------------------------------------------------------+ -class CMannWhitneyU - { -private: - static void UCheb(const double x,const double c,double &tj,double &tj1,double &r); - static double UThreePointInterpolate(const double p1,const double p2,const double p3,const int n); - static double USigma(double s,const int n1,const int n2); - static double USigma000(const int n1,const int n2); - static double USigma075(const int n1,const int n2); - static double USigma150(const int n1,const int n2); - static double USigma225(const int n1,const int n2); - static double USigma300(const int n1,const int n2); - static double USigma333(const int n1,const int n2); - static double USigma367(const int n1,const int n2); - static double USigma400(const int n1,const int n2); - static double UTbln5n5(const double s); - static double UTbln5n6(const double s); - static double UTbln5n7(const double s); - static double UTbln5n8(const double s); - static double UTbln5n9(const double s); - static double UTbln5n10(const double s); - static double UTbln5n11(const double s); - static double UTbln5n12(const double s); - static double UTbln5n13(const double s); - static double UTbln5n14(const double s); - static double UTbln5n15(const double s); - static double UTbln5n16(const double s); - static double UTbln5n17(const double s); - static double UTbln5n18(const double s); - static double UTbln5n19(const double s); - static double UTbln5n20(const double s); - static double UTbln5n21(const double s); - static double UTbln5n22(const double s); - static double UTbln5n23(const double s); - static double UTbln5n24(const double s); - static double UTbln5n25(const double s); - static double UTbln5n26(const double s); - static double UTbln5n27(const double s); - static double UTbln5n28(const double s); - static double UTbln5n29(const double s); - static double UTbln5n30(const double s); - static double UTbln5n100(const double s); - static double UTbln6n6(const double s); - static double UTbln6n7(const double s); - static double UTbln6n8(const double s); - static double UTbln6n9(const double s); - static double UTbln6n10(const double s); - static double UTbln6n11(const double s); - static double UTbln6n12(const double s); - static double UTbln6n13(const double s); - static double UTbln6n14(const double s); - static double UTbln6n15(const double s); - static double UTbln6n30(const double s); - static double UTbln6n100(const double s); - static double UTbln7n7(const double s); - static double UTbln7n8(const double s); - static double UTbln7n9(const double s); - static double UTbln7n10(const double s); - static double UTbln7n11(const double s); - static double UTbln7n12(const double s); - static double UTbln7n13(const double s); - static double UTbln7n14(const double s); - static double UTbln7n15(const double s); - static double UTbln7n30(const double s); - static double UTbln7n100(const double s); - static double UTbln8n8(const double s); - static double UTbln8n9(const double s); - static double UTbln8n10(const double s); - static double UTbln8n11(const double s); - static double UTbln8n12(const double s); - static double UTbln8n13(const double s); - static double UTbln8n14(const double s); - static double UTbln8n15(const double s); - static double UTbln8n30(const double s); - static double UTbln8n100(const double s); - static double UTbln9n9(const double s); - static double UTbln9n10(const double s); - static double UTbln9n11(const double s); - static double UTbln9n12(const double s); - static double UTbln9n13(const double s); - static double UTbln9n14(const double s); - static double UTbln9n15(const double s); - static double UTbln9n30(const double s); - static double UTbln9n100(const double s); - static double UTbln10n10(const double s); - static double UTbln10n11(const double s); - static double UTbln10n12(const double s); - static double UTbln10n13(const double s); - static double UTbln10n14(const double s); - static double UTbln10n15(const double s); - static double UTbln10n30(const double s); - static double UTbln10n100(const double s); - static double UTbln11n11(const double s); - static double UTbln11n12(const double s); - static double UTbln11n13(const double s); - static double UTbln11n14(const double s); - static double UTbln11n15(const double s); - static double UTbln11n30(const double s); - static double UTbln11n100(const double s); - static double UTbln12n12(const double s); - static double UTbln12n13(const double s); - static double UTbln12n14(const double s); - static double UTbln12n15(const double s); - static double UTbln12n30(const double s); - static double UTbln12n100(const double s); - static double UTbln13n13(const double s); - static double UTbln13n14(const double s); - static double UTbln13n15(const double s); - static double UTbln13n30(const double s); - static double UTbln13n100(const double s); - static double UTbln14n14(const double s); - static double UTbln14n15(const double s); - static double UTbln14n30(const double s); - static double UTbln14n100(const double s); -public: - //--- constructor, destructor - CMannWhitneyU(void); - ~CMannWhitneyU(void); - //--- method - static void CMannWhitneyUTest(const double &x[],const int n,const double &y[],const int m,double &bothTails,double &leftTail,double &rightTail); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMannWhitneyU::CMannWhitneyU(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMannWhitneyU::~CMannWhitneyU(void) - { - - } -//+------------------------------------------------------------------+ -//| Mann-Whitney U-test | -//| This test checks hypotheses about whether X and Y are samples of | -//| two continuous distributions of the same shape and same median or| -//| whether their medians are different. | -//| The following tests are performed: | -//| * two-tailed test (null hypothesis - the medians are equal) | -//| * left-tailed test (null hypothesis - the median of the first| -//| sample is greater than or equal to the median of the second| -//| sample) | -//| * right-tailed test (null hypothesis - the median of the | -//| first sample is less than or equal to the median of the | -//| second sample). | -//| Requirements: | -//| * the samples are independent | -//| * X and Y are continuous distributions (or discrete | -//| distributions well- approximating continuous distributions)| -//| * distributions of X and Y have the same shape. The only | -//| possible difference is their position (i.e. the value of | -//| the median) | -//| * the number of elements in each sample is not less than 5 | -//| * the scale of measurement should be ordinal, interval or | -//| ratio (i.e. the test could not be applied to nominal | -//| variables). | -//| The test is non-parametric and doesn't require distributions to | -//| be normal. | -//| Input parameters: | -//| X - sample 1. Array whose index goes from 0 to N-1. | -//| N - size of the sample. N>=5 | -//| Y - sample 2. Array whose index goes from 0 to M-1. | -//| M - size of the sample. M>=5 | -//| Output parameters: | -//| BothTails - p-value for two-tailed test. | -//| If BothTails is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| LeftTail - p-value for left-tailed test. | -//| If LeftTail is less than the given | -//| significance level, the null hypothesis is | -//| rejected. | -//| RightTail - p-value for right-tailed test. | -//| If RightTail is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| To calculate p-values, special approximation is used. This | -//| method lets us calculate p-values with satisfactory accuracy in | -//| interval [0.0001, 1]. There is no approximation outside the | -//| [0.0001, 1] interval. Therefore, if the significance level | -//| outlies this interval, the test returns 0.0001. | -//| Relative precision of approximation of p-value: | -//| N M Max.err. Rms.err. | -//| 5..10 N..10 1.4e-02 6.0e-04 | -//| 5..10 N..100 2.2e-02 5.3e-06 | -//| 10..15 N..15 1.0e-02 3.2e-04 | -//| 10..15 N..100 1.0e-02 2.2e-05 | -//| 15..100 N..100 6.1e-03 2.7e-06 | -//| For N,M>100 accuracy checks weren't put into practice, but taking| -//| into account characteristics of asymptotic approximation used, | -//| precision should not be sharply different from the values for | -//| interval [5, 100]. | -//+------------------------------------------------------------------+ -static void CMannWhitneyU::CMannWhitneyUTest(const double &x[],const int n, - const double &y[],const int m, - double &bothTails,double &leftTail, - double &rightTail) - { -//--- Prepare - if(n<=4 || m<=4) - { - bothTails=1.0; - leftTail=1.0; - rightTail=1.0; - return; - } -//--- create variables - int i=0; - int j=0; - int k=0; - int t=0; - double tmp=0; - int tmpi=0; - int ns=n+m; - double r[]; - int c[]; - double u=0; - double p=0; - double mp=0; - double s=0; - double sigma=0; - double mu=0; - int tiecount=0; - int tiesize[]; -//--- allocation - ArrayResizeAL(r,ns); - ArrayResizeAL(c,ns); -//--- fiiling arrays - for(i=0;i=r[t-1]) - t=1; - else - { - //--- change positions - tmp=r[k-1]; - r[k-1]=r[t-1]; - r[t-1]=tmp; - tmpi=c[k-1]; - c[k-1]=c[t-1]; - c[t-1]=tmpi; - t=k; - } - } - i++; - } - while(i<=ns); - //--- change value - i=ns-1; - do - { - //--- change positions - tmp=r[i]; - r[i]=r[0]; - r[0]=tmp; - tmpi=c[i]; - c[i]=c[0]; - c[0]=tmpi; - t=1; - //--- cycle - while(t!=0) - { - k=2*t; - //--- check - if(k>i) - t=0; - else - { - //--- check - if(kr[k-1]) - k++; - //--- check - if(r[t-1]>=r[k-1]) - t=0; - else - { - //--- change positions - tmp=r[k-1]; - r[k-1]=r[t-1]; - r[t-1]=tmp; - tmpi=c[k-1]; - c[k-1]=c[t-1]; - c[t-1]=tmpi; - t=k; - } - } - } - i--; - } - while(i>=1); - } -//--- compute tied ranks - i=0; - tiecount=0; - ArrayResizeAL(tiesize,ns-1+1); -//--- cycle - while(i29) - { - f0=UTbln5n15(s); - f1=UTbln5n30(s); - f2=UTbln5n100(s); - //--- return result - return(UThreePointInterpolate(f0,f1,f2,MathMax(n1,n2))); - } - } -//--- n1=6,n2=6,7,8... - if(MathMin(n1,n2)==6) - { - //--- check - if(MathMax(n1,n2)==6) - return(UTbln6n6(s)); - //--- check - if(MathMax(n1,n2)==7) - return(UTbln6n7(s)); - //--- check - if(MathMax(n1,n2)==8) - return(UTbln6n8(s)); - //--- check - if(MathMax(n1,n2)==9) - return(UTbln6n9(s)); - //--- check - if(MathMax(n1,n2)==10) - return(UTbln6n10(s)); - //--- check - if(MathMax(n1,n2)==11) - return(UTbln6n11(s)); - //--- check - if(MathMax(n1,n2)==12) - return(UTbln6n12(s)); - //--- check - if(MathMax(n1,n2)==13) - return(UTbln6n13(s)); - //--- check - if(MathMax(n1,n2)==14) - return(UTbln6n14(s)); - //--- check - if(MathMax(n1,n2)==15) - return(UTbln6n15(s)); - //--- check - if(MathMax(n1,n2)>15) - { - f0=UTbln6n15(s); - f1=UTbln6n30(s); - f2=UTbln6n100(s); - //--- return result - return(UThreePointInterpolate(f0,f1,f2,MathMax(n1,n2))); - } - } -//--- n1=7,n2=7,8,9... - if(MathMin(n1,n2)==7) - { - //--- check - if(MathMax(n1,n2)==7) - return(UTbln7n7(s)); - //--- check - if(MathMax(n1,n2)==8) - return(UTbln7n8(s)); - //--- check - if(MathMax(n1,n2)==9) - return(UTbln7n9(s)); - //--- check - if(MathMax(n1,n2)==10) - return(UTbln7n10(s)); - //--- check - if(MathMax(n1,n2)==11) - return(UTbln7n11(s)); - //--- check - if(MathMax(n1,n2)==12) - return(UTbln7n12(s)); - //--- check - if(MathMax(n1,n2)==13) - return(UTbln7n13(s)); - //--- check - if(MathMax(n1,n2)==14) - return(UTbln7n14(s)); - //--- check - if(MathMax(n1,n2)==15) - return(UTbln7n15(s)); - //--- check - if(MathMax(n1,n2)>15) - { - f0=UTbln7n15(s); - f1=UTbln7n30(s); - f2=UTbln7n100(s); - //--- return result - return(UThreePointInterpolate(f0,f1,f2,MathMax(n1,n2))); - } - } -//--- n1=8,n2=8,9,10... - if(MathMin(n1,n2)==8) - { - //--- check - if(MathMax(n1,n2)==8) - return(UTbln8n8(s)); - //--- check - if(MathMax(n1,n2)==9) - return(UTbln8n9(s)); - //--- check - if(MathMax(n1,n2)==10) - return(UTbln8n10(s)); - //--- check - if(MathMax(n1,n2)==11) - return(UTbln8n11(s)); - //--- check - if(MathMax(n1,n2)==12) - return(UTbln8n12(s)); - //--- check - if(MathMax(n1,n2)==13) - return(UTbln8n13(s)); - //--- check - if(MathMax(n1,n2)==14) - return(UTbln8n14(s)); - //--- check - if(MathMax(n1,n2)==15) - return(UTbln8n15(s)); - //--- check - if(MathMax(n1,n2)>15) - { - f0=UTbln8n15(s); - f1=UTbln8n30(s); - f2=UTbln8n100(s); - //--- return result - return(UThreePointInterpolate(f0,f1,f2,MathMax(n1,n2))); - } - } -//--- n1=9,n2=9,10,11... - if(MathMin(n1,n2)==9) - { - //--- check - if(MathMax(n1,n2)==9) - return(UTbln9n9(s)); - //--- check - if(MathMax(n1,n2)==10) - return(UTbln9n10(s)); - //--- check - if(MathMax(n1,n2)==11) - return(UTbln9n11(s)); - //--- check - if(MathMax(n1,n2)==12) - return(UTbln9n12(s)); - //--- check - if(MathMax(n1,n2)==13) - return(UTbln9n13(s)); - //--- check - if(MathMax(n1,n2)==14) - return(UTbln9n14(s)); - //--- check - if(MathMax(n1,n2)==15) - return(UTbln9n15(s)); - //--- check - if(MathMax(n1,n2)>15) - { - f0=UTbln9n15(s); - f1=UTbln9n30(s); - f2=UTbln9n100(s); - //--- return result - return(UThreePointInterpolate(f0,f1,f2,MathMax(n1,n2))); - } - } -//--- n1=10,n2=10,11,12... - if(MathMin(n1,n2)==10) - { - //--- check - if(MathMax(n1,n2)==10) - return(UTbln10n10(s)); - //--- check - if(MathMax(n1,n2)==11) - return(UTbln10n11(s)); - //--- check - if(MathMax(n1,n2)==12) - return(UTbln10n12(s)); - //--- check - if(MathMax(n1,n2)==13) - return(UTbln10n13(s)); - //--- check - if(MathMax(n1,n2)==14) - return(UTbln10n14(s)); - //--- check - if(MathMax(n1,n2)==15) - return(UTbln10n15(s)); - //--- check - if(MathMax(n1,n2)>15) - { - f0=UTbln10n15(s); - f1=UTbln10n30(s); - f2=UTbln10n100(s); - //--- return result - return(UThreePointInterpolate(f0,f1,f2,MathMax(n1,n2))); - } - } -//--- n1=11,n2=11,12,13... - if(MathMin(n1,n2)==11) - { - //--- check - if(MathMax(n1,n2)==11) - return(UTbln11n11(s)); - //--- check - if(MathMax(n1,n2)==12) - return(UTbln11n12(s)); - //--- check - if(MathMax(n1,n2)==13) - return(UTbln11n13(s)); - //--- check - if(MathMax(n1,n2)==14) - return(UTbln11n14(s)); - //--- check - if(MathMax(n1,n2)==15) - return(UTbln11n15(s)); - //--- check - if(MathMax(n1,n2)>15) - { - f0=UTbln11n15(s); - f1=UTbln11n30(s); - f2=UTbln11n100(s); - //--- return result - return(UThreePointInterpolate(f0,f1,f2,MathMax(n1,n2))); - } - } -//--- n1=12,n2=12,13,14... - if(MathMin(n1,n2)==12) - { - //--- check - if(MathMax(n1,n2)==12) - return(UTbln12n12(s)); - //--- check - if(MathMax(n1,n2)==13) - return(UTbln12n13(s)); - //--- check - if(MathMax(n1,n2)==14) - return(UTbln12n14(s)); - //--- check - if(MathMax(n1,n2)==15) - return(UTbln12n15(s)); - //--- check - if(MathMax(n1,n2)>15) - { - f0=UTbln12n15(s); - f1=UTbln12n30(s); - f2=UTbln12n100(s); - //--- return result - return(UThreePointInterpolate(f0,f1,f2,MathMax(n1,n2))); - } - } -//--- n1=13,n2=13,14,15... - if(MathMin(n1,n2)==13) - { - //--- check - if(MathMax(n1,n2)==13) - return(UTbln13n13(s)); - //--- check - if(MathMax(n1,n2)==14) - return(UTbln13n14(s)); - //--- check - if(MathMax(n1,n2)==15) - return(UTbln13n15(s)); - //--- check - if(MathMax(n1,n2)>15) - { - f0=UTbln13n15(s); - f1=UTbln13n30(s); - f2=UTbln13n100(s); - //--- return result - return(UThreePointInterpolate(f0,f1,f2,MathMax(n1,n2))); - } - } -//--- n1=14,n2=14,15... - if(MathMin(n1,n2)==14) - { - //--- check - if(MathMax(n1,n2)==14) - return(UTbln14n14(s)); - //--- check - if(MathMax(n1,n2)==15) - return(UTbln14n15(s)); - //--- check - if(MathMax(n1,n2)>15) - { - f0=UTbln14n15(s); - f1=UTbln14n30(s); - f2=UTbln14n100(s); - //--- return result - return(UThreePointInterpolate(f0,f1,f2,MathMax(n1,n2))); - } - } -//--- n1>=15,n2>=15... - if(s>4) - s=4; -//--- check - if(s<3) - { - //--- calculation - s0=0.000000e+00; - f0=USigma000(n1,n2); - s1=7.500000e-01; - f1=USigma075(n1,n2); - s2=1.500000e+00; - f2=USigma150(n1,n2); - s3=2.250000e+00; - f3=USigma225(n1,n2); - s4=3.000000e+00; - f4=USigma300(n1,n2); - //--- calculation result - f1=((s-s0)*f1-(s-s1)*f0)/(s1-s0); - f2=((s-s0)*f2-(s-s2)*f0)/(s2-s0); - f3=((s-s0)*f3-(s-s3)*f0)/(s3-s0); - f4=((s-s0)*f4-(s-s4)*f0)/(s4-s0); - f2=((s-s1)*f2-(s-s2)*f1)/(s2-s1); - f3=((s-s1)*f3-(s-s3)*f1)/(s3-s1); - f4=((s-s1)*f4-(s-s4)*f1)/(s4-s1); - f3=((s-s2)*f3-(s-s3)*f2)/(s3-s2); - f4=((s-s2)*f4-(s-s4)*f2)/(s4-s2); - f4=((s-s3)*f4-(s-s4)*f3)/(s4-s3); - //--- return result - return(f4); - } -//--- else - s0=3.000000e+00; - f0=USigma300(n1,n2); - s1=3.333333e+00; - f1=USigma333(n1,n2); - s2=3.666667e+00; - f2=USigma367(n1,n2); - s3=4.000000e+00; - f3=USigma400(n1,n2); -//--- calculation result - f1=((s-s0)*f1-(s-s1)*f0)/(s1-s0); - f2=((s-s0)*f2-(s-s2)*f0)/(s2-s0); - f3=((s-s0)*f3-(s-s3)*f0)/(s3-s0); - f2=((s-s1)*f2-(s-s2)*f1)/(s2-s1); - f3=((s-s1)*f3-(s-s3)*f1)/(s3-s1); - f3=((s-s2)*f3-(s-s3)*f2)/(s3-s2); -//--- return result - return(f3); - } -//+------------------------------------------------------------------+ -//| Sign test | -//+------------------------------------------------------------------+ -class CSignTest - { -public: - //--- constructor, destructor - CSignTest(void); - ~CSignTest(void); - //--- method - static void OneSampleSignTest(const double &x[],const int n,const double median,double &bothTails,double &leftTail,double &rightTail); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CSignTest::CSignTest(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSignTest::~CSignTest(void) - { - - } -//+------------------------------------------------------------------+ -//| Sign test | -//| This test checks three hypotheses about the median of the given | -//| sample. | -//| The following tests are performed: | -//| * two-tailed test (null hypothesis - the median is equal to | -//| the given value) | -//| * left-tailed test (null hypothesis - the median is greater | -//| than or equal to the given value) | -//| * right-tailed test (null hypothesis - the median is less | -//| than or equal to the given value) | -//| Requirements: | -//| * the scale of measurement should be ordinal, interval or | -//| ratio (i.e. the test could not be applied to nominal | -//| variables). | -//| The test is non-parametric and doesn't require distribution X to | -//| be normal | -//| Input parameters: | -//| X - sample. Array whose index goes from 0 to N-1. | -//| N - size of the sample. | -//| Median - assumed median value. | -//| Output parameters: | -//| BothTails - p-value for two-tailed test. | -//| If BothTails is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| LeftTail - p-value for left-tailed test. | -//| If LeftTail is less than the given | -//| significance level, the null hypothesis is | -//| rejected. | -//| RightTail - p-value for right-tailed test. | -//| If RightTail is less than the given | -//| significance levelthe null hypothesis is | -//| rejected. | -//| While calculating p-values high-precision binomial distribution | -//| approximation is used, so significance levels have about 15 exact| -//| digits. | -//+------------------------------------------------------------------+ -static void CSignTest::OneSampleSignTest(const double &x[],const int n, - const double median,double &bothTails, - double &leftTail,double &rightTail) - { -//--- check - if(n<=1) - { - bothTails=1.0; - leftTail=1.0; - rightTail=1.0; - return; - } -//--- Calculate: -//--- GTCnt - count of x[i]>Median -//--- NECnt - count of x[i]<>Median - int i; - int greater=0; - int noteql=0; -//--- calculation - for(i=0;imedian) - greater++; - //--- check - if(x[i]!=median) - noteql++; - } -//--- check - if(noteql==0) - { - bothTails=0.0; - leftTail=0.0; - rightTail=0.0; - return; - } -//--- calculation - bothTails=2*CBinomialDistr::BinomialDistribution(MathMin(greater,noteql-greater),noteql,0.5); - leftTail=CBinomialDistr::BinomialDistribution(greater,noteql,0.5); - rightTail=CBinomialDistr::BinomialComplDistribution(greater-1,noteql,0.5); - } -//+------------------------------------------------------------------+ -//| Studentt tests | -//+------------------------------------------------------------------+ -class CStudentTests - { -public: - //--- constructor, destructor - CStudentTests(void); - ~CStudentTests(void); - //--- methods - static void StudentTest1(const double &x[],const int n,const double mean,double &bothTails,double &leftTail,double &rightTail); - static void StudentTest2(const double &x[],const int n,const double &y[],const int m,double &bothTails,double &leftTail,double &rightTail); - static void UnequalVarianceTest(const double &x[],const int n,const double &y[],const int m,double &bothTails,double &leftTail,double &rightTail); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CStudentTests::CStudentTests(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CStudentTests::~CStudentTests(void) - { - - } -//+------------------------------------------------------------------+ -//| One-sample t-test | -//| This test checks three hypotheses about the mean of the given | -//| sample. The following tests are performed: | -//| * two-tailed test (null hypothesis - the mean is equal to the| -//| given value) | -//| * left-tailed test (null hypothesis - the mean is greater | -//| than or equal to the given value) | -//| * right-tailed test (null hypothesis - the mean is less than | -//| or equal to the given value). | -//| The test is based on the assumption that a given sample has a | -//| normal distribution and an unknown dispersion. If the | -//| distribution sharply differs from normal, the test will work | -//| incorrectly. | -//| Input parameters: | -//| X - sample. Array whose index goes from 0 to N-1. | -//| N - size of sample. | -//| Mean - assumed value of the mean. | -//| Output parameters: | -//| BothTails - p-value for two-tailed test. | -//| If BothTails is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| LeftTail - p-value for left-tailed test. | -//| If LeftTail is less than the given | -//| significance level, the null hypothesis is | -//| rejected. | -//| RightTail - p-value for right-tailed test. | -//| If RightTail is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//+------------------------------------------------------------------+ -static void CStudentTests::StudentTest1(const double &x[],const int n, - const double mean,double &bothTails, - double &leftTail,double &rightTail) - { -//--- check - if(n<=1) - { - bothTails=1.0; - leftTail=1.0; - rightTail=1.0; - //--- exit the function - return; - } -//--- create variables - int i; - double xmean; - double xvariance=0; - double xstddev=0; - double v1=0; - double v2=0; - double stat=0; - double s=0; -//--- Mean - xmean=0; - for(i=0;i0) - p=1-0.5*CIncBetaF::IncompleteBeta(df/2,0.5,df/(df+CMath::Sqr(stat))); - else - p=0.5*CIncBetaF::IncompleteBeta(df/2,0.5,df/(df+CMath::Sqr(stat))); -//--- get parameters - bothTails=2*MathMin(p,1-p); - leftTail=p; - rightTail=1-p; - } -//+------------------------------------------------------------------+ -//| Variance tests | -//+------------------------------------------------------------------+ -class CVarianceTests - { -public: - //--- constructor, destructor - CVarianceTests(void); - ~CVarianceTests(void); - //--- method - static void FTest(const double &x[],const int n,const double &y[],const int m,double &bothTails,double &leftTail,double &rightTail); - static void OneSampleVarianceTest(const double &x[],const int n,const double variance,double &bothTails,double &leftTail,double &rightTail); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CVarianceTests::CVarianceTests(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CVarianceTests::~CVarianceTests(void) - { - - } -//+------------------------------------------------------------------+ -//| Two-sample F-test | -//| This test checks three hypotheses about dispersions of the given | -//| samples. The following tests are performed: | -//| * two-tailed test (null hypothesis - the dispersions are | -//| equal) | -//| * left-tailed test (null hypothesis - the dispersion of the | -//| first sample is greater than or equal to the dispersion of | -//| the second sample). | -//| * right-tailed test (null hypothesis - the dispersion of the | -//| first sample is less than or equal to the dispersion of | -//| the second sample) | -//| The test is based on the following assumptions: | -//| * the given samples have normal distributions | -//| * the samples are independent. | -//| Input parameters: | -//| X - sample 1. Array whose index goes from 0 to N-1. | -//| N - sample size. | -//| Y - sample 2. Array whose index goes from 0 to M-1. | -//| M - sample size. | -//| Output parameters: | -//| BothTails - p-value for two-tailed test. | -//| If BothTails is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//| LeftTail - p-value for left-tailed test. | -//| If LeftTail is less than the given | -//| significance level, the null hypothesis is | -//| rejected. | -//| RightTail - p-value for right-tailed test. | -//| If RightTail is less than the given | -//| significance level the null hypothesis is | -//| rejected. | -//+------------------------------------------------------------------+ -static void CVarianceTests::FTest(const double &x[],const int n,const double &y[], - const int m,double &bothTails,double &leftTail, - double &rightTail) - { -//--- check - if(n<=2 || m<=2) - { - bothTails=1.0; - leftTail=1.0; - rightTail=1.0; - //--- exit the function - return; - } -//--- create variables - int i; - double xmean=0; - double ymean=0; - double xvar=0; - double yvar=0; - int df1=0; - int df2=0; - double stat=0; -//--- Mean - for(i=0; i<=n-1; i++) - xmean+=x[i]; - xmean=xmean/n; - for(i=0; i<=m-1; i++) - ymean+=y[i]; - ymean=ymean/m; -//--- Variance (using corrected two-pass algorithm) - for(i=0;i=r[t-1]) - t=1; - else - { - //--- change values - tmp=r[k-1]; - r[k-1]=r[t-1]; - r[t-1]=tmp; - tmpi=c[k-1]; - c[k-1]=c[t-1]; - c[t-1]=tmpi; - t=k; - } - } - i++; - } - while(i<=ns); - //--- change value - i=ns-1; - //--- cycle - do - { - //--- change values - tmp=r[i]; - r[i]=r[0]; - r[0]=tmp; - tmpi=c[i]; - c[i]=c[0]; - c[0]=tmpi; - t=1; - //--- cycle - while(t!=0) - { - k=2*t; - //--- check - if(k>i) - t=0; - else - { - //--- check - if(kr[k-1]) - k++; - } - //--- check - if(r[t-1]>=r[k-1]) - t=0; - else - { - //--- change values - tmp=r[k-1]; - r[k-1]=r[t-1]; - r[t-1]=tmp; - tmpi=c[k-1]; - c[k-1]=c[t-1]; - c[t-1]=tmpi; - t=k; - } - } - } - i--; - } - while(i>=1); - } -//--- compute tied ranks - i=0; - while(ie) - w+=r[i]; - } -//--- Result - mu=(double)(ns*(ns+1))/4.0; - sigma=MathSqrt((double)(ns*(ns+1)*(2*ns+1))/24.0); - s=(w-mu)/sigma; -//--- check - if(s<=0) - { - p=MathExp(WSigma(-((w-mu)/sigma),ns)); - mp=1-MathExp(WSigma(-((w-1-mu)/sigma),ns)); - } - else - { - mp=MathExp(WSigma((w-mu)/sigma,ns)); - p=1-MathExp(WSigma((w+1-mu)/sigma,ns)); - } -//--- get parameters - bothTails=MathMax(2*MathMin(p,mp),1.0E-4); - leftTail=MathMax(p,1.0E-4); - rightTail=MathMax(mp,1.0E-4); - } -//+------------------------------------------------------------------+ -//| Sequential Chebyshev interpolation. | -//+------------------------------------------------------------------+ -static void CWilcoxonSignedRank::WCheb(const double x,const double c, - double &tj,double &tj1,double &r) - { -//--- create a variable - double t; -//--- change values - r+=c*tj; - t=2*x*tj1-tj; - tj=tj1; - tj1=t; - } -//+------------------------------------------------------------------+ -//| Tail(S, 5) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W5(const double s) - { -//--- create variables - int w=0; - double r=0; - w=(int)MathRound(-(3.708099e+00*s)+7.500000e+00); -//--- check - if(w>=7) - r=-6.931e-01; -//--- check - if(w==6) - r=-9.008e-01; -//--- check - if(w==5) - r=-1.163e+00; -//--- check - if(w==4) - r=-1.520e+00; -//--- check - if(w==3) - r=-1.856e+00; -//--- check - if(w==2) - r=-2.367e+00; -//--- check - if(w==1) - r=-2.773e+00; -//--- check - if(w<=0) - r=-3.466e+00; -//--- return result - return(r); - } -//+------------------------------------------------------------------+ -//| Tail(S, 6) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W6(const double s) - { -//--- create variables - int w=0; - double r=0; -//--- check - w=(int)MathRound(-(4.769696e+00*s)+1.050000e+01); - if(w>=10) - r=-6.931e-01; -//--- check - if(w==9) - r=-8.630e-01; -//--- check - if(w==8) - r=-1.068e+00; -//--- check - if(w==7) - r=-1.269e+00; -//--- check - if(w==6) - r=-1.520e+00; -//--- check - if(w==5) - r=-1.856e+00; -//--- check - if(w==4) - r=-2.213e+00; -//--- check - if(w==3) - r=-2.549e+00; -//--- check - if(w==2) - r=-3.060e+00; -//--- check - if(w==1) - r=-3.466e+00; -//--- check - if(w<=0) - r=-4.159e+00; -//--- return result - return(r); - } -//+------------------------------------------------------------------+ -//| Tail(S, 7) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W7(const double s) - { -//--- create variables - int w=0; - double r=0; -//--- check - w=(int)MathRound(-(5.916080e+00*s)+1.400000e+01); - if(w>=14) - r=-6.325e-01; -//--- check - if(w==13) - r=-7.577e-01; -//--- check - if(w==12) - r=-9.008e-01; -//--- check - if(w==11) - r=-1.068e+00; -//--- check - if(w==10) - r=-1.241e+00; -//--- check - if(w==9) - r=-1.451e+00; -//--- check - if(w==8) - r=-1.674e+00; -//--- check - if(w==7) - r=-1.908e+00; -//--- check - if(w==6) - r=-2.213e+00; -//--- check - if(w==5) - r=-2.549e+00; -//--- check - if(w==4) - r=-2.906e+00; -//--- check - if(w==3) - r=-3.243e+00; -//--- check - if(w==2) - r=-3.753e+00; -//--- check - if(w==1) - r=-4.159e+00; -//--- check - if(w<=0) - r=-4.852e+00; -//--- return result - return(r); - } -//+------------------------------------------------------------------+ -//| Tail(S, 8) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W8(const double s) - { -//--- create variables - int w=0; - double r=0; -//--- check - w=(int)MathRound(-(7.141428e+00*s)+1.800000e+01); - if(w>=18) - r=-6.399e-01; -//--- check - if(w==17) - r=-7.494e-01; -//--- check - if(w==16) - r=-8.630e-01; -//--- check - if(w==15) - r=-9.913e-01; -//--- check - if(w==14) - r=-1.138e+00; -//--- check - if(w==13) - r=-1.297e+00; -//--- check - if(w==12) - r=-1.468e+00; -//--- check - if(w==11) - r=-1.653e+00; -//--- check - if(w==10) - r=-1.856e+00; -//--- check - if(w==9) - r=-2.079e+00; -//--- check - if(w==8) - r=-2.326e+00; -//--- check - if(w==7) - r=-2.601e+00; -//--- check - if(w==6) - r=-2.906e+00; -//--- check - if(w==5) - r=-3.243e+00; -//--- check - if(w==4) - r=-3.599e+00; -//--- check - if(w==3) - r=-3.936e+00; -//--- check - if(w==2) - r=-4.447e+00; -//--- check - if(w==1) - r=-4.852e+00; -//--- check - if(w<=0) - r=-5.545e+00; -//--- return result - return(r); - } -//+------------------------------------------------------------------+ -//| Tail(S, 9) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W9(const double s) - { -//--- create variables - int w=0; - double r=0; -//--- check - w=(int)MathRound(-(8.440972e+00*s)+2.250000e+01); - if(w>=22) - r=-6.931e-01; -//--- check - if(w==21) - r=-7.873e-01; -//--- check - if(w==20) - r=-8.912e-01; -//--- check - if(w==19) - r=-1.002e+00; -//--- check - if(w==18) - r=-1.120e+00; -//--- check - if(w==17) - r=-1.255e+00; -//--- check - if(w==16) - r=-1.394e+00; -//--- check - if(w==15) - r=-1.547e+00; -//--- check - if(w==14) - r=-1.717e+00; -//--- check - if(w==13) - r=-1.895e+00; -//--- check - if(w==12) - r=-2.079e+00; -//--- check - if(w==11) - r=-2.287e+00; -//--- check - if(w==10) - r=-2.501e+00; -//--- check - if(w==9) - r=-2.742e+00; -//--- check - if(w==8) - r=-3.019e+00; -//--- check - if(w==7) - r=-3.294e+00; -//--- check - if(w==6) - r=-3.599e+00; -//--- check - if(w==5) - r=-3.936e+00; -//--- check - if(w==4) - r=-4.292e+00; -//--- check - if(w==3) - r=-4.629e+00; -//--- check - if(w==2) - r=-5.140e+00; -//--- check - if(w==1) - r=-5.545e+00; -//--- check - if(w<=0) - r=-6.238e+00; -//--- return result - return(r); - } -//+------------------------------------------------------------------+ -//| Tail(S, 10) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W10(const double s) - { -//--- create variables - int w=0; - double r=0; -//--- check - w=(int)MathRound(-(9.810708e+00*s)+2.750000e+01); - if(w>=27) - r=-6.931e-01; -//--- check - if(w==26) - r=-7.745e-01; -//--- check - if(w==25) - r=-8.607e-01; -//--- check - if(w==24) - r=-9.551e-01; -//--- check - if(w==23) - r=-1.057e+00; -//--- check - if(w==22) - r=-1.163e+00; -//--- check - if(w==21) - r=-1.279e+00; -//--- check - if(w==20) - r=-1.402e+00; -//--- check - if(w==19) - r=-1.533e+00; -//--- check - if(w==18) - r=-1.674e+00; -//--- check - if(w==17) - r=-1.826e+00; -//--- check - if(w==16) - r=-1.983e+00; -//--- check - if(w==15) - r=-2.152e+00; -//--- check - if(w==14) - r=-2.336e+00; -//--- check - if(w==13) - r=-2.525e+00; -//--- check - if(w==12) - r=-2.727e+00; -//--- check - if(w==11) - r=-2.942e+00; -//--- check - if(w==10) - r=-3.170e+00; -//--- check - if(w==9) - r=-3.435e+00; -//--- check - if(w==8) - r=-3.713e+00; -//--- check - if(w==7) - r=-3.987e+00; -//--- check - if(w==6) - r=-4.292e+00; -//--- check - if(w==5) - r=-4.629e+00; -//--- check - if(w==4) - r=-4.986e+00; -//--- check - if(w==3) - r=-5.322e+00; -//--- check - if(w==2) - r=-5.833e+00; -//--- check - if(w==1) - r=-6.238e+00; -//--- check - if(w<=0) - r=-6.931e+00; -//--- return result - return(r); - } -//+------------------------------------------------------------------+ -//| Tail(S, 11) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W11(const double s) - { -//--- create variables - int w=0; - double r=0; -//--- check - w=(int)MathRound(-(1.124722e+01*s)+3.300000e+01); - if(w>=33) - r=-6.595e-01; -//--- check - if(w==32) - r=-7.279e-01; -//--- check - if(w==31) - r=-8.002e-01; -//--- check - if(w==30) - r=-8.782e-01; -//--- check - if(w==29) - r=-9.615e-01; -//--- check - if(w==28) - r=-1.050e+00; -//--- check - if(w==27) - r=-1.143e+00; -//--- check - if(w==26) - r=-1.243e+00; -//--- check - if(w==25) - r=-1.348e+00; -//--- check - if(w==24) - r=-1.459e+00; -//--- check - if(w==23) - r=-1.577e+00; -//--- check - if(w==22) - r=-1.700e+00; -//--- check - if(w==21) - r=-1.832e+00; -//--- check - if(w==20) - r=-1.972e+00; -//--- check - if(w==19) - r=-2.119e+00; -//--- check - if(w==18) - r=-2.273e+00; -//--- check - if(w==17) - r=-2.437e+00; -//--- check - if(w==16) - r=-2.607e+00; -//--- check - if(w==15) - r=-2.788e+00; -//--- check - if(w==14) - r=-2.980e+00; -//--- check - if(w==13) - r=-3.182e+00; -//--- check - if(w==12) - r=-3.391e+00; -//--- check - if(w==11) - r=-3.617e+00; -//--- check - if(w==10) - r=-3.863e+00; -//--- check - if(w==9) - r=-4.128e+00; -//--- check - if(w==8) - r=-4.406e+00; -//--- check - if(w==7) - r=-4.680e+00; -//--- check - if(w==6) - r=-4.986e+00; -//--- check - if(w==5) - r=-5.322e+00; -//--- check - if(w==4) - r=-5.679e+00; -//--- check - if(w==3) - r=-6.015e+00; -//--- check - if(w==2) - r=-6.526e+00; -//--- check - if(w==1) - r=-6.931e+00; -//--- check - if(w<=0) - r=-7.625e+00; -//--- return result - return(r); - } -//+------------------------------------------------------------------+ -//| Tail(S, 12) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W12(const double s) - { -//--- create variables - int w=0; - double r=0; -//--- check - w=(int)MathRound(-(1.274755e+01*s)+3.900000e+01); - if(w>=39) - r=-6.633e-01; -//--- check - if(w==38) - r=-7.239e-01; -//--- check - if(w==37) - r=-7.878e-01; -//--- check - if(w==36) - r=-8.556e-01; -//--- check - if(w==35) - r=-9.276e-01; -//--- check - if(w==34) - r=-1.003e+00; -//--- check - if(w==33) - r=-1.083e+00; -//--- check - if(w==32) - r=-1.168e+00; -//--- check - if(w==31) - r=-1.256e+00; -//--- check - if(w==30) - r=-1.350e+00; -//--- check - if(w==29) - r=-1.449e+00; -//--- check - if(w==28) - r=-1.552e+00; -//--- check - if(w==27) - r=-1.660e+00; -//--- check - if(w==26) - r=-1.774e+00; -//--- check - if(w==25) - r=-1.893e+00; -//--- check - if(w==24) - r=-2.017e+00; -//--- check - if(w==23) - r=-2.148e+00; -//--- check - if(w==22) - r=-2.285e+00; -//--- check - if(w==21) - r=-2.429e+00; -//--- check - if(w==20) - r=-2.581e+00; -//--- check - if(w==19) - r=-2.738e+00; -//--- check - if(w==18) - r=-2.902e+00; -//--- check - if(w==17) - r=-3.076e+00; -//--- check - if(w==16) - r=-3.255e+00; -//--- check - if(w==15) - r=-3.443e+00; -//--- check - if(w==14) - r=-3.645e+00; -//--- check - if(w==13) - r=-3.852e+00; -//--- check - if(w==12) - r=-4.069e+00; -//--- check - if(w==11) - r=-4.310e+00; -//--- check - if(w==10) - r=-4.557e+00; -//--- check - if(w==9) - r=-4.821e+00; -//--- check - if(w==8) - r=-5.099e+00; -//--- check - if(w==7) - r=-5.373e+00; -//--- check - if(w==6) - r=-5.679e+00; -//--- check - if(w==5) - r=-6.015e+00; -//--- check - if(w==4) - r=-6.372e+00; -//--- check - if(w==3) - r=-6.708e+00; -//--- check - if(w==2) - r=-7.219e+00; -//--- check - if(w==1) - r=-7.625e+00; -//--- check - if(w<=0) - r=-8.318e+00; -//--- return result - return(r); - } -//+------------------------------------------------------------------+ -//| Tail(S, 13) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W13(const double s) - { -//--- create variables - int w=0; - double r=0; -//--- check - w=(int)MathRound(-(1.430909e+01*s)+4.550000e+01); - if(w>=45) - r=-6.931e-01; -//--- check - if(w==44) - r=-7.486e-01; -//--- check - if(w==43) - r=-8.068e-01; -//--- check - if(w==42) - r=-8.683e-01; -//--- check - if(w==41) - r=-9.328e-01; -//--- check - if(w==40) - r=-1.001e+00; -//--- check - if(w==39) - r=-1.072e+00; -//--- check - if(w==38) - r=-1.146e+00; -//--- check - if(w==37) - r=-1.224e+00; -//--- check - if(w==36) - r=-1.306e+00; -//--- check - if(w==35) - r=-1.392e+00; -//--- check - if(w==34) - r=-1.481e+00; -//--- check - if(w==33) - r=-1.574e+00; -//--- check - if(w==32) - r=-1.672e+00; -//--- check - if(w==31) - r=-1.773e+00; -//--- check - if(w==30) - r=-1.879e+00; -//--- check - if(w==29) - r=-1.990e+00; -//--- check - if(w==28) - r=-2.104e+00; -//--- check - if(w==27) - r=-2.224e+00; -//--- check - if(w==26) - r=-2.349e+00; -//--- check - if(w==25) - r=-2.479e+00; -//--- check - if(w==24) - r=-2.614e+00; -//--- check - if(w==23) - r=-2.755e+00; -//--- check - if(w==22) - r=-2.902e+00; -//--- check - if(w==21) - r=-3.055e+00; -//--- check - if(w==20) - r=-3.215e+00; -//--- check - if(w==19) - r=-3.380e+00; -//--- check - if(w==18) - r=-3.551e+00; -//--- check - if(w==17) - r=-3.733e+00; -//--- check - if(w==16) - r=-3.917e+00; -//--- check - if(w==15) - r=-4.113e+00; -//--- check - if(w==14) - r=-4.320e+00; -//--- check - if(w==13) - r=-4.534e+00; -//--- check - if(w==12) - r=-4.762e+00; -//--- check - if(w==11) - r=-5.004e+00; -//--- check - if(w==10) - r=-5.250e+00; -//--- check - if(w==9) - r=-5.514e+00; -//--- check - if(w==8) - r=-5.792e+00; -//--- check - if(w==7) - r=-6.066e+00; -//--- check - if(w==6) - r=-6.372e+00; -//--- check - if(w==5) - r=-6.708e+00; -//--- check - if(w==4) - r=-7.065e+00; -//--- check - if(w==3) - r=-7.401e+00; -//--- check - if(w==2) - r=-7.912e+00; -//--- check - if(w==1) - r=-8.318e+00; -//--- check - if(w<=0) - r=-9.011e+00; -//--- return result - return(r); - } -//+------------------------------------------------------------------+ -//| Tail(S, 14) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W14(const double s) - { -//--- create variables - int w=0; - double r=0; -//--- check - w=(int)MathRound(-(1.592953e+01*s)+5.250000e+01); - if(w>=52) - r=-6.931e-01; -//--- check - if(w==51) - r=-7.428e-01; -//--- check - if(w==50) - r=-7.950e-01; -//--- check - if(w==49) - r=-8.495e-01; -//--- check - if(w==48) - r=-9.067e-01; -//--- check - if(w==47) - r=-9.664e-01; -//--- check - if(w==46) - r=-1.029e+00; -//--- check - if(w==45) - r=-1.094e+00; -//--- check - if(w==44) - r=-1.162e+00; -//--- check - if(w==43) - r=-1.233e+00; -//--- check - if(w==42) - r=-1.306e+00; -//--- check - if(w==41) - r=-1.383e+00; -//--- check - if(w==40) - r=-1.463e+00; -//--- check - if(w==39) - r=-1.546e+00; -//--- check - if(w==38) - r=-1.632e+00; -//--- check - if(w==37) - r=-1.722e+00; -//--- check - if(w==36) - r=-1.815e+00; -//--- check - if(w==35) - r=-1.911e+00; -//--- check - if(w==34) - r=-2.011e+00; -//--- check - if(w==33) - r=-2.115e+00; -//--- check - if(w==32) - r=-2.223e+00; -//--- check - if(w==31) - r=-2.334e+00; -//--- check - if(w==30) - r=-2.450e+00; -//--- check - if(w==29) - r=-2.570e+00; -//--- check - if(w==28) - r=-2.694e+00; -//--- check - if(w==27) - r=-2.823e+00; -//--- check - if(w==26) - r=-2.956e+00; -//--- check - if(w==25) - r=-3.095e+00; -//--- check - if(w==24) - r=-3.238e+00; -//--- check - if(w==23) - r=-3.387e+00; -//--- check - if(w==22) - r=-3.541e+00; -//--- check - if(w==21) - r=-3.700e+00; -//--- check - if(w==20) - r=-3.866e+00; -//--- check - if(w==19) - r=-4.038e+00; -//--- check - if(w==18) - r=-4.215e+00; -//--- check - if(w==17) - r=-4.401e+00; -//--- check - if(w==16) - r=-4.592e+00; -//--- check - if(w==15) - r=-4.791e+00; -//--- check - if(w==14) - r=-5.004e+00; -//--- check - if(w==13) - r=-5.227e+00; -//--- check - if(w==12) - r=-5.456e+00; -//--- check - if(w==11) - r=-5.697e+00; -//--- check - if(w==10) - r=-5.943e+00; -//--- check - if(w==9) - r=-6.208e+00; -//--- check - if(w==8) - r=-6.485e+00; -//--- check - if(w==7) - r=-6.760e+00; -//--- check - if(w==6) - r=-7.065e+00; -//--- check - if(w==5) - r=-7.401e+00; -//--- check - if(w==4) - r=-7.758e+00; -//--- check - if(w==3) - r=-8.095e+00; -//--- check - if(w==2) - r=-8.605e+00; -//--- check - if(w==1) - r=-9.011e+00; -//--- check - if(w<=0) - r=-9.704e+00; -//--- return result - return(r); - } -//+------------------------------------------------------------------+ -//| Tail(S, 15) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W15(const double s) - { -//--- create variables - int w=0; - double r=0; -//--- check - w=(int)MathRound(-(1.760682e+01*s)+6.000000e+01); - if(w>=60) - r=-6.714e-01; -//--- check - if(w==59) - r=-7.154e-01; -//--- check - if(w==58) - r=-7.613e-01; -//--- check - if(w==57) - r=-8.093e-01; -//--- check - if(w==56) - r=-8.593e-01; -//--- check - if(w==55) - r=-9.114e-01; -//--- check - if(w==54) - r=-9.656e-01; -//--- check - if(w==53) - r=-1.022e+00; -//--- check - if(w==52) - r=-1.081e+00; -//--- check - if(w==51) - r=-1.142e+00; -//--- check - if(w==50) - r=-1.205e+00; -//--- check - if(w==49) - r=-1.270e+00; -//--- check - if(w==48) - r=-1.339e+00; -//--- check - if(w==47) - r=-1.409e+00; -//--- check - if(w==46) - r=-1.482e+00; -//--- check - if(w==45) - r=-1.558e+00; -//--- check - if(w==44) - r=-1.636e+00; -//--- check - if(w==43) - r=-1.717e+00; -//--- check - if(w==42) - r=-1.801e+00; -//--- check - if(w==41) - r=-1.888e+00; -//--- check - if(w==40) - r=-1.977e+00; -//--- check - if(w==39) - r=-2.070e+00; -//--- check - if(w==38) - r=-2.166e+00; -//--- check - if(w==37) - r=-2.265e+00; -//--- check - if(w==36) - r=-2.366e+00; -//--- check - if(w==35) - r=-2.472e+00; -//--- check - if(w==34) - r=-2.581e+00; -//--- check - if(w==33) - r=-2.693e+00; -//--- check - if(w==32) - r=-2.809e+00; -//--- check - if(w==31) - r=-2.928e+00; -//--- check - if(w==30) - r=-3.051e+00; -//--- check - if(w==29) - r=-3.179e+00; -//--- check - if(w==28) - r=-3.310e+00; -//--- check - if(w==27) - r=-3.446e+00; -//--- check - if(w==26) - r=-3.587e+00; -//--- check - if(w==25) - r=-3.732e+00; -//--- check - if(w==24) - r=-3.881e+00; -//--- check - if(w==23) - r=-4.036e+00; -//--- check - if(w==22) - r=-4.195e+00; -//--- check - if(w==21) - r=-4.359e+00; -//--- check - if(w==20) - r=-4.531e+00; -//--- check - if(w==19) - r=-4.707e+00; -//--- check - if(w==18) - r=-4.888e+00; -//--- check - if(w==17) - r=-5.079e+00; -//--- check - if(w==16) - r=-5.273e+00; -//--- check - if(w==15) - r=-5.477e+00; -//--- check - if(w==14) - r=-5.697e+00; -//--- check - if(w==13) - r=-5.920e+00; -//--- check - if(w==12) - r=-6.149e+00; -//--- check - if(w==11) - r=-6.390e+00; -//--- check - if(w==10) - r=-6.636e+00; -//--- check - if(w==9) - r=-6.901e+00; -//--- check - if(w==8) - r=-7.178e+00; -//--- check - if(w==7) - r=-7.453e+00; -//--- check - if(w==6) - r=-7.758e+00; -//--- check - if(w==5) - r=-8.095e+00; -//--- check - if(w==4) - r=-8.451e+00; -//--- check - if(w==3) - r=-8.788e+00; -//--- check - if(w==2) - r=-9.299e+00; -//--- check - if(w==1) - r=-9.704e+00; -//--- check - if(w<=0) - r=-1.040e+01; -//--- return result - return(r); - } -//+------------------------------------------------------------------+ -//| Tail(S, 16) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W16(const double s) - { -//--- create variables - int w=0; - double r=0; -//--- check - w=(int)MathRound(-(1.933908e+01*s)+6.800000e+01); - if(w>=68) - r=-6.733e-01; -//--- check - if(w==67) - r=-7.134e-01; -//--- check - if(w==66) - r=-7.551e-01; -//--- check - if(w==65) - r=-7.986e-01; -//--- check - if(w==64) - r=-8.437e-01; -//--- check - if(w==63) - r=-8.905e-01; -//--- check - if(w==62) - r=-9.391e-01; -//--- check - if(w==61) - r=-9.895e-01; -//--- check - if(w==60) - r=-1.042e+00; -//--- check - if(w==59) - r=-1.096e+00; -//--- check - if(w==58) - r=-1.152e+00; -//--- check - if(w==57) - r=-1.210e+00; -//--- check - if(w==56) - r=-1.270e+00; -//--- check - if(w==55) - r=-1.331e+00; -//--- check - if(w==54) - r=-1.395e+00; -//--- check - if(w==53) - r=-1.462e+00; -//--- check - if(w==52) - r=-1.530e+00; -//--- check - if(w==51) - r=-1.600e+00; -//--- check - if(w==50) - r=-1.673e+00; -//--- check - if(w==49) - r=-1.748e+00; -//--- check - if(w==48) - r=-1.825e+00; -//--- check - if(w==47) - r=-1.904e+00; -//--- check - if(w==46) - r=-1.986e+00; -//--- check - if(w==45) - r=-2.071e+00; -//--- check - if(w==44) - r=-2.158e+00; -//--- check - if(w==43) - r=-2.247e+00; -//--- check - if(w==42) - r=-2.339e+00; -//--- check - if(w==41) - r=-2.434e+00; -//--- check - if(w==40) - r=-2.532e+00; -//--- check - if(w==39) - r=-2.632e+00; -//--- check - if(w==38) - r=-2.735e+00; -//--- check - if(w==37) - r=-2.842e+00; -//--- check - if(w==36) - r=-2.951e+00; -//--- check - if(w==35) - r=-3.064e+00; -//--- check - if(w==34) - r=-3.179e+00; -//--- check - if(w==33) - r=-3.298e+00; -//--- check - if(w==32) - r=-3.420e+00; -//--- check - if(w==31) - r=-3.546e+00; -//--- check - if(w==30) - r=-3.676e+00; -//--- check - if(w==29) - r=-3.810e+00; -//--- check - if(w==28) - r=-3.947e+00; -//--- check - if(w==27) - r=-4.088e+00; -//--- check - if(w==26) - r=-4.234e+00; -//--- check - if(w==25) - r=-4.383e+00; -//--- check - if(w==24) - r=-4.538e+00; -//--- check - if(w==23) - r=-4.697e+00; -//--- check - if(w==22) - r=-4.860e+00; -//--- check - if(w==21) - r=-5.029e+00; -//--- check - if(w==20) - r=-5.204e+00; -//--- check - if(w==19) - r=-5.383e+00; -//--- check - if(w==18) - r=-5.569e+00; -//--- check - if(w==17) - r=-5.762e+00; -//--- check - if(w==16) - r=-5.960e+00; -//--- check - if(w==15) - r=-6.170e+00; -//--- check - if(w==14) - r=-6.390e+00; -//--- check - if(w==13) - r=-6.613e+00; -//--- check - if(w==12) - r=-6.842e+00; -//--- check - if(w==11) - r=-7.083e+00; -//--- check - if(w==10) - r=-7.329e+00; -//--- check - if(w==9) - r=-7.594e+00; -//--- check - if(w==8) - r=-7.871e+00; -//--- check - if(w==7) - r=-8.146e+00; -//--- check - if(w==6) - r=-8.451e+00; -//--- check - if(w==5) - r=-8.788e+00; -//--- check - if(w==4) - r=-9.144e+00; -//--- check - if(w==3) - r=-9.481e+00; -//--- check - if(w==2) - r=-9.992e+00; -//--- check - if(w==1) - r=-1.040e+01; -//--- check - if(w<=0) - r=-1.109e+01; -//--- return result - return(r); - } -//+------------------------------------------------------------------+ -//| Tail(S, 17) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W17(const double s) - { -//--- create variables - int w=0; - double r=0; -//--- check - w=(int)MathRound(-(2.112463e+01*s)+7.650000e+01); - if(w>=76) - r=-6.931e-01; -//--- check - if(w==75) - r=-7.306e-01; -//--- check - if(w==74) - r=-7.695e-01; -//--- check - if(w==73) - r=-8.097e-01; -//--- check - if(w==72) - r=-8.514e-01; -//--- check - if(w==71) - r=-8.946e-01; -//--- check - if(w==70) - r=-9.392e-01; -//--- check - if(w==69) - r=-9.853e-01; -//--- check - if(w==68) - r=-1.033e+00; -//--- check - if(w==67) - r=-1.082e+00; -//--- check - if(w==66) - r=-1.133e+00; -//--- check - if(w==65) - r=-1.185e+00; -//--- check - if(w==64) - r=-1.240e+00; -//--- check - if(w==63) - r=-1.295e+00; -//--- check - if(w==62) - r=-1.353e+00; -//--- check - if(w==61) - r=-1.412e+00; -//--- check - if(w==60) - r=-1.473e+00; -//--- check - if(w==59) - r=-1.536e+00; -//--- check - if(w==58) - r=-1.600e+00; -//--- check - if(w==57) - r=-1.666e+00; -//--- check - if(w==56) - r=-1.735e+00; -//--- check - if(w==55) - r=-1.805e+00; -//--- check - if(w==54) - r=-1.877e+00; -//--- check - if(w==53) - r=-1.951e+00; -//--- check - if(w==52) - r=-2.028e+00; -//--- check - if(w==51) - r=-2.106e+00; -//--- check - if(w==50) - r=-2.186e+00; -//--- check - if(w==49) - r=-2.269e+00; -//--- check - if(w==48) - r=-2.353e+00; -//--- check - if(w==47) - r=-2.440e+00; -//--- check - if(w==46) - r=-2.530e+00; -//--- check - if(w==45) - r=-2.621e+00; -//--- check - if(w==44) - r=-2.715e+00; -//--- check - if(w==43) - r=-2.812e+00; -//--- check - if(w==42) - r=-2.911e+00; -//--- check - if(w==41) - r=-3.012e+00; -//--- check - if(w==40) - r=-3.116e+00; -//--- check - if(w==39) - r=-3.223e+00; -//--- check - if(w==38) - r=-3.332e+00; -//--- check - if(w==37) - r=-3.445e+00; -//--- check - if(w==36) - r=-3.560e+00; -//--- check - if(w==35) - r=-3.678e+00; -//--- check - if(w==34) - r=-3.799e+00; -//--- check - if(w==33) - r=-3.924e+00; -//--- check - if(w==32) - r=-4.052e+00; -//--- check - if(w==31) - r=-4.183e+00; -//--- check - if(w==30) - r=-4.317e+00; -//--- check - if(w==29) - r=-4.456e+00; -//--- check - if(w==28) - r=-4.597e+00; -//--- check - if(w==27) - r=-4.743e+00; -//--- check - if(w==26) - r=-4.893e+00; -//--- check - if(w==25) - r=-5.047e+00; -//--- check - if(w==24) - r=-5.204e+00; -//--- check - if(w==23) - r=-5.367e+00; -//--- check - if(w==22) - r=-5.534e+00; -//--- check - if(w==21) - r=-5.706e+00; -//--- check - if(w==20) - r=-5.884e+00; -//--- check - if(w==19) - r=-6.066e+00; -//--- check - if(w==18) - r=-6.254e+00; -//--- check - if(w==17) - r=-6.451e+00; -//--- check - if(w==16) - r=-6.654e+00; -//--- check - if(w==15) - r=-6.864e+00; -//--- check - if(w==14) - r=-7.083e+00; -//--- check - if(w==13) - r=-7.306e+00; -//--- check - if(w==12) - r=-7.535e+00; -//--- check - if(w==11) - r=-7.776e+00; -//--- check - if(w==10) - r=-8.022e+00; -//--- check - if(w==9) - r=-8.287e+00; -//--- check - if(w==8) - r=-8.565e+00; -//--- check - if(w==7) - r=-8.839e+00; -//--- check - if(w==6) - r=-9.144e+00; -//--- check - if(w==5) - r=-9.481e+00; -//--- check - if(w==4) - r=-9.838e+00; -//--- check - if(w==3) - r=-1.017e+01; -//--- check - if(w==2) - r=-1.068e+01; -//--- check - if(w==1) - r=-1.109e+01; -//--- check - if(w<=0) - r=-1.178e+01; -//--- return result - return(r); - } -//+------------------------------------------------------------------+ -//| Tail(S, 18) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W18(const double s) - { -//--- create variables - int w=0; - double r=0; -//--- check - w=(int)MathRound(-(2.296193e+01*s)+8.550000e+01); - if(w>=85) - r=-6.931e-01; -//--- check - if(w==84) - r=-7.276e-01; -//--- check - if(w==83) - r=-7.633e-01; -//--- check - if(w==82) - r=-8.001e-01; -//--- check - if(w==81) - r=-8.381e-01; -//--- check - if(w==80) - r=-8.774e-01; -//--- check - if(w==79) - r=-9.179e-01; -//--- check - if(w==78) - r=-9.597e-01; -//--- check - if(w==77) - r=-1.003e+00; -//--- check - if(w==76) - r=-1.047e+00; -//--- check - if(w==75) - r=-1.093e+00; -//--- check - if(w==74) - r=-1.140e+00; -//--- check - if(w==73) - r=-1.188e+00; -//--- check - if(w==72) - r=-1.238e+00; -//--- check - if(w==71) - r=-1.289e+00; -//--- check - if(w==70) - r=-1.342e+00; -//--- check - if(w==69) - r=-1.396e+00; -//--- check - if(w==68) - r=-1.452e+00; -//--- check - if(w==67) - r=-1.509e+00; -//--- check - if(w==66) - r=-1.568e+00; -//--- check - if(w==65) - r=-1.628e+00; -//--- check - if(w==64) - r=-1.690e+00; -//--- check - if(w==63) - r=-1.753e+00; -//--- check - if(w==62) - r=-1.818e+00; -//--- check - if(w==61) - r=-1.885e+00; -//--- check - if(w==60) - r=-1.953e+00; -//--- check - if(w==59) - r=-2.023e+00; -//--- check - if(w==58) - r=-2.095e+00; -//--- check - if(w==57) - r=-2.168e+00; -//--- check - if(w==56) - r=-2.244e+00; -//--- check - if(w==55) - r=-2.321e+00; -//--- check - if(w==54) - r=-2.400e+00; -//--- check - if(w==53) - r=-2.481e+00; -//--- check - if(w==52) - r=-2.564e+00; -//--- check - if(w==51) - r=-2.648e+00; -//--- check - if(w==50) - r=-2.735e+00; -//--- check - if(w==49) - r=-2.824e+00; -//--- check - if(w==48) - r=-2.915e+00; -//--- check - if(w==47) - r=-3.008e+00; -//--- check - if(w==46) - r=-3.104e+00; -//--- check - if(w==45) - r=-3.201e+00; -//--- check - if(w==44) - r=-3.301e+00; -//--- check - if(w==43) - r=-3.403e+00; -//--- check - if(w==42) - r=-3.508e+00; -//--- check - if(w==41) - r=-3.615e+00; -//--- check - if(w==40) - r=-3.724e+00; -//--- check - if(w==39) - r=-3.836e+00; -//--- check - if(w==38) - r=-3.950e+00; -//--- check - if(w==37) - r=-4.068e+00; -//--- check - if(w==36) - r=-4.188e+00; -//--- check - if(w==35) - r=-4.311e+00; -//--- check - if(w==34) - r=-4.437e+00; -//--- check - if(w==33) - r=-4.565e+00; -//--- check - if(w==32) - r=-4.698e+00; -//--- check - if(w==31) - r=-4.833e+00; -//--- check - if(w==30) - r=-4.971e+00; -//--- check - if(w==29) - r=-5.113e+00; -//--- check - if(w==28) - r=-5.258e+00; -//--- check - if(w==27) - r=-5.408e+00; -//--- check - if(w==26) - r=-5.561e+00; -//--- check - if(w==25) - r=-5.717e+00; -//--- check - if(w==24) - r=-5.878e+00; -//--- check - if(w==23) - r=-6.044e+00; -//--- check - if(w==22) - r=-6.213e+00; -//--- check - if(w==21) - r=-6.388e+00; -//--- check - if(w==20) - r=-6.569e+00; -//--- check - if(w==19) - r=-6.753e+00; -//--- check - if(w==18) - r=-6.943e+00; -//--- check - if(w==17) - r=-7.144e+00; -//--- check - if(w==16) - r=-7.347e+00; -//--- check - if(w==15) - r=-7.557e+00; -//--- check - if(w==14) - r=-7.776e+00; -//--- check - if(w==13) - r=-7.999e+00; -//--- check - if(w==12) - r=-8.228e+00; -//--- check - if(w==11) - r=-8.469e+00; -//--- check - if(w==10) - r=-8.715e+00; -//--- check - if(w==9) - r=-8.980e+00; -//--- check - if(w==8) - r=-9.258e+00; -//--- check - if(w==7) - r=-9.532e+00; -//--- check - if(w==6) - r=-9.838e+00; -//--- check - if(w==5) - r=-1.017e+01; -//--- check - if(w==4) - r=-1.053e+01; -//--- check - if(w==3) - r=-1.087e+01; -//--- check - if(w==2) - r=-1.138e+01; -//--- check - if(w==1) - r=-1.178e+01; -//--- check - if(w<=0) - r=-1.248e+01; -//--- return result - return(r); - } -//+------------------------------------------------------------------+ -//| Tail(S, 19) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W19(const double s) - { -//--- create variables - int w=0; - double r=0; -//--- check - w=(int)MathRound(-(2.484955e+01*s)+9.500000e+01); - if(w>=95) - r=-6.776e-01; -//--- check - if(w==94) - r=-7.089e-01; -//--- check - if(w==93) - r=-7.413e-01; -//--- check - if(w==92) - r=-7.747e-01; -//--- check - if(w==91) - r=-8.090e-01; -//--- check - if(w==90) - r=-8.445e-01; -//--- check - if(w==89) - r=-8.809e-01; -//--- check - if(w==88) - r=-9.185e-01; -//--- check - if(w==87) - r=-9.571e-01; -//--- check - if(w==86) - r=-9.968e-01; -//--- check - if(w==85) - r=-1.038e+00; -//--- check - if(w==84) - r=-1.080e+00; -//--- check - if(w==83) - r=-1.123e+00; -//--- check - if(w==82) - r=-1.167e+00; -//--- check - if(w==81) - r=-1.213e+00; -//--- check - if(w==80) - r=-1.259e+00; -//--- check - if(w==79) - r=-1.307e+00; -//--- check - if(w==78) - r=-1.356e+00; -//--- check - if(w==77) - r=-1.407e+00; -//--- check - if(w==76) - r=-1.458e+00; -//--- check - if(w==75) - r=-1.511e+00; -//--- check - if(w==74) - r=-1.565e+00; -//--- check - if(w==73) - r=-1.621e+00; -//--- check - if(w==72) - r=-1.678e+00; -//--- check - if(w==71) - r=-1.736e+00; -//--- check - if(w==70) - r=-1.796e+00; -//--- check - if(w==69) - r=-1.857e+00; -//--- check - if(w==68) - r=-1.919e+00; -//--- check - if(w==67) - r=-1.983e+00; -//--- check - if(w==66) - r=-2.048e+00; -//--- check - if(w==65) - r=-2.115e+00; -//--- check - if(w==64) - r=-2.183e+00; -//--- check - if(w==63) - r=-2.253e+00; -//--- check - if(w==62) - r=-2.325e+00; -//--- check - if(w==61) - r=-2.398e+00; -//--- check - if(w==60) - r=-2.472e+00; -//--- check - if(w==59) - r=-2.548e+00; -//--- check - if(w==58) - r=-2.626e+00; -//--- check - if(w==57) - r=-2.706e+00; -//--- check - if(w==56) - r=-2.787e+00; -//--- check - if(w==55) - r=-2.870e+00; -//--- check - if(w==54) - r=-2.955e+00; -//--- check - if(w==53) - r=-3.042e+00; -//--- check - if(w==52) - r=-3.130e+00; -//--- check - if(w==51) - r=-3.220e+00; -//--- check - if(w==50) - r=-3.313e+00; -//--- check - if(w==49) - r=-3.407e+00; -//--- check - if(w==48) - r=-3.503e+00; -//--- check - if(w==47) - r=-3.601e+00; -//--- check - if(w==46) - r=-3.702e+00; -//--- check - if(w==45) - r=-3.804e+00; -//--- check - if(w==44) - r=-3.909e+00; -//--- check - if(w==43) - r=-4.015e+00; -//--- check - if(w==42) - r=-4.125e+00; -//--- check - if(w==41) - r=-4.236e+00; -//--- check - if(w==40) - r=-4.350e+00; -//--- check - if(w==39) - r=-4.466e+00; -//--- check - if(w==38) - r=-4.585e+00; -//--- check - if(w==37) - r=-4.706e+00; -//--- check - if(w==36) - r=-4.830e+00; -//--- check - if(w==35) - r=-4.957e+00; -//--- check - if(w==34) - r=-5.086e+00; -//--- check - if(w==33) - r=-5.219e+00; -//--- check - if(w==32) - r=-5.355e+00; -//--- check - if(w==31) - r=-5.493e+00; -//--- check - if(w==30) - r=-5.634e+00; -//--- check - if(w==29) - r=-5.780e+00; -//--- check - if(w==28) - r=-5.928e+00; -//--- check - if(w==27) - r=-6.080e+00; -//--- check - if(w==26) - r=-6.235e+00; -//--- check - if(w==25) - r=-6.394e+00; -//--- check - if(w==24) - r=-6.558e+00; -//--- check - if(w==23) - r=-6.726e+00; -//--- check - if(w==22) - r=-6.897e+00; -//--- check - if(w==21) - r=-7.074e+00; -//--- check - if(w==20) - r=-7.256e+00; -//--- check - if(w==19) - r=-7.443e+00; -//--- check - if(w==18) - r=-7.636e+00; -//--- check - if(w==17) - r=-7.837e+00; -//--- check - if(w==16) - r=-8.040e+00; -//--- check - if(w==15) - r=-8.250e+00; -//--- check - if(w==14) - r=-8.469e+00; -//--- check - if(w==13) - r=-8.692e+00; -//--- check - if(w==12) - r=-8.921e+00; -//--- check - if(w==11) - r=-9.162e+00; -//--- check - if(w==10) - r=-9.409e+00; -//--- check - if(w==9) - r=-9.673e+00; -//--- check - if(w==8) - r=-9.951e+00; -//--- check - if(w==7) - r=-1.023e+01; -//--- check - if(w==6) - r=-1.053e+01; -//--- check - if(w==5) - r=-1.087e+01; -//--- check - if(w==4) - r=-1.122e+01; -//--- check - if(w==3) - r=-1.156e+01; -//--- check - if(w==2) - r=-1.207e+01; -//--- check - if(w==1) - r=-1.248e+01; -//--- check - if(w<=0) - r=-1.317e+01; -//--- return result - return(r); - } -//+------------------------------------------------------------------+ -//| Tail(S, 20) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W20(const double s) - { -//--- create variables - int w=0; - double r=0; -//--- check - w=(int)MathRound(-(2.678619e+01*s)+1.050000e+02); - if(w>=105) - r=-6.787e-01; -//--- check - if(w==104) - r=-7.078e-01; -//--- check - if(w==103) - r=-7.378e-01; -//--- check - if(w==102) - r=-7.686e-01; -//--- check - if(w==101) - r=-8.004e-01; -//--- check - if(w==100) - r=-8.330e-01; -//--- check - if(w==99) - r=-8.665e-01; -//--- check - if(w==98) - r=-9.010e-01; -//--- check - if(w==97) - r=-9.363e-01; -//--- check - if(w==96) - r=-9.726e-01; -//--- check - if(w==95) - r=-1.010e+00; -//--- check - if(w==94) - r=-1.048e+00; -//--- check - if(w==93) - r=-1.087e+00; -//--- check - if(w==92) - r=-1.128e+00; -//--- check - if(w==91) - r=-1.169e+00; -//--- check - if(w==90) - r=-1.211e+00; -//--- check - if(w==89) - r=-1.254e+00; -//--- check - if(w==88) - r=-1.299e+00; -//--- check - if(w==87) - r=-1.344e+00; -//--- check - if(w==86) - r=-1.390e+00; -//--- check - if(w==85) - r=-1.438e+00; -//--- check - if(w==84) - r=-1.486e+00; -//--- check - if(w==83) - r=-1.536e+00; -//--- check - if(w==82) - r=-1.587e+00; -//--- check - if(w==81) - r=-1.639e+00; -//--- check - if(w==80) - r=-1.692e+00; -//--- check - if(w==79) - r=-1.746e+00; -//--- check - if(w==78) - r=-1.802e+00; -//--- check - if(w==77) - r=-1.859e+00; -//--- check - if(w==76) - r=-1.916e+00; -//--- check - if(w==75) - r=-1.976e+00; -//--- check - if(w==74) - r=-2.036e+00; -//--- check - if(w==73) - r=-2.098e+00; -//--- check - if(w==72) - r=-2.161e+00; -//--- check - if(w==71) - r=-2.225e+00; -//--- check - if(w==70) - r=-2.290e+00; -//--- check - if(w==69) - r=-2.357e+00; -//--- check - if(w==68) - r=-2.426e+00; -//--- check - if(w==67) - r=-2.495e+00; -//--- check - if(w==66) - r=-2.566e+00; -//--- check - if(w==65) - r=-2.639e+00; -//--- check - if(w==64) - r=-2.713e+00; -//--- check - if(w==63) - r=-2.788e+00; -//--- check - if(w==62) - r=-2.865e+00; -//--- check - if(w==61) - r=-2.943e+00; -//--- check - if(w==60) - r=-3.023e+00; -//--- check - if(w==59) - r=-3.104e+00; -//--- check - if(w==58) - r=-3.187e+00; -//--- check - if(w==57) - r=-3.272e+00; -//--- check - if(w==56) - r=-3.358e+00; -//--- check - if(w==55) - r=-3.446e+00; -//--- check - if(w==54) - r=-3.536e+00; -//--- check - if(w==53) - r=-3.627e+00; -//--- check - if(w==52) - r=-3.721e+00; -//--- check - if(w==51) - r=-3.815e+00; -//--- check - if(w==50) - r=-3.912e+00; -//--- check - if(w==49) - r=-4.011e+00; -//--- check - if(w==48) - r=-4.111e+00; -//--- check - if(w==47) - r=-4.214e+00; -//--- check - if(w==46) - r=-4.318e+00; -//--- check - if(w==45) - r=-4.425e+00; -//--- check - if(w==44) - r=-4.534e+00; -//--- check - if(w==43) - r=-4.644e+00; -//--- check - if(w==42) - r=-4.757e+00; -//--- check - if(w==41) - r=-4.872e+00; -//--- check - if(w==40) - r=-4.990e+00; -//--- check - if(w==39) - r=-5.109e+00; -//--- check - if(w==38) - r=-5.232e+00; -//--- check - if(w==37) - r=-5.356e+00; -//--- check - if(w==36) - r=-5.484e+00; -//--- check - if(w==35) - r=-5.614e+00; -//--- check - if(w==34) - r=-5.746e+00; -//--- check - if(w==33) - r=-5.882e+00; -//--- check - if(w==32) - r=-6.020e+00; -//--- check - if(w==31) - r=-6.161e+00; -//--- check - if(w==30) - r=-6.305e+00; -//--- check - if(w==29) - r=-6.453e+00; -//--- check - if(w==28) - r=-6.603e+00; -//--- check - if(w==27) - r=-6.757e+00; -//--- check - if(w==26) - r=-6.915e+00; -//--- check - if(w==25) - r=-7.076e+00; -//--- check - if(w==24) - r=-7.242e+00; -//--- check - if(w==23) - r=-7.411e+00; -//--- check - if(w==22) - r=-7.584e+00; -//--- check - if(w==21) - r=-7.763e+00; -//--- check - if(w==20) - r=-7.947e+00; -//--- check - if(w==19) - r=-8.136e+00; -//--- check - if(w==18) - r=-8.330e+00; -//--- check - if(w==17) - r=-8.530e+00; -//--- check - if(w==16) - r=-8.733e+00; -//--- check - if(w==15) - r=-8.943e+00; -//--- check - if(w==14) - r=-9.162e+00; -//--- check - if(w==13) - r=-9.386e+00; -//--- check - if(w==12) - r=-9.614e+00; -//--- check - if(w==11) - r=-9.856e+00; -//--- check - if(w==10) - r=-1.010e+01; -//--- check - if(w==9) - r=-1.037e+01; -//--- check - if(w==8) - r=-1.064e+01; -//--- check - if(w==7) - r=-1.092e+01; -//--- check - if(w==6) - r=-1.122e+01; -//--- check - if(w==5) - r=-1.156e+01; -//--- check - if(w==4) - r=-1.192e+01; -//--- check - if(w==3) - r=-1.225e+01; -//--- check - if(w==2) - r=-1.276e+01; -//--- check - if(w==1) - r=-1.317e+01; -//--- check - if(w<=0) - r=-1.386e+01; -//--- - return(r); - } -//+------------------------------------------------------------------+ -//| Tail(S, 21) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W21(const double s) - { -//--- create variables - int w=0; - double r=0; -//--- check - w=(int)MathRound(-(2.877064e+01*s)+1.155000e+02); - if(w>=115) - r=-6.931e-01; -//--- check - if(w==114) - r=-7.207e-01; -//--- check - if(w==113) - r=-7.489e-01; -//--- check - if(w==112) - r=-7.779e-01; -//--- check - if(w==111) - r=-8.077e-01; -//--- check - if(w==110) - r=-8.383e-01; -//--- check - if(w==109) - r=-8.697e-01; -//--- check - if(w==108) - r=-9.018e-01; -//--- check - if(w==107) - r=-9.348e-01; -//--- check - if(w==106) - r=-9.685e-01; -//--- check - if(w==105) - r=-1.003e+00; -//--- check - if(w==104) - r=-1.039e+00; -//--- check - if(w==103) - r=-1.075e+00; -//--- check - if(w==102) - r=-1.112e+00; -//--- check - if(w==101) - r=-1.150e+00; -//--- check - if(w==100) - r=-1.189e+00; -//--- check - if(w==99) - r=-1.229e+00; -//--- check - if(w==98) - r=-1.269e+00; -//--- check - if(w==97) - r=-1.311e+00; -//--- check - if(w==96) - r=-1.353e+00; -//--- check - if(w==95) - r=-1.397e+00; -//--- check - if(w==94) - r=-1.441e+00; -//--- check - if(w==93) - r=-1.486e+00; -//--- check - if(w==92) - r=-1.533e+00; -//--- check - if(w==91) - r=-1.580e+00; -//--- check - if(w==90) - r=-1.628e+00; -//--- check - if(w==89) - r=-1.677e+00; -//--- check - if(w==88) - r=-1.728e+00; -//--- check - if(w==87) - r=-1.779e+00; -//--- check - if(w==86) - r=-1.831e+00; -//--- check - if(w==85) - r=-1.884e+00; -//--- check - if(w==84) - r=-1.939e+00; -//--- check - if(w==83) - r=-1.994e+00; -//--- check - if(w==82) - r=-2.051e+00; -//--- check - if(w==81) - r=-2.108e+00; -//--- check - if(w==80) - r=-2.167e+00; -//--- check - if(w==79) - r=-2.227e+00; -//--- check - if(w==78) - r=-2.288e+00; -//--- check - if(w==77) - r=-2.350e+00; -//--- check - if(w==76) - r=-2.414e+00; -//--- check - if(w==75) - r=-2.478e+00; -//--- check - if(w==74) - r=-2.544e+00; -//--- check - if(w==73) - r=-2.611e+00; -//--- check - if(w==72) - r=-2.679e+00; -//--- check - if(w==71) - r=-2.748e+00; -//--- check - if(w==70) - r=-2.819e+00; -//--- check - if(w==69) - r=-2.891e+00; -//--- check - if(w==68) - r=-2.964e+00; -//--- check - if(w==67) - r=-3.039e+00; -//--- check - if(w==66) - r=-3.115e+00; -//--- check - if(w==65) - r=-3.192e+00; -//--- check - if(w==64) - r=-3.270e+00; -//--- check - if(w==63) - r=-3.350e+00; -//--- check - if(w==62) - r=-3.432e+00; -//--- check - if(w==61) - r=-3.515e+00; -//--- check - if(w==60) - r=-3.599e+00; -//--- check - if(w==59) - r=-3.685e+00; -//--- check - if(w==58) - r=-3.772e+00; -//--- check - if(w==57) - r=-3.861e+00; -//--- check - if(w==56) - r=-3.952e+00; -//--- check - if(w==55) - r=-4.044e+00; -//--- check - if(w==54) - r=-4.138e+00; -//--- check - if(w==53) - r=-4.233e+00; -//--- check - if(w==52) - r=-4.330e+00; -//--- check - if(w==51) - r=-4.429e+00; -//--- check - if(w==50) - r=-4.530e+00; -//--- check - if(w==49) - r=-4.632e+00; -//--- check - if(w==48) - r=-4.736e+00; -//--- check - if(w==47) - r=-4.842e+00; -//--- check - if(w==46) - r=-4.950e+00; -//--- check - if(w==45) - r=-5.060e+00; -//--- check - if(w==44) - r=-5.172e+00; -//--- check - if(w==43) - r=-5.286e+00; -//--- check - if(w==42) - r=-5.402e+00; -//--- check - if(w==41) - r=-5.520e+00; -//--- check - if(w==40) - r=-5.641e+00; -//--- check - if(w==39) - r=-5.763e+00; -//--- check - if(w==38) - r=-5.889e+00; -//--- check - if(w==37) - r=-6.016e+00; -//--- check - if(w==36) - r=-6.146e+00; -//--- check - if(w==35) - r=-6.278e+00; -//--- check - if(w==34) - r=-6.413e+00; -//--- check - if(w==33) - r=-6.551e+00; -//--- check - if(w==32) - r=-6.692e+00; -//--- check - if(w==31) - r=-6.835e+00; -//--- check - if(w==30) - r=-6.981e+00; -//--- check - if(w==29) - r=-7.131e+00; -//--- check - if(w==28) - r=-7.283e+00; -//--- check - if(w==27) - r=-7.439e+00; -//--- check - if(w==26) - r=-7.599e+00; -//--- check - if(w==25) - r=-7.762e+00; -//--- check - if(w==24) - r=-7.928e+00; -//--- check - if(w==23) - r=-8.099e+00; -//--- check - if(w==22) - r=-8.274e+00; -//--- check - if(w==21) - r=-8.454e+00; -//--- check - if(w==20) - r=-8.640e+00; -//--- check - if(w==19) - r=-8.829e+00; -//--- check - if(w==18) - r=-9.023e+00; -//--- check - if(w==17) - r=-9.223e+00; -//--- check - if(w==16) - r=-9.426e+00; -//--- check - if(w==15) - r=-9.636e+00; -//--- check - if(w==14) - r=-9.856e+00; -//--- check - if(w==13) - r=-1.008e+01; -//--- check - if(w==12) - r=-1.031e+01; -//--- check - if(w==11) - r=-1.055e+01; -//--- check - if(w==10) - r=-1.079e+01; -//--- check - if(w==9) - r=-1.106e+01; -//--- check - if(w==8) - r=-1.134e+01; -//--- check - if(w==7) - r=-1.161e+01; -//--- check - if(w==6) - r=-1.192e+01; -//--- check - if(w==5) - r=-1.225e+01; -//--- check - if(w==4) - r=-1.261e+01; -//--- check - if(w==3) - r=-1.295e+01; -//--- check - if(w==2) - r=-1.346e+01; -//--- check - if(w==1) - r=-1.386e+01; -//--- check - if(w<=0) - r=-1.456e+01; -//--- return result - return(r); - } -//+------------------------------------------------------------------+ -//| Tail(S, 22) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W22(const double s) - { -//--- create variables - int w=0; - double r=0; -//--- check - w=(int)MathRound(-(3.080179e+01*s)+1.265000e+02); - if(w>=126) - r=-6.931e-01; -//--- check - if(w==125) - r=-7.189e-01; -//--- check - if(w==124) - r=-7.452e-01; -//--- check - if(w==123) - r=-7.722e-01; -//--- check - if(w==122) - r=-7.999e-01; -//--- check - if(w==121) - r=-8.283e-01; -//--- check - if(w==120) - r=-8.573e-01; -//--- check - if(w==119) - r=-8.871e-01; -//--- check - if(w==118) - r=-9.175e-01; -//--- check - if(w==117) - r=-9.486e-01; -//--- check - if(w==116) - r=-9.805e-01; -//--- check - if(w==115) - r=-1.013e+00; -//--- check - if(w==114) - r=-1.046e+00; -//--- check - if(w==113) - r=-1.080e+00; -//--- check - if(w==112) - r=-1.115e+00; -//--- check - if(w==111) - r=-1.151e+00; -//--- check - if(w==110) - r=-1.187e+00; -//--- check - if(w==109) - r=-1.224e+00; -//--- check - if(w==108) - r=-1.262e+00; -//--- check - if(w==107) - r=-1.301e+00; -//--- check - if(w==106) - r=-1.340e+00; -//--- check - if(w==105) - r=-1.381e+00; -//--- check - if(w==104) - r=-1.422e+00; -//--- check - if(w==103) - r=-1.464e+00; -//--- check - if(w==102) - r=-1.506e+00; -//--- check - if(w==101) - r=-1.550e+00; -//--- check - if(w==100) - r=-1.594e+00; -//--- check - if(w==99) - r=-1.640e+00; -//--- check - if(w==98) - r=-1.686e+00; -//--- check - if(w==97) - r=-1.733e+00; -//--- check - if(w==96) - r=-1.781e+00; -//--- check - if(w==95) - r=-1.830e+00; -//--- check - if(w==94) - r=-1.880e+00; -//--- check - if(w==93) - r=-1.930e+00; -//--- check - if(w==92) - r=-1.982e+00; -//--- check - if(w==91) - r=-2.034e+00; -//--- check - if(w==90) - r=-2.088e+00; -//--- check - if(w==89) - r=-2.142e+00; -//--- check - if(w==88) - r=-2.198e+00; -//--- check - if(w==87) - r=-2.254e+00; -//--- check - if(w==86) - r=-2.312e+00; -//--- check - if(w==85) - r=-2.370e+00; -//--- check - if(w==84) - r=-2.429e+00; -//--- check - if(w==83) - r=-2.490e+00; -//--- check - if(w==82) - r=-2.551e+00; -//--- check - if(w==81) - r=-2.614e+00; -//--- check - if(w==80) - r=-2.677e+00; -//--- check - if(w==79) - r=-2.742e+00; -//--- check - if(w==78) - r=-2.808e+00; -//--- check - if(w==77) - r=-2.875e+00; -//--- check - if(w==76) - r=-2.943e+00; -//--- check - if(w==75) - r=-3.012e+00; -//--- check - if(w==74) - r=-3.082e+00; -//--- check - if(w==73) - r=-3.153e+00; -//--- check - if(w==72) - r=-3.226e+00; -//--- check - if(w==71) - r=-3.300e+00; -//--- check - if(w==70) - r=-3.375e+00; -//--- check - if(w==69) - r=-3.451e+00; -//--- check - if(w==68) - r=-3.529e+00; -//--- check - if(w==67) - r=-3.607e+00; -//--- check - if(w==66) - r=-3.687e+00; -//--- check - if(w==65) - r=-3.769e+00; -//--- check - if(w==64) - r=-3.851e+00; -//--- check - if(w==63) - r=-3.935e+00; -//--- check - if(w==62) - r=-4.021e+00; -//--- check - if(w==61) - r=-4.108e+00; -//--- check - if(w==60) - r=-4.196e+00; -//--- check - if(w==59) - r=-4.285e+00; -//--- check - if(w==58) - r=-4.376e+00; -//--- check - if(w==57) - r=-4.469e+00; -//--- check - if(w==56) - r=-4.563e+00; -//--- check - if(w==55) - r=-4.659e+00; -//--- check - if(w==54) - r=-4.756e+00; -//--- check - if(w==53) - r=-4.855e+00; -//--- check - if(w==52) - r=-4.955e+00; -//--- check - if(w==51) - r=-5.057e+00; -//--- check - if(w==50) - r=-5.161e+00; -//--- check - if(w==49) - r=-5.266e+00; -//--- check - if(w==48) - r=-5.374e+00; -//--- check - if(w==47) - r=-5.483e+00; -//--- check - if(w==46) - r=-5.594e+00; -//--- check - if(w==45) - r=-5.706e+00; -//--- check - if(w==44) - r=-5.821e+00; -//--- check - if(w==43) - r=-5.938e+00; -//--- check - if(w==42) - r=-6.057e+00; -//--- check - if(w==41) - r=-6.177e+00; -//--- check - if(w==40) - r=-6.300e+00; -//--- check - if(w==39) - r=-6.426e+00; -//--- check - if(w==38) - r=-6.553e+00; -//--- check - if(w==37) - r=-6.683e+00; -//--- check - if(w==36) - r=-6.815e+00; -//--- check - if(w==35) - r=-6.949e+00; -//--- check - if(w==34) - r=-7.086e+00; -//--- check - if(w==33) - r=-7.226e+00; -//--- check - if(w==32) - r=-7.368e+00; -//--- check - if(w==31) - r=-7.513e+00; -//--- check - if(w==30) - r=-7.661e+00; -//--- check - if(w==29) - r=-7.813e+00; -//--- check - if(w==28) - r=-7.966e+00; -//--- check - if(w==27) - r=-8.124e+00; -//--- check - if(w==26) - r=-8.285e+00; -//--- check - if(w==25) - r=-8.449e+00; -//--- check - if(w==24) - r=-8.617e+00; -//--- check - if(w==23) - r=-8.789e+00; -//--- check - if(w==22) - r=-8.965e+00; -//--- check - if(w==21) - r=-9.147e+00; -//--- check - if(w==20) - r=-9.333e+00; -//--- check - if(w==19) - r=-9.522e+00; -//--- check - if(w==18) - r=-9.716e+00; -//--- check - if(w==17) - r=-9.917e+00; -//--- check - if(w==16) - r=-1.012e+01; -//--- check - if(w==15) - r=-1.033e+01; -//--- check - if(w==14) - r=-1.055e+01; -//--- check - if(w==13) - r=-1.077e+01; -//--- check - if(w==12) - r=-1.100e+01; -//--- check - if(w==11) - r=-1.124e+01; -//--- check - if(w==10) - r=-1.149e+01; -//--- check - if(w==9) - r=-1.175e+01; -//--- check - if(w==8) - r=-1.203e+01; -//--- check - if(w==7) - r=-1.230e+01; -//--- check - if(w==6) - r=-1.261e+01; -//--- check - if(w==5) - r=-1.295e+01; -//--- check - if(w==4) - r=-1.330e+01; -//--- check - if(w==3) - r=-1.364e+01; -//--- check - if(w==2) - r=-1.415e+01; -//--- check - if(w==1) - r=-1.456e+01; -//--- check - if(w<=0) - r=-1.525e+01; -//--- return result - return(r); - } -//+------------------------------------------------------------------+ -//| Tail(S, 23) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W23(const double s) - { -//--- create variables - int w=0; - double r=0; -//--- check - w=(int)MathRound(-(3.287856e+01*s)+1.380000e+02); - if(w>=138) - r=-6.813e-01; -//--- check - if(w==137) - r=-7.051e-01; -//--- check - if(w==136) - r=-7.295e-01; -//--- check - if(w==135) - r=-7.544e-01; -//--- check - if(w==134) - r=-7.800e-01; -//--- check - if(w==133) - r=-8.061e-01; -//--- check - if(w==132) - r=-8.328e-01; -//--- check - if(w==131) - r=-8.601e-01; -//--- check - if(w==130) - r=-8.880e-01; -//--- check - if(w==129) - r=-9.166e-01; -//--- check - if(w==128) - r=-9.457e-01; -//--- check - if(w==127) - r=-9.755e-01; -//--- check - if(w==126) - r=-1.006e+00; -//--- check - if(w==125) - r=-1.037e+00; -//--- check - if(w==124) - r=-1.069e+00; -//--- check - if(w==123) - r=-1.101e+00; -//--- check - if(w==122) - r=-1.134e+00; -//--- check - if(w==121) - r=-1.168e+00; -//--- check - if(w==120) - r=-1.202e+00; -//--- check - if(w==119) - r=-1.237e+00; -//--- check - if(w==118) - r=-1.273e+00; -//--- check - if(w==117) - r=-1.309e+00; -//--- check - if(w==116) - r=-1.347e+00; -//--- check - if(w==115) - r=-1.384e+00; -//--- check - if(w==114) - r=-1.423e+00; -//--- check - if(w==113) - r=-1.462e+00; -//--- check - if(w==112) - r=-1.502e+00; -//--- check - if(w==111) - r=-1.543e+00; -//--- check - if(w==110) - r=-1.585e+00; -//--- check - if(w==109) - r=-1.627e+00; -//--- check - if(w==108) - r=-1.670e+00; -//--- check - if(w==107) - r=-1.714e+00; -//--- check - if(w==106) - r=-1.758e+00; -//--- check - if(w==105) - r=-1.804e+00; -//--- check - if(w==104) - r=-1.850e+00; -//--- check - if(w==103) - r=-1.897e+00; -//--- check - if(w==102) - r=-1.944e+00; -//--- check - if(w==101) - r=-1.993e+00; -//--- check - if(w==100) - r=-2.042e+00; -//--- check - if(w==99) - r=-2.093e+00; -//--- check - if(w==98) - r=-2.144e+00; -//--- check - if(w==97) - r=-2.195e+00; -//--- check - if(w==96) - r=-2.248e+00; -//--- check - if(w==95) - r=-2.302e+00; -//--- check - if(w==94) - r=-2.356e+00; -//--- check - if(w==93) - r=-2.412e+00; -//--- check - if(w==92) - r=-2.468e+00; -//--- check - if(w==91) - r=-2.525e+00; -//--- check - if(w==90) - r=-2.583e+00; -//--- check - if(w==89) - r=-2.642e+00; -//--- check - if(w==88) - r=-2.702e+00; -//--- check - if(w==87) - r=-2.763e+00; -//--- check - if(w==86) - r=-2.825e+00; -//--- check - if(w==85) - r=-2.888e+00; -//--- check - if(w==84) - r=-2.951e+00; -//--- check - if(w==83) - r=-3.016e+00; -//--- check - if(w==82) - r=-3.082e+00; -//--- check - if(w==81) - r=-3.149e+00; -//--- check - if(w==80) - r=-3.216e+00; -//--- check - if(w==79) - r=-3.285e+00; -//--- check - if(w==78) - r=-3.355e+00; -//--- check - if(w==77) - r=-3.426e+00; -//--- check - if(w==76) - r=-3.498e+00; -//--- check - if(w==75) - r=-3.571e+00; -//--- check - if(w==74) - r=-3.645e+00; -//--- check - if(w==73) - r=-3.721e+00; -//--- check - if(w==72) - r=-3.797e+00; -//--- check - if(w==71) - r=-3.875e+00; -//--- check - if(w==70) - r=-3.953e+00; -//--- check - if(w==69) - r=-4.033e+00; -//--- check - if(w==68) - r=-4.114e+00; -//--- check - if(w==67) - r=-4.197e+00; -//--- check - if(w==66) - r=-4.280e+00; -//--- check - if(w==65) - r=-4.365e+00; -//--- check - if(w==64) - r=-4.451e+00; -//--- check - if(w==63) - r=-4.539e+00; -//--- check - if(w==62) - r=-4.628e+00; -//--- check - if(w==61) - r=-4.718e+00; -//--- check - if(w==60) - r=-4.809e+00; -//--- check - if(w==59) - r=-4.902e+00; -//--- check - if(w==58) - r=-4.996e+00; -//--- check - if(w==57) - r=-5.092e+00; -//--- check - if(w==56) - r=-5.189e+00; -//--- check - if(w==55) - r=-5.287e+00; -//--- check - if(w==54) - r=-5.388e+00; -//--- check - if(w==53) - r=-5.489e+00; -//--- check - if(w==52) - r=-5.592e+00; -//--- check - if(w==51) - r=-5.697e+00; -//--- check - if(w==50) - r=-5.804e+00; -//--- check - if(w==49) - r=-5.912e+00; -//--- check - if(w==48) - r=-6.022e+00; -//--- check - if(w==47) - r=-6.133e+00; -//--- check - if(w==46) - r=-6.247e+00; -//--- check - if(w==45) - r=-6.362e+00; -//--- check - if(w==44) - r=-6.479e+00; -//--- check - if(w==43) - r=-6.598e+00; -//--- check - if(w==42) - r=-6.719e+00; -//--- check - if(w==41) - r=-6.842e+00; -//--- check - if(w==40) - r=-6.967e+00; -//--- check - if(w==39) - r=-7.094e+00; -//--- check - if(w==38) - r=-7.224e+00; -//--- check - if(w==37) - r=-7.355e+00; -//--- check - if(w==36) - r=-7.489e+00; -//--- check - if(w==35) - r=-7.625e+00; -//--- check - if(w==34) - r=-7.764e+00; -//--- check - if(w==33) - r=-7.905e+00; -//--- check - if(w==32) - r=-8.049e+00; -//--- check - if(w==31) - r=-8.196e+00; -//--- check - if(w==30) - r=-8.345e+00; -//--- check - if(w==29) - r=-8.498e+00; -//--- check - if(w==28) - r=-8.653e+00; -//--- check - if(w==27) - r=-8.811e+00; -//--- check - if(w==26) - r=-8.974e+00; -//--- check - if(w==25) - r=-9.139e+00; -//--- check - if(w==24) - r=-9.308e+00; -//--- check - if(w==23) - r=-9.481e+00; -//--- check - if(w==22) - r=-9.658e+00; -//--- check - if(w==21) - r=-9.840e+00; -//--- check - if(w==20) - r=-1.003e+01; -//--- check - if(w==19) - r=-1.022e+01; -//--- check - if(w==18) - r=-1.041e+01; -//--- check - if(w==17) - r=-1.061e+01; -//--- check - if(w==16) - r=-1.081e+01; -//--- check - if(w==15) - r=-1.102e+01; -//--- check - if(w==14) - r=-1.124e+01; -//--- check - if(w==13) - r=-1.147e+01; -//--- check - if(w==12) - r=-1.169e+01; -//--- check - if(w==11) - r=-1.194e+01; -//--- check - if(w==10) - r=-1.218e+01; -//--- check - if(w==9) - r=-1.245e+01; -//--- check - if(w==8) - r=-1.272e+01; -//--- check - if(w==7) - r=-1.300e+01; -//--- check - if(w==6) - r=-1.330e+01; -//--- check - if(w==5) - r=-1.364e+01; -//--- check - if(w==4) - r=-1.400e+01; -//--- check - if(w==3) - r=-1.433e+01; -//--- check - if(w==2) - r=-1.484e+01; -//--- check - if(w==1) - r=-1.525e+01; -//--- check - if(w<=0) - r=-1.594e+01; -//--- return result - return(r); - } -//+------------------------------------------------------------------+ -//| Tail(S, 24) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W24(const double s) - { -//--- create variables - int w=0; - double r=0; -//--- check - w=(int)MathRound(-(3.500000e+01*s)+1.500000e+02); - if(w>=150) - r=-6.820e-01; -//--- check - if(w==149) - r=-7.044e-01; -//--- check - if(w==148) - r=-7.273e-01; -//--- check - if(w==147) - r=-7.507e-01; -//--- check - if(w==146) - r=-7.746e-01; -//--- check - if(w==145) - r=-7.990e-01; -//--- check - if(w==144) - r=-8.239e-01; -//--- check - if(w==143) - r=-8.494e-01; -//--- check - if(w==142) - r=-8.754e-01; -//--- check - if(w==141) - r=-9.020e-01; -//--- check - if(w==140) - r=-9.291e-01; -//--- check - if(w==139) - r=-9.567e-01; -//--- check - if(w==138) - r=-9.849e-01; -//--- check - if(w==137) - r=-1.014e+00; -//--- check - if(w==136) - r=-1.043e+00; -//--- check - if(w==135) - r=-1.073e+00; -//--- check - if(w==134) - r=-1.103e+00; -//--- check - if(w==133) - r=-1.135e+00; -//--- check - if(w==132) - r=-1.166e+00; -//--- check - if(w==131) - r=-1.198e+00; -//--- check - if(w==130) - r=-1.231e+00; -//--- check - if(w==129) - r=-1.265e+00; -//--- check - if(w==128) - r=-1.299e+00; -//--- check - if(w==127) - r=-1.334e+00; -//--- check - if(w==126) - r=-1.369e+00; -//--- check - if(w==125) - r=-1.405e+00; -//--- check - if(w==124) - r=-1.441e+00; -//--- check - if(w==123) - r=-1.479e+00; -//--- check - if(w==122) - r=-1.517e+00; -//--- check - if(w==121) - r=-1.555e+00; -//--- check - if(w==120) - r=-1.594e+00; -//--- check - if(w==119) - r=-1.634e+00; -//--- check - if(w==118) - r=-1.675e+00; -//--- check - if(w==117) - r=-1.716e+00; -//--- check - if(w==116) - r=-1.758e+00; -//--- check - if(w==115) - r=-1.800e+00; -//--- check - if(w==114) - r=-1.844e+00; -//--- check - if(w==113) - r=-1.888e+00; -//--- check - if(w==112) - r=-1.932e+00; -//--- check - if(w==111) - r=-1.978e+00; -//--- check - if(w==110) - r=-2.024e+00; -//--- check - if(w==109) - r=-2.070e+00; -//--- check - if(w==108) - r=-2.118e+00; -//--- check - if(w==107) - r=-2.166e+00; -//--- check - if(w==106) - r=-2.215e+00; -//--- check - if(w==105) - r=-2.265e+00; -//--- check - if(w==104) - r=-2.316e+00; -//--- check - if(w==103) - r=-2.367e+00; -//--- check - if(w==102) - r=-2.419e+00; -//--- check - if(w==101) - r=-2.472e+00; -//--- check - if(w==100) - r=-2.526e+00; -//--- check - if(w==99) - r=-2.580e+00; -//--- check - if(w==98) - r=-2.636e+00; -//--- check - if(w==97) - r=-2.692e+00; -//--- check - if(w==96) - r=-2.749e+00; -//--- check - if(w==95) - r=-2.806e+00; -//--- check - if(w==94) - r=-2.865e+00; -//--- check - if(w==93) - r=-2.925e+00; -//--- check - if(w==92) - r=-2.985e+00; -//--- check - if(w==91) - r=-3.046e+00; -//--- check - if(w==90) - r=-3.108e+00; -//--- check - if(w==89) - r=-3.171e+00; -//--- check - if(w==88) - r=-3.235e+00; -//--- check - if(w==87) - r=-3.300e+00; -//--- check - if(w==86) - r=-3.365e+00; -//--- check - if(w==85) - r=-3.432e+00; -//--- check - if(w==84) - r=-3.499e+00; -//--- check - if(w==83) - r=-3.568e+00; -//--- check - if(w==82) - r=-3.637e+00; -//--- check - if(w==81) - r=-3.708e+00; -//--- check - if(w==80) - r=-3.779e+00; -//--- check - if(w==79) - r=-3.852e+00; -//--- check - if(w==78) - r=-3.925e+00; -//--- check - if(w==77) - r=-4.000e+00; -//--- check - if(w==76) - r=-4.075e+00; -//--- check - if(w==75) - r=-4.151e+00; -//--- check - if(w==74) - r=-4.229e+00; -//--- check - if(w==73) - r=-4.308e+00; -//--- check - if(w==72) - r=-4.387e+00; -//--- check - if(w==71) - r=-4.468e+00; -//--- check - if(w==70) - r=-4.550e+00; -//--- check - if(w==69) - r=-4.633e+00; -//--- check - if(w==68) - r=-4.718e+00; -//--- check - if(w==67) - r=-4.803e+00; -//--- check - if(w==66) - r=-4.890e+00; -//--- check - if(w==65) - r=-4.978e+00; -//--- check - if(w==64) - r=-5.067e+00; -//--- check - if(w==63) - r=-5.157e+00; -//--- check - if(w==62) - r=-5.249e+00; -//--- check - if(w==61) - r=-5.342e+00; -//--- check - if(w==60) - r=-5.436e+00; -//--- check - if(w==59) - r=-5.531e+00; -//--- check - if(w==58) - r=-5.628e+00; -//--- check - if(w==57) - r=-5.727e+00; -//--- check - if(w==56) - r=-5.826e+00; -//--- check - if(w==55) - r=-5.927e+00; -//--- check - if(w==54) - r=-6.030e+00; -//--- check - if(w==53) - r=-6.134e+00; -//--- check - if(w==52) - r=-6.240e+00; -//--- check - if(w==51) - r=-6.347e+00; -//--- check - if(w==50) - r=-6.456e+00; -//--- check - if(w==49) - r=-6.566e+00; -//--- check - if(w==48) - r=-6.678e+00; -//--- check - if(w==47) - r=-6.792e+00; -//--- check - if(w==46) - r=-6.907e+00; -//--- check - if(w==45) - r=-7.025e+00; -//--- check - if(w==44) - r=-7.144e+00; -//--- check - if(w==43) - r=-7.265e+00; -//--- check - if(w==42) - r=-7.387e+00; -//--- check - if(w==41) - r=-7.512e+00; -//--- check - if(w==40) - r=-7.639e+00; -//--- check - if(w==39) - r=-7.768e+00; -//--- check - if(w==38) - r=-7.899e+00; -//--- check - if(w==37) - r=-8.032e+00; -//--- check - if(w==36) - r=-8.167e+00; -//--- check - if(w==35) - r=-8.305e+00; -//--- check - if(w==34) - r=-8.445e+00; -//--- check - if(w==33) - r=-8.588e+00; -//--- check - if(w==32) - r=-8.733e+00; -//--- check - if(w==31) - r=-8.881e+00; -//--- check - if(w==30) - r=-9.031e+00; -//--- check - if(w==29) - r=-9.185e+00; -//--- check - if(w==28) - r=-9.341e+00; -//--- check - if(w==27) - r=-9.501e+00; -//--- check - if(w==26) - r=-9.664e+00; -//--- check - if(w==25) - r=-9.830e+00; -//--- check - if(w==24) - r=-1.000e+01; -//--- check - if(w==23) - r=-1.017e+01; -//--- check - if(w==22) - r=-1.035e+01; -//--- check - if(w==21) - r=-1.053e+01; -//--- check - if(w==20) - r=-1.072e+01; -//--- check - if(w==19) - r=-1.091e+01; -//--- check - if(w==18) - r=-1.110e+01; -//--- check - if(w==17) - r=-1.130e+01; -//--- check - if(w==16) - r=-1.151e+01; -//--- check - if(w==15) - r=-1.172e+01; -//--- check - if(w==14) - r=-1.194e+01; -//--- check - if(w==13) - r=-1.216e+01; -//--- check - if(w==12) - r=-1.239e+01; -//--- check - if(w==11) - r=-1.263e+01; -//--- check - if(w==10) - r=-1.287e+01; -//--- check - if(w==9) - r=-1.314e+01; -//--- check - if(w==8) - r=-1.342e+01; -//--- check - if(w==7) - r=-1.369e+01; -//--- check - if(w==6) - r=-1.400e+01; -//--- check - if(w==5) - r=-1.433e+01; -//--- check - if(w==4) - r=-1.469e+01; -//--- check - if(w==3) - r=-1.503e+01; -//--- check - if(w==2) - r=-1.554e+01; -//--- check - if(w==1) - r=-1.594e+01; -//--- check - if(w<=0) - r=-1.664e+01; -//--- return result - return(r); - } -//+------------------------------------------------------------------+ -//| Tail(S, 25) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W25(const double s) - { -//--- create variables - double result=0; - double x=0; - double tj=0; - double tj1=0; -//--- change values - x=MathMin(2*(s-0.000000e+00)/4.000000e+00-1,1.0); - tj=1; - tj1=x; -//--- interpolating - WCheb(x,-5.150509e+00,tj,tj1,result); - WCheb(x,-5.695528e+00,tj,tj1,result); - WCheb(x,-1.437637e+00,tj,tj1,result); - WCheb(x,-2.611906e-01,tj,tj1,result); - WCheb(x,-7.625722e-02,tj,tj1,result); - WCheb(x,-2.579892e-02,tj,tj1,result); - WCheb(x,-1.086876e-02,tj,tj1,result); - WCheb(x,-2.906543e-03,tj,tj1,result); - WCheb(x,-2.354881e-03,tj,tj1,result); - WCheb(x,1.007195e-04,tj,tj1,result); - WCheb(x,-8.437327e-04,tj,tj1,result); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tail(S, 26) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W26(const double s) - { -//--- create variables - double result=0; - double x=0; - double tj=0; - double tj1=0; -//--- change values - x=MathMin(2*(s-0.000000e+00)/4.000000e+00-1,1.0); - tj=1; - tj1=x; -//--- interpolating - WCheb(x,-5.117622e+00,tj,tj1,result); - WCheb(x,-5.635159e+00,tj,tj1,result); - WCheb(x,-1.395167e+00,tj,tj1,result); - WCheb(x,-2.382823e-01,tj,tj1,result); - WCheb(x,-6.531987e-02,tj,tj1,result); - WCheb(x,-2.060112e-02,tj,tj1,result); - WCheb(x,-8.203697e-03,tj,tj1,result); - WCheb(x,-1.516523e-03,tj,tj1,result); - WCheb(x,-1.431364e-03,tj,tj1,result); - WCheb(x,6.384553e-04,tj,tj1,result); - WCheb(x,-3.238369e-04,tj,tj1,result); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tail(S, 27) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W27(const double s) - { -//--- create variables - double result=0; - double x=0; - double tj=0; - double tj1=0; -//--- change values - x=MathMin(2*(s-0.000000e+00)/4.000000e+00-1,1.0); - tj=1; - tj1=x; -//--- interpolating - WCheb(x,-5.089731e+00,tj,tj1,result); - WCheb(x,-5.584248e+00,tj,tj1,result); - WCheb(x,-1.359966e+00,tj,tj1,result); - WCheb(x,-2.203696e-01,tj,tj1,result); - WCheb(x,-5.753344e-02,tj,tj1,result); - WCheb(x,-1.761891e-02,tj,tj1,result); - WCheb(x,-7.096897e-03,tj,tj1,result); - WCheb(x,-1.419108e-03,tj,tj1,result); - WCheb(x,-1.581214e-03,tj,tj1,result); - WCheb(x,3.033766e-04,tj,tj1,result); - WCheb(x,-5.901441e-04,tj,tj1,result); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tail(S, 28) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W28(const double s) - { -//--- create variables - double result=0; - double x=0; - double tj=0; - double tj1=0; -//--- change values - x=MathMin(2*(s-0.000000e+00)/4.000000e+00-1,1.0); - tj=1; - tj1=x; -//--- interpolating - WCheb(x,-5.065046e+00,tj,tj1,result); - WCheb(x,-5.539163e+00,tj,tj1,result); - WCheb(x,-1.328939e+00,tj,tj1,result); - WCheb(x,-2.046376e-01,tj,tj1,result); - WCheb(x,-5.061515e-02,tj,tj1,result); - WCheb(x,-1.469271e-02,tj,tj1,result); - WCheb(x,-5.711578e-03,tj,tj1,result); - WCheb(x,-8.389153e-04,tj,tj1,result); - WCheb(x,-1.250575e-03,tj,tj1,result); - WCheb(x,4.047245e-04,tj,tj1,result); - WCheb(x,-5.128555e-04,tj,tj1,result); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tail(S, 29) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W29(const double s) - { -//--- create variables - double result=0; - double x=0; - double tj=0; - double tj1=0; -//--- change values - x=MathMin(2*(s-0.000000e+00)/4.000000e+00-1,1.0); - tj=1; - tj1=x; -//--- interpolating - WCheb(x,-5.043413e+00,tj,tj1,result); - WCheb(x,-5.499756e+00,tj,tj1,result); - WCheb(x,-1.302137e+00,tj,tj1,result); - WCheb(x,-1.915129e-01,tj,tj1,result); - WCheb(x,-4.516329e-02,tj,tj1,result); - WCheb(x,-1.260064e-02,tj,tj1,result); - WCheb(x,-4.817269e-03,tj,tj1,result); - WCheb(x,-5.478130e-04,tj,tj1,result); - WCheb(x,-1.111668e-03,tj,tj1,result); - WCheb(x,4.093451e-04,tj,tj1,result); - WCheb(x,-5.135860e-04,tj,tj1,result); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tail(S, 30) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W30(const double s) - { -//--- create variables - double result=0; - double x=0; - double tj=0; - double tj1=0; -//--- change values - x=MathMin(2*(s-0.000000e+00)/4.000000e+00-1,1.0); - tj=1; - tj1=x; -//--- interpolating - WCheb(x,-5.024071e+00,tj,tj1,result); - WCheb(x,-5.464515e+00,tj,tj1,result); - WCheb(x,-1.278342e+00,tj,tj1,result); - WCheb(x,-1.800030e-01,tj,tj1,result); - WCheb(x,-4.046294e-02,tj,tj1,result); - WCheb(x,-1.076162e-02,tj,tj1,result); - WCheb(x,-3.968677e-03,tj,tj1,result); - WCheb(x,-1.911679e-04,tj,tj1,result); - WCheb(x,-8.619185e-04,tj,tj1,result); - WCheb(x,5.125362e-04,tj,tj1,result); - WCheb(x,-3.984370e-04,tj,tj1,result); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tail(S, 40) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W40(const double s) - { -//--- create variables - double result=0; - double x=0; - double tj=0; - double tj1=0; -//--- change values - x=MathMin(2*(s-0.000000e+00)/4.000000e+00-1,1.0); - tj=1; - tj1=x; -//--- interpolating - WCheb(x,-4.904809e+00,tj,tj1,result); - WCheb(x,-5.248327e+00,tj,tj1,result); - WCheb(x,-1.136698e+00,tj,tj1,result); - WCheb(x,-1.170982e-01,tj,tj1,result); - WCheb(x,-1.824427e-02,tj,tj1,result); - WCheb(x,-3.888648e-03,tj,tj1,result); - WCheb(x,-1.344929e-03,tj,tj1,result); - WCheb(x,2.790407e-04,tj,tj1,result); - WCheb(x,-4.619858e-04,tj,tj1,result); - WCheb(x,3.359121e-04,tj,tj1,result); - WCheb(x,-2.883026e-04,tj,tj1,result); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tail(S, 60) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W60(const double s) - { -//--- create variables - double result=0; - double x=0; - double tj=0; - double tj1=0; -//--- change values - x=MathMin(2*(s-0.000000e+00)/4.000000e+00-1,1.0); - tj=1; - tj1=x; -//--- interpolating - WCheb(x,-4.809656e+00,tj,tj1,result); - WCheb(x,-5.077191e+00,tj,tj1,result); - WCheb(x,-1.029402e+00,tj,tj1,result); - WCheb(x,-7.507931e-02,tj,tj1,result); - WCheb(x,-6.506226e-03,tj,tj1,result); - WCheb(x,-1.391278e-03,tj,tj1,result); - WCheb(x,-4.263635e-04,tj,tj1,result); - WCheb(x,2.302271e-04,tj,tj1,result); - WCheb(x,-2.384348e-04,tj,tj1,result); - WCheb(x,1.865587e-04,tj,tj1,result); - WCheb(x,-1.622355e-04,tj,tj1,result); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tail(S, 120) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W120(const double s) - { -//--- create variables - double result=0; - double x=0; - double tj=0; - double tj1=0; -//--- change values - x=MathMin(2*(s-0.000000e+00)/4.000000e+00-1,1.0); - tj=1; - tj1=x; -//--- interpolating - WCheb(x,-4.729426e+00,tj,tj1,result); - WCheb(x,-4.934426e+00,tj,tj1,result); - WCheb(x,-9.433231e-01,tj,tj1,result); - WCheb(x,-4.492504e-02,tj,tj1,result); - WCheb(x,1.673948e-05,tj,tj1,result); - WCheb(x,-6.077014e-04,tj,tj1,result); - WCheb(x,-7.215768e-05,tj,tj1,result); - WCheb(x,9.086734e-05,tj,tj1,result); - WCheb(x,-8.447980e-05,tj,tj1,result); - WCheb(x,6.705028e-05,tj,tj1,result); - WCheb(x,-5.828507e-05,tj,tj1,result); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tail(S, 200) | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::W200(const double s) - { -//--- create variables - double result=0; - double x=0; - double tj=0; - double tj1=0; -//--- change values - x=MathMin(2*(s-0.000000e+00)/4.000000e+00-1,1.0); - tj=1; - tj1=x; -//--- interpolating - WCheb(x,-4.700240e+00,tj,tj1,result); - WCheb(x,-4.883080e+00,tj,tj1,result); - WCheb(x,-9.132168e-01,tj,tj1,result); - WCheb(x,-3.512684e-02,tj,tj1,result); - WCheb(x,1.726342e-03,tj,tj1,result); - WCheb(x,-5.189796e-04,tj,tj1,result); - WCheb(x,-1.628659e-06,tj,tj1,result); - WCheb(x,4.261786e-05,tj,tj1,result); - WCheb(x,-4.002498e-05,tj,tj1,result); - WCheb(x,3.146287e-05,tj,tj1,result); - WCheb(x,-2.727576e-05,tj,tj1,result); -//--- return result - return(result); - } -//+------------------------------------------------------------------+ -//| Tail(S,N), S>=0 | -//+------------------------------------------------------------------+ -static double CWilcoxonSignedRank::WSigma(const double s,const int n) - { -//--- create variables - double f0; - double f1; - double f2; - double f3; - double f4; - double x0; - double x1; - double x2; - double x3; - double x4; - double x; -//--- initialization - f4=0; -//--- check - if(n==5) - return(W5(s)); -//--- check - if(n==6) - return(W6(s)); -//--- check - if(n==7) - return(W7(s)); -//--- check - if(n==8) - return(W8(s)); -//--- check - if(n==9) - return(W9(s)); -//--- check - if(n==10) - return(W10(s)); -//--- check - if(n==11) - return(W11(s)); -//--- check - if(n==12) - return(W12(s)); -//--- check - if(n==13) - return(W13(s)); -//--- check - if(n==14) - return(W14(s)); -//--- check - if(n==15) - return(W15(s)); -//--- check - if(n==16) - return(W16(s)); -//--- check - if(n==17) - return(W17(s)); -//--- check - if(n==18) - return(W18(s)); -//--- check - if(n==19) - return(W19(s)); -//--- check - if(n==20) - return(W20(s)); -//--- check - if(n==21) - return(W21(s)); -//--- check - if(n==22) - return(W22(s)); -//--- check - if(n==23) - return(W23(s)); -//--- check - if(n==24) - return(W24(s)); -//--- check - if(n==25) - return(W25(s)); -//--- check - if(n==26) - return(W26(s)); -//--- check - if(n==27) - return(W27(s)); -//--- check - if(n==28) - return(W28(s)); -//--- check - if(n==29) - return(W29(s)); -//--- check - if(n==30) - return(W30(s)); -//--- check - if(n>30) - { - x=1.0/n; - x0=1.0/30; - f0=W30(s); - x1=1.0/40; - f1=W40(s); - x2=1.0/60; - f2=W60(s); - x3=1.0/120; - f3=W120(s); - x4=1.0/200; - f4=W200(s); - //--- get result - f1=((x-x0)*f1-(x-x1)*f0)/(x1-x0); - f2=((x-x0)*f2-(x-x2)*f0)/(x2-x0); - f3=((x-x0)*f3-(x-x3)*f0)/(x3-x0); - f4=((x-x0)*f4-(x-x4)*f0)/(x4-x0); - f2=((x-x1)*f2-(x-x2)*f1)/(x2-x1); - f3=((x-x1)*f3-(x-x3)*f1)/(x3-x1); - f4=((x-x1)*f4-(x-x4)*f1)/(x4-x1); - f3=((x-x2)*f3-(x-x3)*f2)/(x3-x2); - f4=((x-x2)*f4-(x-x4)*f2)/(x4-x2); - f4=((x-x3)*f4-(x-x4)*f3)/(x4-x3); - } -//--- return result - return(f4); - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Fuzzy/dictionary.mqh b/Include/Math/Fuzzy/dictionary.mqh deleted file mode 100644 index 5e93a4c..0000000 --- a/Include/Math/Fuzzy/dictionary.mqh +++ /dev/null @@ -1,197 +0,0 @@ -//+------------------------------------------------------------------+ -//| dictionary.mqh | -//| 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 -#include "RuleParser.mqh" -//+------------------------------------------------------------------+ -//| Gets the value associated with the specified key in the CList | -//| Where key - string, value - CObject | -//+------------------------------------------------------------------+ -bool TryGetValue(CList *list,string key,CObject *&value) - { - for(int i=0; i -#include "FuzzyVariable.mqh" -#include "InferenceMethod.mqh" -//+------------------------------------------------------------------+ -//| Purpose: Creating fuzzy rules | -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ -//| And/Or operator type | -//+------------------------------------------------------------------+ -enum OperatorType - { - And, // And operator - Or // Or operator - }; -//+------------------------------------------------------------------+ -//| Hedge modifiers | -//+------------------------------------------------------------------+ -enum HedgeType - { - None, // None - Slightly, // Cube root - Somewhat, // Square root - Very, // Square - Extremely // Cube - }; -//+------------------------------------------------------------------+ -//| Class of CConditions used in the 'if' expression | -//+------------------------------------------------------------------+ -class ICondition : public CObject - { -public: - //--- method to check type - virtual bool IsTypeOf(EnCondition type) { return(type==TYPE_CLASS_ICondition); } - }; -//+------------------------------------------------------------------+ -//| Single condition | -//+------------------------------------------------------------------+ -class CSingleCondition : public ICondition - { -private: - INamedVariable *m_var; // Type of variable - INamedValue *m_term; // Type of value - bool m_not; // Is MF inverted - -public: - CSingleCondition(void); - CSingleCondition(INamedVariable *var,INamedValue *term); - CSingleCondition(INamedVariable *var,INamedValue *term,bool not); - ~CSingleCondition(void); - //--- methods gets or sets the varriable - INamedVariable *Var(void) { return(m_var); } - void Var(INamedVariable *value) { m_var=value; } - //--- methods gets or sets mark "Is MF inverted" - bool Not(void) { return(m_not); } - void Not(bool not) { m_not=not; } - //--- methods gets or sets term in expression - INamedValue *Term(void) { return(m_term); } - void Term(INamedValue *value) { m_term=value; } - //--- method to check type - virtual bool IsTypeOf(EnCondition type) { return(type==TYPE_CLASS_SingleCondition); } - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CSingleCondition::CSingleCondition(void) - { - m_var = NULL; - m_not = false; - m_term=NULL; - }; -//+------------------------------------------------------------------+ -//| First constructor with parameters | -//+------------------------------------------------------------------+ -CSingleCondition::CSingleCondition(INamedVariable *var,INamedValue *term) - { - m_var=var; - m_term=term; - } -//+------------------------------------------------------------------+ -//| Second constructor with parameters | -//+------------------------------------------------------------------+ -CSingleCondition::CSingleCondition(INamedVariable *var,INamedValue *term,bool not) - { - m_var=var; - m_term=term; - m_not=not; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSingleCondition::~CSingleCondition(void) - { - if(CheckPointer(m_var)==POINTER_DYNAMIC) - delete m_var; - if(CheckPointer(m_term)==POINTER_DYNAMIC) - delete m_term; - } -//+------------------------------------------------------------------+ -//| Condition of fuzzy rule for the both Mamdani and Sugeno systems | -//+------------------------------------------------------------------+ -class CFuzzyCondition : public CSingleCondition - { -private: - HedgeType m_hedge; // hedge type - -public: - CFuzzyCondition(CFuzzyVariable *var,CFuzzyTerm *term,bool not); - CFuzzyCondition(CFuzzyVariable *var,CFuzzyTerm *term,bool not,HedgeType hedge); - CFuzzyCondition(CFuzzyVariable *var,CFuzzyTerm *term); - ~CFuzzyCondition(void); - //--- methods gets or sets the hedge type - HedgeType Hedge(void) { return (m_hedge); } - void Hedge(HedgeType value) { m_hedge=value; } - //--- method to check type - virtual bool IsTypeOf(EnCondition type) { return(type==TYPE_CLASS_FuzzyCondition); } - }; -//+------------------------------------------------------------------+ -//| First constructor with parameters | -//+------------------------------------------------------------------+ -CFuzzyCondition::CFuzzyCondition(CFuzzyVariable *var,CFuzzyTerm *term,bool not) - { - CSingleCondition::Var(var); - CSingleCondition::Term(term); - CSingleCondition::Not(not); - m_hedge=None; - } -//+------------------------------------------------------------------+ -//| Second constructor with parameters | -//+------------------------------------------------------------------+ -CFuzzyCondition::CFuzzyCondition(CFuzzyVariable *var,CFuzzyTerm *term,bool not,HedgeType hedge) - { - CSingleCondition::Var(var); - CSingleCondition::Term(term); - CSingleCondition::Not(not); - m_hedge=hedge; - } -//+------------------------------------------------------------------+ -//| Thrid constructor with parameters | -//+------------------------------------------------------------------+ -CFuzzyCondition::CFuzzyCondition(CFuzzyVariable *var,CFuzzyTerm *term) - - { - CSingleCondition::Var(var); - CSingleCondition::Term(term); - CSingleCondition::Not(false); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CFuzzyCondition::~CFuzzyCondition(void) - { - - } -//+------------------------------------------------------------------+ -//| Several CConditions linked by or/and operators | -//+------------------------------------------------------------------+ -class CConditions : public ICondition - { -private: - bool m_not; // Default : false - OperatorType m_op; // Type of operator. Default : And - CList *m_conditions; // List of CConditions - -public: - CConditions(void); - ~CConditions(void); - //--- methods gets or sets the mark "Is MF inverted" - bool Not(void) { return(m_not); } - void Not(bool value) { m_not=value; } - //--- methods gets or sets operator that links expressions (and/or) - OperatorType Op(void) { return (m_op); } - void Op(OperatorType value) { m_op=value; } - //--- method gets the list of CConditions (single or multiples) - CList *ConditionsList(void) { return(m_conditions); } - //--- method to check type - virtual bool IsTypeOf(EnCondition type) { return(type==TYPE_CLASS_Conditions); } - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CConditions::CConditions(void) - { - m_not=false; - m_op = And; - m_conditions=new CList; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CConditions::~CConditions(void) - { - delete m_conditions; - } -//+------------------------------------------------------------------+ -//| Class used by rule parser | -//+------------------------------------------------------------------+ -class IParsableRule : public CObject - { -public: - //--- methods gets or sets the condition (IF) part of the rule - virtual CConditions *Condition(void) { return(NULL); } - virtual void Condition(CConditions *value) { } - //--- methods gets or sets the conclusion (THEN) part of the rule - virtual CSingleCondition *Conclusion(void) { return(NULL); } - virtual void Conclusion(CSingleCondition *value) { } - //--- method to check type - virtual bool IsTypeOf(EnRule type) { return(type==TYPE_CLASS_IParsableRule); } - }; -//+------------------------------------------------------------------+ -//| Implements common functionality of fuzzy rules | -//+------------------------------------------------------------------+ -class CGenericFuzzyRule : public IParsableRule - { -private: - CConditions *m_generic_condition; // Generic path of condition - -public: - CGenericFuzzyRule(void); - ~CGenericFuzzyRule(void); - //--- methods gets or sets the condition (IF) part of the rule - CConditions *Condition(void) { return(m_generic_condition); } - void Condition(CConditions *value) { m_generic_condition=value; } - //--- methods create a single condition - CFuzzyCondition *CreateCondition(CFuzzyVariable *var,CFuzzyTerm *term); - CFuzzyCondition *CreateCondition(CFuzzyVariable *var,CFuzzyTerm *term,bool not); - CFuzzyCondition *CreateCondition(CFuzzyVariable *var,CFuzzyTerm *term,bool not,HedgeType hedge); - //--- methods gets or sets the conclusion (THEN) part of the rule - virtual CSingleCondition *Conclusion(void) { return(NULL); } - virtual void Conclusion(CSingleCondition *value) { } - //--- method to check type - virtual bool IsTypeOf(EnRule type) { return(type==TYPE_CLASS_GenericFuzzyRule); } - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CGenericFuzzyRule::CGenericFuzzyRule(void) - { - m_generic_condition=new CConditions(); - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CGenericFuzzyRule::~CGenericFuzzyRule(void) - { - delete m_generic_condition; - } -//+------------------------------------------------------------------+ -//| Create a single condition(1) | -//+------------------------------------------------------------------+ -CFuzzyCondition *CGenericFuzzyRule::CreateCondition(CFuzzyVariable *var,CFuzzyTerm *term) - { -//--- return fuzzy condition - return new CFuzzyCondition(var, term); - } -//+------------------------------------------------------------------+ -//| Create a single condition(2) | -//+------------------------------------------------------------------+ -CFuzzyCondition *CGenericFuzzyRule::CreateCondition(CFuzzyVariable *var,CFuzzyTerm *term,bool not) - { -//--- return fuzzy condition - return new CFuzzyCondition(var, term, not); - } -//+------------------------------------------------------------------+ -//| Create a single condition(3) | -//+------------------------------------------------------------------+ -CFuzzyCondition *CGenericFuzzyRule::CreateCondition(CFuzzyVariable *var,CFuzzyTerm *term,bool not,HedgeType hedge) - { -//--- return fuzzy condition - return new CFuzzyCondition(var, term, not, hedge); - } -//+------------------------------------------------------------------+ -//| Fuzzy rule for Mamdani fuzzy system. | -//| NOTE: a rule cannot be created directly, only via | -//| MamdaniFuzzySystem::EmptyRule or MamdaniFuzzySystem::ParseRule | -//+------------------------------------------------------------------+ -class CMamdaniFuzzyRule : public CGenericFuzzyRule - { -private: - CSingleCondition *m_mamdani_conclusion; // Mamdani conclusion - double m_weight; // Weight of Mamdani rule - -public: - CMamdaniFuzzyRule(void); - ~CMamdaniFuzzyRule(void); - //--- methods gets or sets the conclusion (THEN) part of the rule - CSingleCondition *Conclusion(void) { return(m_mamdani_conclusion); } - void Conclusion(CSingleCondition *value) { m_mamdani_conclusion=value; } - //--- methods gets or sets the rule weight - double Weight(void) { return(m_weight); } - void Weight(const double value) { m_weight=value; } - //--- method to check type - virtual bool IsTypeOf(EnRule type) { return(type==TYPE_CLASS_MamdaniFuzzyRule); } - }; -//+---------------------------------------------------------------+ -//| Constructor without parameters | -//+---------------------------------------------------------------+ -CMamdaniFuzzyRule::CMamdaniFuzzyRule(void) - { - m_weight=1.0; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMamdaniFuzzyRule::~CMamdaniFuzzyRule(void) - { - if(CheckPointer(m_mamdani_conclusion)==POINTER_DYNAMIC) - delete m_mamdani_conclusion; - } -//+------------------------------------------------------------------+ -//| Fuzzy rule for Sugeno fuzzy system | -//| NOTE: a rule cannot be created directly, only via | -//| SugenoFuzzySystem::EmptyRule or SugenoFuzzySystem::ParseRule | -//+------------------------------------------------------------------+ -class CSugenoFuzzyRule : public CGenericFuzzyRule - { -private: - CSingleCondition *m_sugeno_conclusion; // Sugeno conclusion - -public: - CSugenoFuzzyRule(void); - ~CSugenoFuzzyRule(void); - //--- methods gets or sets the conclusion (THEN) part of the rule - CSingleCondition *Conclusion(void) { return(m_sugeno_conclusion); } - void Conclusion(CSingleCondition *value) { m_sugeno_conclusion=value; } - //--- method to check type - virtual bool IsTypeOf(EnRule type) { return(type==TYPE_CLASS_SugenoFuzzyRule); } - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+-------------------------- ---------------------------------------+ -CSugenoFuzzyRule::CSugenoFuzzyRule(void) - { - - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSugenoFuzzyRule::~CSugenoFuzzyRule(void) - { - if(CheckPointer(m_sugeno_conclusion)==POINTER_DYNAMIC) - delete m_sugeno_conclusion; - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Fuzzy/fuzzyterm.mqh b/Include/Math/Fuzzy/fuzzyterm.mqh deleted file mode 100644 index 9ea5823..0000000 --- a/Include/Math/Fuzzy/fuzzyterm.mqh +++ /dev/null @@ -1,69 +0,0 @@ -//+------------------------------------------------------------------+ -//| fuzzyterm.mqh | -//| 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 "MembershipFunction.mqh" -#include "Helper.mqh" -//+------------------------------------------------------------------+ -//| Purpose: creating fuzzy term. | -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ -//| Fuzzy or linguistic term. | -//+------------------------------------------------------------------+ -class CFuzzyTerm : public CNamedValueImpl - { -private: - IMembershipFunction *m_mf; // The membership function of the term - -public: - CFuzzyTerm(const string name,IMembershipFunction *mf); - ~CFuzzyTerm(void); - //--- method to check type - virtual bool IsTypeOf(EnType type) { return(type==TYPE_CLASS_FuzzyTerm); } - //--- method gets the membership function initially associated with the term - IMembershipFunction *MembershipFunction() { return(m_mf); } - }; -//+------------------------------------------------------------------+ -//| Constructor with parameters | -//+------------------------------------------------------------------+ -CFuzzyTerm::CFuzzyTerm(const string name,IMembershipFunction *mf) - { - CNamedValueImpl::Name(name); - m_mf=mf; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CFuzzyTerm::~CFuzzyTerm(void) - { - if(CheckPointer(m_mf)==POINTER_DYNAMIC) - { - delete m_mf; - } - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Fuzzy/fuzzyvariable.mqh b/Include/Math/Fuzzy/fuzzyvariable.mqh deleted file mode 100644 index ab5ce97..0000000 --- a/Include/Math/Fuzzy/fuzzyvariable.mqh +++ /dev/null @@ -1,113 +0,0 @@ -//+------------------------------------------------------------------+ -//| fuzzyvariable.mqh | -//| 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 "FuzzyTerm.mqh" -//+------------------------------------------------------------------+ -//| Purpose: creating fuzzy variable | -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ -//| Fuzzy or linguistic variable. | -//+------------------------------------------------------------------+ -class CFuzzyVariable : public CNamedVariableImpl - { -private: - double m_min; // Minimum value of the variable - double m_max; // Maximum value of the variable - CList *m_terms; // List of terms in a variable - -public : - CFuzzyVariable(const string name,const double min,const double max); - ~CFuzzyVariable(void); - //--- method to check type - virtual bool IsTypeOf(EnType type) { return(type==TYPE_CLASS_FuzzyVariable); } - //--- methods gets or sets parameters of varriable - void Max(const double max) { m_max=max; } - double Max(void) { return (m_max); } - void Min(const double min) { m_min=min; } - double Min(void) { return (m_min); } - //--- methods gets or sets the terms - CList *Terms() { return(m_terms); } - void Terms(CList *terms) { m_terms=terms; } - //--- add fuzzy term - void AddTerm(CFuzzyTerm *term); - //--- get membership function by name - CFuzzyTerm *GetTermByName(const string name); - //--- overload - CList *Values() { return(m_terms); } - }; -//+------------------------------------------------------------------+ -//| Constructor with parameters | -//+------------------------------------------------------------------+ -CFuzzyVariable::CFuzzyVariable(const string name,const double min,const double max) - { - CNamedVariableImpl::Name(name); - m_terms=new CList(); - if(min>max) - { - Print("Incorrect parameters! Maximum value must be greater than minimum one."); - } - else - { - m_min = min; - m_max = max; - } - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CFuzzyVariable::~CFuzzyVariable(void) - { - delete m_terms; - } -//+------------------------------------------------------------------+ -//| Add fuzzy term to list terms in a variable | -//+------------------------------------------------------------------+ -void CFuzzyVariable::AddTerm(CFuzzyTerm *term) - { - m_terms.Add(term); - } -//+------------------------------------------------------------------+ -//| Get membership function (term) by name | -//+------------------------------------------------------------------+ -CFuzzyTerm *CFuzzyVariable::GetTermByName(const string name) - { - for(int i=0; i -#include -#include "FuzzyRule.mqh" -#include "InferenceMethod.mqh" -#include "Dictionary.mqh" -//+------------------------------------------------------------------+ -//| Purpose: Creating generic fuzzy system | -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ -//| Common functionality of Mamdani and Sugeno fuzzy systems | -//+------------------------------------------------------------------+ -class CGenericFuzzySystem - { -private: - CList *m_input; // List of input fuzzy variables - AndMethod m_and_method; // And method from InferenceMethod - OrMethod m_or_method; // Or method from InferenceMethod - -protected: - CGenericFuzzySystem(void); - ~CGenericFuzzySystem(void); -public: - //--- method gets the input linguistic variables - CList *Input(void) { return(m_input); } - //--- method gets or sets the type of "And method" - void AndMethod(AndMethod value) { m_and_method=value; } - AndMethod AndMethod(void) { return (m_and_method); } - //--- method gets or sets the type of "Or method" - void OrMethod(OrMethod value) { m_or_method=value; } - OrMethod OrMethod(void) { return (m_or_method); } - //--- method gets the varriable by name - CFuzzyVariable *InputByName(const string name); - //--- common steps of calculating - CList *Fuzzify(CList *inputValues); -protected: - double EvaluateCondition(ICondition *condition,CList *fuzzifiedInput); - double EvaluateConditionPair(const double cond1,const double cond2,OperatorType op); -private: - bool ValidateInputValues(CList *inputValues,string &msg); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CGenericFuzzySystem::CGenericFuzzySystem(void) - { - m_input=new CList; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CGenericFuzzySystem::~CGenericFuzzySystem(void) - { - if(CheckPointer(m_input)==POINTER_DYNAMIC) - { - delete m_input; - } - } -//+------------------------------------------------------------------+ -//| Get input linguistic variable by its name | -//+------------------------------------------------------------------+ -CFuzzyVariable *CGenericFuzzySystem::InputByName(const string name) - { - CList *result=CGenericFuzzySystem::Input(); - for(int i=0; ivar.Max()) - { - msg=StringFormat("Value for the %s variable is out of range.",var.Name()); - //--- return false - return (false); - } - } - } - if(contain==false) - { - msg=StringFormat("Value for the %s variable does not present.",var.Name()); - //--- return false - return (false); - } - } -//--- return true - return (true); - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Fuzzy/helper.mqh b/Include/Math/Fuzzy/helper.mqh deleted file mode 100644 index 9530145..0000000 --- a/Include/Math/Fuzzy/helper.mqh +++ /dev/null @@ -1,158 +0,0 @@ -//+------------------------------------------------------------------+ -//| helper.mqh | -//| 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 "InferenceMethod.mqh" -//+------------------------------------------------------------------+ -//| Purpose: Analysis of the fuzzy rules | -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ -//| This class must be implemented by values in parsable rules | -//+------------------------------------------------------------------+ -class INamedValue : public CObject - { -public: - //--- method to check type - virtual bool IsTypeOf(EnType type) { return(type==TYPE_CLASS_INamedValue); } - //--- methods gets or sets the name - virtual string Name(void) { return(""); } - virtual void Name(const string name) { } - }; -//+------------------------------------------------------------------+ -//| This class must be implemented by values in parsable rules | -//+------------------------------------------------------------------+ -class INamedVariable : public INamedValue - { -public: - //--- method to check type - virtual bool IsTypeOf(EnType type) { return(type==TYPE_CLASS_INamedValue); } - //--- get list of values that belongs to the variable - virtual CList *Values(void) { return(NULL); } - }; -//+------------------------------------------------------------------+ -//| Named variable | -//+------------------------------------------------------------------+ -class CNamedVariableImpl : public INamedVariable - { -private: - string m_name; // Name of the variable - -public: - //--- method to check type - virtual bool IsTypeOf(EnType type) { return(type==TYPE_CLASS_NamedVariableImpl); } - //--- methods gets or sets varriable name - virtual void Name(const string name); - virtual string Name(void) { return(m_name); } - //--- get list of values that belongs to the variable - virtual CList *Values(void) { return(NULL); } - }; -//+------------------------------------------------------------------+ -//| Set variable name | -//+------------------------------------------------------------------+ -void CNamedVariableImpl::Name(const string name) - { - if(!CNameHelper::IsValidName(name)) - { - Print("Invalid variable name."); - } - m_name=name; - } -//+------------------------------------------------------------------+ -//| Named value of variable | -//+------------------------------------------------------------------+ -class CNamedValueImpl : public INamedValue - { -private: - string m_name; // Name of the value - -public: - //--- method to check type - virtual bool IsTypeOf(EnType type) { return(type==TYPE_CLASS_NamedVariableImpl); } - //--- methods gets or sets varriable name - virtual void Name(const string name); - virtual string Name(void) { return(m_name); } - }; -//+------------------------------------------------------------------+ -//| Set variable name | -//+------------------------------------------------------------------+ -void CNamedValueImpl::Name(const string name) - { - if(!CNameHelper::IsValidName(name)) - { - Print("Invalid term name."); - } - m_name=name; - } -//+------------------------------------------------------------------+ -//| Keywords: | -//+------------------------------------------------------------------+ -static string KEYWORDS[]={ "if","then","is","and","or","not","(",")","slightly","somewhat","very","extremely" }; // Keywords in rules -//+------------------------------------------------------------------+ -//| Class NameHelper checks the availability of names | -//+------------------------------------------------------------------+ -class CNameHelper - { -public: - //+------------------------------------------------------------------+ - //| Check the name of variable/term | - //+------------------------------------------------------------------+ - static bool IsValidName(const string name) - { - //--- Empty names are not allowed - if(StringLen(name)==0) - { - //--- return false - return (false); - } - - for(int i=0; i=48 && s<=57) // Not numbers and symbol '_' - && !( s >= 65 && s <= 90 ) // Not capital letters - && !( s >= 97 && s <= 122 )) // Not letters - { - //--- return false - return (false); - } - } - //--- Identifier cannot be a keword - for(int i=0; i -//+------------------------------------------------------------------+ -//| Purpose: Contains a number of enumerations, | -//| for the convenience of working with other files | -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ -//| And evaluating method | -//+------------------------------------------------------------------+ -enum AndMethod - { - MinAnd, // Minimum: min(a, b) - ProductionAnd // Production: a * b - }; -//+------------------------------------------------------------------+ -//| Or evaluating method | -//+------------------------------------------------------------------+ -enum OrMethod - { - MaxOr, // Maximum: max(a, b) - ProbabilisticOr // Probabilistic OR: a + b - a * b - }; -//+------------------------------------------------------------------+ -//| Fuzzy implication method | -//+------------------------------------------------------------------+ -enum ImplicationMethod - { - MinIpm, // Truncation of output fuzzy set - ProductionImp // Scaling of output fuzzy set - }; -//+------------------------------------------------------------------+ -//| Aggregation method for membership functions | -//+------------------------------------------------------------------+ -enum AggregationMethod - { - MaxAgg, // Maximum of rule outpus - SumAgg // Sum of rule output - }; -//+------------------------------------------------------------------+ -//| Defuzzification method | -//+------------------------------------------------------------------+ -enum DefuzzificationMethod - { - CentroidDef, // Center of area of fuzzy result MF - BisectorDef, // The point divides the area under the MF into two equal - AverageMaximumDef, // Arithmetic mean of all the maxima of the MF - LargestMaximumDef, // The largest of the maxima of the membership function - SmallestMaximumDef // The smallest of the maxima of the membership function - }; -//+------------------------------------------------------------------+ -//| Type of varriable and term | -//+------------------------------------------------------------------+ -enum EnType - { - TYPE_CLASS_INamedValue, // Base class - TYPE_CLASS_INamedVariable, // INamedVariable : INamedValue - TYPE_CLASS_NamedVariableImpl, // NamedVariableImpl : INamedVariable - TYPE_CLASS_NamedValueImpl, // NamedValueImpl : INamedValue - TYPE_CLASS_FuzzyTerm, // FuzzyTerm : NamedValueImpl - TYPE_CLASS_FuzzyVariable, // FuzzyVariable : NamedVariableImpl - TYPE_CLASS_SugenoVariable, // SugenoVariable : NamedVariableImpl - TYPE_CLASS_ISugenoFunction, // ISugenoFunction : NamedValueImpl - TYPE_CLASS_LinearSugenoFunction // LinearSugenoFunction : ISugenoFunction - }; -//+------------------------------------------------------------------+ -//| Type of expression | -//+------------------------------------------------------------------+ -enum EnLexem - { - TYPE_CLASS_IExpression, // Base class - TYPE_CLASS_Lexem, // Lexem : IExpression - TYPE_CLASS_ConditionExpression, // ConditionExpression : IExpression - TYPE_CLASS_VarLexem, // VarLexem : Lexem - TYPE_CLASS_KeywordLexem, // KeywordLexem : Lexem - TYPE_CLASS_AltLexem, // AltLexem : Lexem - TYPE_CLASS_TermLexem // TermLexem : AltLexem - }; -//+------------------------------------------------------------------+ -//| Type of condition | -//+------------------------------------------------------------------+ -enum EnCondition - { - TYPE_CLASS_ICondition, // Base class - TYPE_CLASS_Conditions, // Conditions : ICondition - TYPE_CLASS_SingleCondition, // SingleCondition : ICondition - TYPE_CLASS_FuzzyCondition // FuzzyCondition : SingleCondition - }; -//+------------------------------------------------------------------+ -//| Type of rule | -//+------------------------------------------------------------------+ -enum EnRule - { - TYPE_CLASS_IParsableRule, // Base class - TYPE_CLASS_GenericFuzzyRule, // GenericFuzzyRule : IParsableRule - TYPE_CLASS_MamdaniFuzzyRule, // MamdaniFuzzyRule : GenericFuzzyRule - TYPE_CLASS_SugenoFuzzyRule // SugenoFuzzyRule : GenericFuzzyRule - }; -//+------------------------------------------------------------------+ diff --git a/Include/Math/Fuzzy/mamdanifuzzysystem.mqh b/Include/Math/Fuzzy/mamdanifuzzysystem.mqh deleted file mode 100644 index 26eb2bc..0000000 --- a/Include/Math/Fuzzy/mamdanifuzzysystem.mqh +++ /dev/null @@ -1,552 +0,0 @@ -//+------------------------------------------------------------------+ -//| mandanifuzzysystem.mqh | -//| 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 -#include "GenericFuzzySystem.mqh" -#include "InferenceMethod.mqh" -#include "RuleParser.mqh" -#include "FuzzyRule.mqh" -//+------------------------------------------------------------------+ -//| Purpose: Creating Mamdani fuzzy system | -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ -//| Mamdani fuzzy inference system | -//+------------------------------------------------------------------+ -class CMamdaniFuzzySystem : public CGenericFuzzySystem - { -private: - CList *m_output; // List of fuzzy variable - CList *m_rules; // List of Mamdani fuzzy rule - ImplicationMethod m_impl_method; // Implication method - AggregationMethod m_aggr_method; // Aggregation method - DefuzzificationMethod m_defuzz_method; // Defuzzification method - -public: - CMamdaniFuzzySystem(void); - ~CMamdaniFuzzySystem(void); - //--- method gets the output linguistic variables - CList *Output() { return(m_output); } - //--- method gets the fuzzy rule - CList *Rules() { return(m_rules); } - //--- methods gets or sets the implication method - ImplicationMethod ImplicationMethod() { return (m_impl_method); } - void ImplicationMethod(ImplicationMethod value) { m_impl_method=value; } - //--- methods gets or sets the aggregation method - AggregationMethod AggregationMethod() { return (m_aggr_method); } - void AggregationMethod(AggregationMethod value) { m_aggr_method=value; } - //--- methods gets or sets the defuzzification method - DefuzzificationMethod DefuzzificationMethod() { return (m_defuzz_method); } - void DefuzzificationMethod(DefuzzificationMethod value) { m_defuzz_method=value; } - //--- maethod gets the variable by name - CFuzzyVariable *OutputByName(const string name); - //--- create a new rule - CMamdaniFuzzyRule *EmptyRule(); - //--- parse rule - CMamdaniFuzzyRule *ParseRule(const string rule); - //--- method for calculate result - CList *Calculate(CList *inputValues); - CList *EvaluateConditions(CList *fuzzifiedInput); - CList *Implicate(CList *conditions); - CList *Aggregate(CList *conclusions); - CList *Defuzzify(CList *fuzzyResult); - double Defuzzify(IMembershipFunction *mf,const double min,const double max); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CMamdaniFuzzySystem::CMamdaniFuzzySystem(void) - { - m_output= new CList; - m_rules = new CList; - m_impl_method = MinIpm; // Implication method default is Min - m_aggr_method =MaxAgg; // Aggregation method default is Max - m_defuzz_method = CentroidDef; // Defuzzification method default is Centroid - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CMamdaniFuzzySystem::~CMamdaniFuzzySystem(void) - { - delete m_output; - delete m_rules; - } -//+------------------------------------------------------------------+ -//| Get output linguistic variable by its name | -//+------------------------------------------------------------------+ -CFuzzyVariable *CMamdaniFuzzySystem::OutputByName(const string name) - { - for(int i=0; i=halfArea) - { - break; - } - now=now+(max-min)/k; - } - delete mf; - //--- return result - return (now); - } - else if(m_defuzz_method==AverageMaximumDef) - { - //+------------------------------------------------------------------------------------------+ - //| AverageMaximum method is the arithmetic mean of all the maxima of the membership function| - //+------------------------------------------------------------------------------------------+ - double sum_max=0; // Sum of local maxima - double count_max=0; // Count of local maxima - int k=50; // The function is divided into "k" steps - double now=min; // The current position - double step=(max-min)/k; // Calculate the step function - for(int i=1; imf.GetValue(min+step)) - { - sum_max+=mf.GetValue(min); - count_max++; - } - } - //--- check the second element - if(i==k-1) - { - if(mf.GetValue(max)>mf.GetValue(max-step)) - { - sum_max+=mf.GetValue(max); - count_max++; - } - } - //--- check all the other elements - if((point_1>point_0) && (point_1>point_2)) - { - sum_max+=point_1; - count_max++; - } - } - if(count_max==0) - { - delete mf; - //--- return result - return (0); - } - else - { - delete mf; - //--- return result - return (sum_max/count_max); - } - } - else if(m_defuzz_method==LargestMaximumDef) - { - CArrayDouble *local_max=new CArrayDouble; // Array of all local maximum - double result; // Result of defuzzification method - int k=50; // The function is divided into "k" steps - double now=min; // The current position - double step=(max-min)/k; // Calculate the step function - for(int i=1; imf.GetValue(min+step)) - { - local_max.Add(mf.GetValue(min)); - } - } - //--- check the second element - if(i==k-1) - { - if(mf.GetValue(max)>mf.GetValue(max-step)) - { - local_max.Add(mf.GetValue(max)); - } - } - //--- check all the other elements - if((point_1>point_0) && (point_1>point_2)) - { - local_max.Add(point_1); - } - now+=step; - } - result=local_max.At(0); - for(int i=0; imf.GetValue(min+step)) - { - local_max.Add(mf.GetValue(min)); - } - } - //--- check the second element - if(i==k-1) - { - if(mf.GetValue(max)>mf.GetValue(max-step)) - { - local_max.Add(mf.GetValue(max)); - } - } - //--- check all the other elements - if((point_1>point_0) && (point_1>point_2)) - { - local_max.Add(point_1); - } - now+=step; - } - result=local_max.At(0); - for(int i=0; i=local_max.At(i)) - { - result=local_max.At(i); - } - } - now=min; - while(true) - { - if(mf.GetValue(now)==result) - { - break; - } - now+=step; - } - delete local_max; - delete mf; - //--- return result - return (now); - } - else - { - Print("Internal exception."); - delete mf; - //--- return - return (0); - } - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Fuzzy/membershipfunction.mqh b/Include/Math/Fuzzy/membershipfunction.mqh deleted file mode 100644 index cd77783..0000000 --- a/Include/Math/Fuzzy/membershipfunction.mqh +++ /dev/null @@ -1,1008 +0,0 @@ -//+------------------------------------------------------------------+ -//| membershipfunction.mqh | -//| 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 -//+------------------------------------------------------------------+ -//| Purpose: creating membership functions. | -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ -//| Types of membership functions composition | -//+------------------------------------------------------------------+ -enum MfCompositionType - { - MinMF, // Minumum of functions - MaxMF, // Maximum of functions - ProdMF, // Production of functions - SumMF // Sum of functions - }; -//+------------------------------------------------------------------+ -//| The base class of all classes of membership functions | -//+------------------------------------------------------------------+ -class IMembershipFunction : public CObject - { -public: - //--- method evaluate value of the membership function - virtual double GetValue(const double x)=NULL; - }; -//+------------------------------------------------------------------+ -//| Gaussian combination membership function | -//+------------------------------------------------------------------+ -class CNormalCombinationMembershipFunction : public IMembershipFunction - { -private: - double m_b1; // Parametr b1: coordinate of the minimum membership function - double m_sigma1; // Parametr sigma1: concentration factor of the left path of function - double m_b2; // Parametr b2: coordinate of the maximum membership function - double m_sigma2; // Parametr sigma2: concentration factor of the rigth path of function - -public: - CNormalCombinationMembershipFunction(void); - CNormalCombinationMembershipFunction(const double b1,const double sigma1,const double b2,const double sigma2); - ~CNormalCombinationMembershipFunction(void); - //--- methods gets or sets the parametrs - void B1(const double b1) { m_b1=b1; } - double B1(void) { return(m_b1); } - void Sigma1(const double sigma1) { m_sigma1=sigma1; } - double Sigma1(void) { return(m_sigma1); } - void B2(const double b2) { m_b2=b2; } - double B2(void) { return(m_b2); } - void Sigma2(const double sigma2) { m_sigma2=sigma2; } - double Sigma2(void) { return(m_sigma2); } - //--- method gets the argument (x axis value) - double GetValue(const double x); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CNormalCombinationMembershipFunction::CNormalCombinationMembershipFunction(void) - { - - } -//+------------------------------------------------------------------+ -//| Constructor with parameters | -//+------------------------------------------------------------------+ -CNormalCombinationMembershipFunction::CNormalCombinationMembershipFunction(const double b1,const double sigma1,const double b2,const double sigma2) - { - m_b1=b1; - m_sigma1=sigma1; - m_b2=b2; - m_sigma2=sigma2; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CNormalCombinationMembershipFunction::~CNormalCombinationMembershipFunction(void) - { - - } -//+------------------------------------------------------------------+ -//| Get argument (x axis value) | -//+------------------------------------------------------------------+ -double CNormalCombinationMembershipFunction::GetValue(const double x) - { - if(m_b1<=m_b2) - { - if(xm_b2) - { - //--- return result - return (exp((x - m_b2) * (x - m_b2) / ( -2.0 * m_sigma2 * m_sigma2))); - } - else - { - //--- m_b1 <= x && x <= m_b2 - //--- return result - return (1); - } - } - if(m_b1>m_b2) - { - if(xm_b1) - { - //--- return result - return (exp((x - m_b2) * (x - m_b2) / ( -2.0 * m_sigma2 * m_sigma2))); - } - else - { - //--- m_b1 <= x && x <= m_b2 - //--- return result - return ( exp((x - m_b1) * (x - m_b1) / ( -2.0 * m_sigma1 * m_sigma1)) * exp((x - m_b2) * (x - m_b2) / ( -2.0 * m_sigma2 * m_sigma2)) ); - } - } -//--- m_b1 == m_b2 -//--- return result - return (m_b1); - } -//+------------------------------------------------------------------+ -//| Generalized bell-shaped membership function | -//+------------------------------------------------------------------+ -class CGeneralizedBellShapedMembershipFunction : public IMembershipFunction - { -private: - double m_a; // Parametr a: the concentration factor of the membership function - double m_b; // Parametr b: coefficients slope of the membership function - double m_c; // Parametr c: the maximum coordinate of the membership function - -public: - CGeneralizedBellShapedMembershipFunction(void); - CGeneralizedBellShapedMembershipFunction(const double a,const double b,const double c); - ~CGeneralizedBellShapedMembershipFunction(void); - //--- methods gets or sets the parametrs - void A(const double a) { m_a=a; } - double A(void) { return(m_a); } - void B(const double b) { m_b=b; } - double B(void) { return(m_b); } - void C(const double c) { m_c=c; } - double C(void) { return(m_c); } - //--- method gets the argument (x axis value) - double GetValue(const double x); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CGeneralizedBellShapedMembershipFunction::CGeneralizedBellShapedMembershipFunction(void) - { - - } -//+------------------------------------------------------------------+ -//| Constructor with parameters | -//+------------------------------------------------------------------+ -CGeneralizedBellShapedMembershipFunction::CGeneralizedBellShapedMembershipFunction(const double a,const double b,const double c) - { - m_a=a; - m_b=b; - m_c=c; - } -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -CGeneralizedBellShapedMembershipFunction::~CGeneralizedBellShapedMembershipFunction(void) - { - - } -//+------------------------------------------------------------------+ -//| Get argument (x axis value) | -//+------------------------------------------------------------------+ -double CGeneralizedBellShapedMembershipFunction::GetValue(const double x) - { -//--- return result - return (1 / (1 + pow( fabs((x - m_a) / m_c) , 2 * m_b ))); - } -//+------------------------------------------------------------------+ -//| S-shaped membership function | -//+------------------------------------------------------------------+ -class CS_ShapedMembershipFunction : public IMembershipFunction - { -private: - double m_a; // Parametr a: beginning of the interval increases - double m_b; // Parametr b: end of the interval increases - -public: - CS_ShapedMembershipFunction(void); - CS_ShapedMembershipFunction(const double a,const double b); - ~CS_ShapedMembershipFunction(void); - //--- methods gets or sets the parametrs - void A(const double a) { m_a=a; } - double A(void) { return(m_a); } - void B(const double b) { m_b=b; } - double B(void) { return(m_b); } - //--- method gets the argument (x axis value) - double GetValue(const double x); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CS_ShapedMembershipFunction::CS_ShapedMembershipFunction(void) - { - - } -//+------------------------------------------------------------------+ -//| Constructor with parameters | -//+------------------------------------------------------------------+ -CS_ShapedMembershipFunction::CS_ShapedMembershipFunction(const double a,const double b) - { - m_a=a; - m_b=b; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CS_ShapedMembershipFunction::~CS_ShapedMembershipFunction(void) - { - - } -//+------------------------------------------------------------------+ -//| Get argument (x axis value) | -//+------------------------------------------------------------------+ -double CS_ShapedMembershipFunction::GetValue(const double x) - { - if(x<=m_a) - { - //--- return result - return (0.0); - } - else if(m_a= m_b - //--- return result - return (1.0); - } - } -//+------------------------------------------------------------------+ -//| Z-shaped membership function | -//+------------------------------------------------------------------+ -class CZ_ShapedMembershipFunction : public IMembershipFunction - { -private: - double m_a; // Parametr a: beginning of the interval decreasing - double m_b; // Parametr b: end of the interval decreasing - -public: - CZ_ShapedMembershipFunction(void); - CZ_ShapedMembershipFunction(const double a,const double b); - ~CZ_ShapedMembershipFunction(void); - //--- methods gets or sets the parametrs - void A(const double a) { m_a=a; } - double A(void) { return(m_a); } - void B(const double b) { m_b=b; } - double B(void) { return(m_b); } - //--- method gets the argument (x axis value) - double GetValue(const double x); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CZ_ShapedMembershipFunction::CZ_ShapedMembershipFunction(void) - { - - } -//+------------------------------------------------------------------+ -//| Constructor with parameters | -//+------------------------------------------------------------------+ -CZ_ShapedMembershipFunction::CZ_ShapedMembershipFunction(const double a,const double b) - { - m_a=a; - m_b=b; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CZ_ShapedMembershipFunction::~CZ_ShapedMembershipFunction(void) - { - - } -//+------------------------------------------------------------------+ -//| Get argument (x axis value) | -//+------------------------------------------------------------------+ -double CZ_ShapedMembershipFunction::GetValue(const double x) - { - if(x<=m_a) - { - //--- return result - return (1.0); - } - else if(m_a= m_b - //--- return result - return (0.0); - } - } -//+------------------------------------------------------------------+ -//| P-shaped membership function | -//+------------------------------------------------------------------+ -class CP_ShapedMembershipFunction : public IMembershipFunction - { -private: - double m_a; // Parametr a: carrier fuzzy set - double m_d; // Parametr d: carrier fuzzy set - double m_b; // Parametr b: the core of a fuzzy set - double m_c; // Parametr c: the core of a fuzzy set - -public: - CP_ShapedMembershipFunction(void); - CP_ShapedMembershipFunction(const double a,const double b,const double c,const double d); - ~CP_ShapedMembershipFunction(void); - //--- methods gets or sets the parametrs - void A(const double a) { m_a=a; } - double A(void) { return(m_a); } - void D(const double d) { m_d=d; } - double D(void) { return(m_d); } - void B(const double b) { m_b=b; } - double B(void) { return(m_b); } - void C(const double c) { m_c=c; } - double C(void) { return(m_c); } - //--- method gets the argument (x axis value) - double GetValue(const double x); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CP_ShapedMembershipFunction::CP_ShapedMembershipFunction(void) - { - - } -//+------------------------------------------------------------------+ -//| Constructor with parameters | -//+------------------------------------------------------------------+ -CP_ShapedMembershipFunction::CP_ShapedMembershipFunction(const double a,const double b,const double c,const double d) - { - m_a=a; - m_d=d; - m_b=b; - m_c=c; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CP_ShapedMembershipFunction::~CP_ShapedMembershipFunction(void) - { - - } -//+------------------------------------------------------------------+ -//| Get argument (x axis value) | -//+------------------------------------------------------------------+ -double CP_ShapedMembershipFunction::GetValue(const double x) - { - if(x<=m_a) - { - return(0.0); - } - else - if(m_a=m_x4) - { - result=0; - } - else if((x>=m_x2) && (x<=m_x3)) - { - result=1; - } - else if((x>m_x1) && (x=m_x3) - { - result=0; - } - else if(x==m_x2) - { - result=1; - } - else if((x>m_x1) && (x1.0) - { - Print("Incorrect parameter! It is necessary to re-initialize them."); - } - m_constValue=constValue; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CConstantMembershipFunction::~CConstantMembershipFunction(void) - { - - } -//+--------------------------------------------------------------------------------------+ -//| Composition of several membership functions represened as single membership function | -//+--------------------------------------------------------------------------------------+ -class CCompositeMembershipFunction : public IMembershipFunction - { -private: - CList *m_mfs; // List of membership functions - MfCompositionType m_composType; // Composite Type - -public: - CCompositeMembershipFunction(MfCompositionType composType); - CCompositeMembershipFunction(MfCompositionType composType,IMembershipFunction *mf1,IMembershipFunction *mf2); - CCompositeMembershipFunction(MfCompositionType composType,CList *mfs); - ~CCompositeMembershipFunction(void); - //--- methods gets or sets the parametrs - CList *MembershipFunctions(void) { return(m_mfs); } - MfCompositionType CompositionType(void) { return(m_composType); } - void CompositionType(MfCompositionType value) { m_composType=value; } - //--- method gets the argument (x axis value) - - //+------------------------------------------------------------------+ - //| Get argument (x axis value) | - //+------------------------------------------------------------------+ - double GetValue(double const x); -private: - //--- composition of the membership functions - double Compose(const double val1,const double val2); - }; -//+------------------------------------------------------------------+ -//| First constructor with parameters | -//+------------------------------------------------------------------+ -CCompositeMembershipFunction::CCompositeMembershipFunction(MfCompositionType composType) - { - m_mfs=new CList; - m_composType=composType; - } -//+------------------------------------------------------------------+ -//| Second constructor with parameters | -//+------------------------------------------------------------------+ -CCompositeMembershipFunction::CCompositeMembershipFunction(MfCompositionType composType,IMembershipFunction *mf1,IMembershipFunction *mf2) - { - m_mfs=new CList; - m_mfs.Add(mf1); - m_mfs.Add(mf2); - m_composType=composType; - } -//+------------------------------------------------------------------+ -//| Third constructor with parameters | -//+------------------------------------------------------------------+ -CCompositeMembershipFunction::CCompositeMembershipFunction(MfCompositionType composType,CList *mfs) - { - m_mfs=mfs; - m_composType=composType; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CCompositeMembershipFunction::~CCompositeMembershipFunction() - { - m_mfs.FreeMode(false); - delete m_mfs; - } -//+------------------------------------------------------------------+ -//| Get argument (x axis value) | -//+------------------------------------------------------------------+ -double CCompositeMembershipFunction::GetValue(double const x) - { - if(m_mfs.Total()==0) - { - //--- return result - return 0.0; - } - else if(m_mfs.Total()==1) - { - IMembershipFunction *fun=m_mfs.GetNodeAtIndex(0); - //--- return result - return fun.GetValue(x); - } - else - { - IMembershipFunction *fun=m_mfs.GetNodeAtIndex(0); - double result=fun.GetValue(x); - for(int i=1; i -#include -#include "Dictionary.mqh" -#include "FuzzyRule.mqh" -#include "Helper.mqh" -#include "InferenceMethod.mqh" -#include "SugenoVariable.mqh" -//+------------------------------------------------------------------+ -//| Purpose: Analysis of the fuzzy rules | -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ -//| Base class for all expression | -//+------------------------------------------------------------------+ -class IExpression : public CObject - { -public: - //--- method gets the text of expression - virtual string Text(void)=NULL; - //--- method to check type - virtual bool IsTypeOf(EnLexem type) { return(type==TYPE_CLASS_IExpression); } - }; -//+------------------------------------------------------------------+ -//| Class for creating lexem | -//+------------------------------------------------------------------+ -class CLexem : public IExpression - { -public: - //--- method gets the text of expression - virtual string Text(void)=NULL; - //--- method to check type - virtual bool IsTypeOf(EnLexem type) { return(type==TYPE_CLASS_Lexem); } - }; -//+------------------------------------------------------------------+ -//| Class condition expression | -//+------------------------------------------------------------------+ -class CConditionExpression : public IExpression - { -private: - CArrayObj *m_expressions; // List of expression - CFuzzyCondition *m_condition; // Fuzzy condition - -public: - CConditionExpression(CArrayObj *expressions,CFuzzyCondition *condition); - ~CConditionExpression(void); - //--- methods gets or sets array of expression - CArrayObj *Expressions(void) { return (m_expressions); } - void Expressions(CArrayObj *value) { m_expressions=value; } - //--- methods gets or sets fuzzy condition - CFuzzyCondition *Condition(void) { return m_condition; } - void Condition(CFuzzyCondition *value) { m_condition=value; } - //--- method gets the text of expressions - string Text(void); - //--- method to check type - virtual bool IsTypeOf(EnLexem type) { return(type==TYPE_CLASS_ConditionExpression); } - }; -//+------------------------------------------------------------------+ -//| Constructor with parameters | -//+------------------------------------------------------------------+ -CConditionExpression::CConditionExpression(CArrayObj *expressions,CFuzzyCondition *condition) - { - m_expressions=expressions; - m_condition=condition; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CConditionExpression::~CConditionExpression(void) - { - - } -//+------------------------------------------------------------------+ -//| Convert all expressions to text(string) | -//+------------------------------------------------------------------+ -string CConditionExpression::Text(void) - { - string sb; - for(int i=0; i0 && StringGetCharacter(sb,StringLen(sb)-1)==' ') - { - //--- Do not duplicate spaces - } - else - { - sb+=CharToString(' '); - } - sb+=CharToString(ch); - sb+=CharToString(' '); - } - else - { - if(ch==' ' && StringLen(sb)>0 && StringGetCharacter(sb,StringLen(sb)-1)==' ') - { - // Do not duplicate spaces - } - else - { - sb+=CharToString(ch); - } - } - } -//--- Remove spaces -//+------------------------------------------------------------------+ -//| Use conditional compilation to determine | -//| the type of program MQL4 or MQL5 because they have | -//| different realization of StringTrimRight() and StringTrimLeft() | -//+------------------------------------------------------------------+ -#ifdef __MQL5__ - StringTrimRight(sb); - StringTrimLeft(sb); -#else -#ifdef __MQL4__ - sb=StringTrimRight(sb); - sb=StringTrimLeft(sb); -#endif -#endif - string prepRule=sb; -//--- Build lexems dictionary - CList *lexemsDict=BuildLexemsList(in,out); -//--- At first we parse lexems - CArrayObj *expressions=ParseLexems(prepRule,lexemsDict); - if(expressions.Total()==0) - { - Print("No valid identifiers found."); - //--- return - return (NULL); - } -//--- Find condition & conclusion parts part - CDictionary_String_Obj *p_so; - for(int i=0; i0) - { - IExpression *expr0=copyExpressions.At(index); - if(expr0.IsTypeOf(TYPE_CLASS_VarLexem)) - { - //--- Parse variable - CVarLexem *varLexem=copyExpressions.At(index); - if(copyExpressions.Total()<3) - { - Print(StringFormat("Condition strated with '%s' is incorrect.",varLexem.Text())); - //--- return - return(NULL); - } - if(varLexem.Input()==false) - { - Print("The variable in condition part must be an input variable."); - //--- return - return(NULL); - } - //--- Parse 'is' lexem - CLexem *exprIs=copyExpressions.At(index+1); - CDictionary_String_Obj *p_so; - for(int i=0;i0) - { - ICondition *cond=NULL; - for(int i=0; i0) - { - if((copyExpressions.At(index)==p_so_and.Value() && p_so_and.Key()=="and") || (copyExpressions.At(index)==p_so_or.Value() && p_so_or.Key()=="or")) - { - if(copyExpressions.Total()-index<2) - { - condExp=copyExpressions.At(index); - Print(StringFormat("Error at %s in condition part.",condExp.Text())); - //--- return - return (NULL); - } - //--- Set and/or for conditions list - OperatorType newOp=NULL; - if(copyExpressions.At(index)==p_so_and.Value() && p_so_and.Key()=="and") - { - newOp=And; - } - if(copyExpressions.At(index)==p_so_or.Value() && p_so_or.Key()=="or") - { - newOp=Or; - } - if(setOrAnd) - { - if(conds.Op()!=newOp) - { - Print("At the one nesting level cannot be mixed and/or operations."); - //--- return - return (NULL); - } - } - else - { - conds.Op(newOp); - setOrAnd=true; - } - index=index+1; - } - else - { - string str; - condExp=copyExpressions.At(index); - str=condExp.Text(); - condExp=copyExpressions.At(index+1); - Print(StringFormat("%s cannot goes after %s",str,condExp.Text())); - //--- return - return (NULL); - } - } - } - //--- return conditions - return (conds); - } - } -//+------------------------------------------------------------------+ -//| Parse conclusion | -//+------------------------------------------------------------------+ -static CSingleCondition *CRuleParser::ParseConclusion(CArrayObj *conditionExpression,CList *out,CList *lexems) - { - CArrayObj *copyExpression=conditionExpression; -//--- Remove extra brackets - CDictionary_String_Obj *p_so; - CDictionary_String_Obj *p_so_open; - CDictionary_String_Obj *p_so_close; - for(int i=0; i=2 && (copyExpression.At(index)==p_so_open.Value() && copyExpression.At(index+conditionExpression.Total()-1)==p_so_close.Value())) - { - index=index+1; - Total=Total-2; - } - if(Total!=3) - { - Print("Conclusion part of the rule should be in form: 'variable is term'"); - //--- return - return (NULL); - } -//--- Parse variable - CLexem *exprVariable=copyExpression.At(index); - if(!exprVariable.IsTypeOf(TYPE_CLASS_VarLexem)) - { - Print(StringFormat("Wrong identifier '%s' in conclusion part of the rule.",exprVariable.Text())); - //--- return - return (NULL); - } - CVarLexem *varLexem=exprVariable; - if(varLexem.Input()==true) - { - Print("The variable in conclusion part must be an output variable."); - //--- return - return (NULL); - } -//--- Parse 'is' lexem - CLexem *exprIs=copyExpression.At(index+1); - for(int i=0; i -#include "GenericFuzzySystem.mqh" -#include "InferenceMethod.mqh" -#include "RuleParser.mqh" -#include "FuzzyRule.mqh" -#include "SugenoVariable.mqh" -//+------------------------------------------------------------------+ -//| Purpose: Creating Sugeno fuzzy system | -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ -//| Sugeno fuzzy inference system | -//+------------------------------------------------------------------+ -class CSugenoFuzzySystem : public CGenericFuzzySystem - { -private: - CList *m_output; // List of Sugeno variable - CList *m_rules; // List of Sugeno fuzzy rule - -public: - CSugenoFuzzySystem(void); - ~CSugenoFuzzySystem(void); - //--- method gets the output linguistic variables - CList *Output() { return(m_output); } - //--- method gets the fuzzy rule - CList *Rules() { return(m_rules); } - //--- maethod gets the variable by name - CSugenoVariable *OutputByName(const string name); - //--- method create new linear function - CLinearSugenoFunction *CreateSugenoFunction(const string name,CList *coeffs,const double constValue); - CLinearSugenoFunction *CreateSugenoFunction(const string name,const double &coeffs[]); - //--- method create a new rule - CSugenoFuzzyRule *EmptyRule(); - //--- method for calculate result - CSugenoFuzzyRule *ParseRule(const string rule); - CList *EvaluateConditions(CList *fuzzifiedInput); - CList *EvaluateFunctions(CList *inputValues); - CList *CombineResult(CList *ruleWeights,CList *functionResults); - CList *Calculate(CList *inputValues); - }; -//+------------------------------------------------------------------+ -//| Constructor without parameters | -//+------------------------------------------------------------------+ -CSugenoFuzzySystem::CSugenoFuzzySystem(void) - { - m_output=new CList; - m_rules=new CList; - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSugenoFuzzySystem::~CSugenoFuzzySystem(void) - { - delete m_output; - delete m_rules; - } -//+------------------------------------------------------------------+ -//| Get the output variable of the system by name | -//+------------------------------------------------------------------+ -CSugenoVariable *CSugenoFuzzySystem::OutputByName(const string name) - { - for(int i=0; i -#include "FuzzyVariable.mqh" -#include "Dictionary.mqh" -//+------------------------------------------------------------------+ -//| Purpose: creating Sugeno variable. | -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ -//| The base class for Linear Sugeno Function | -//+------------------------------------------------------------------+ -class ISugenoFunction : public CNamedValueImpl - { -public: - //--- method to check type - virtual bool IsTypeOf(EnType type) { return(type==TYPE_CLASS_ISugenoFunction); } - }; -//+------------------------------------------------------------------+ -//| Lenear function for Sugeno Fuzzy System | -//+------------------------------------------------------------------+ -class CLinearSugenoFunction : public ISugenoFunction - { -private: - CList *m_input; // List of input variables - CList *m_coeffs; // The dictionary which stores variables and their coefficients - double m_const_value; // The constant term of the linear equation - -public: - CLinearSugenoFunction(const string name,CList *in); - CLinearSugenoFunction(const string name,CList *in,CList *coeffs,const double constValue); - CLinearSugenoFunction(const string name,CList *in,const double &coeffs[]); - ~CLinearSugenoFunction(void); - //--- method to check type - virtual bool IsTypeOf(EnType type) { return(type==TYPE_CLASS_LinearSugenoFunction); } - //--- methods gets or sets constant coefficient - double ConstValue() { return(m_const_value); } - void ConstValue(const double value) { m_const_value=value; } - //--- methods gets or sets coefficient by fuzzy variable - double GetCoefficient(CFuzzyVariable *var); - void SetCoefficient(CFuzzyVariable *var,const double coeff); - //--- calculate - double Evaluate(CList *inputValues); - }; -//+------------------------------------------------------------------+ -//| First constructor with parameters | -//+------------------------------------------------------------------+ -CLinearSugenoFunction::CLinearSugenoFunction(const string name,CList *in) - { - m_coeffs=new CList; - CNamedValueImpl::Name(name); - m_input=in; - } -//+------------------------------------------------------------------+ -//| Second constructor with parameters | -//+------------------------------------------------------------------+ -CLinearSugenoFunction::CLinearSugenoFunction(const string name,CList *in,CList *coeffs,const double constValue) - { - CNamedValueImpl::Name(name); - m_input=in; -//--- Check that all coeffecients are related to the variable from input - for(int i=0; i0) | -//| b : Second shape parameter (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 MathProbabilityDensityBeta(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; - } -//--- a and b must be positive - if(a<=0.0 || b<=0.0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } - - error_code=ERR_OK; -//--- check x range - if(x<=0.0 || x>=1.0) - return TailLog0(true,log_mode); - - double log_result=(a-1.0)*MathLog(x)+(b-1.0)*MathLog(1.0-x)-MathBetaLog(a,b); -//--- return log beta density - if(log_mode==true) - return log_result; -//--- return beta density - return MathExp(log_result); - } -//+------------------------------------------------------------------+ -//| Beta density function (PDF) | -//+------------------------------------------------------------------+ -//| The function returns the probability density function of | -//| the Beta distribution with shape parameters a and b. | -//| | -//| f(x,a,b)= (1/Beta(a,b))*x^(a-1)*(1-x)^(b-1) | -//| Arguments: | -//| x : Random variable | -//| a : First shape parameter (a>0) | -//| b : Second shape parameter (b>0) | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The probability density evaluated at x. | -//+------------------------------------------------------------------+ -double MathProbabilityDensityBeta(const double x,const double a,const double b,int &error_code) - { - return MathProbabilityDensityBeta(x,a,b,false,error_code); - } -//+------------------------------------------------------------------+ -//| Beta density function (PDF) | -//+------------------------------------------------------------------+ -//| The function calculates the probability density function of the | -//| Beta distribution with shape parameters a and b for values in | -//| x[] array. | -//| | -//| Arguments: | -//| x : Array with random variables | -//| a : First shape parameter (a>0) | -//| b : Second shape parameter (b>0) | -//| log_mode : Logarithm mode flag,if true it calculates Log values| -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathProbabilityDensityBeta(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.0 || b<=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; i=1.0) - result[i]=TailLog0(true,log_mode); - else - { - double log_result=(a-1.0)*MathLog(x_arg)+(b-1.0)*MathLog(1.0-x_arg)-MathBetaLog(a,b); - if(log_mode==true) - result[i]=log_result; - else - result[i]=MathExp(log_result); - } - } - return true; - } -//+------------------------------------------------------------------+ -//| Beta density function (PDF) | -//+------------------------------------------------------------------+ -//| The function calculates the probability density function of the | -//| Beta distribution with shape parameters a and b for values in | -//| x[] array. | -//| | -//| Arguments: | -//| x : Array with random variables | -//| a : First shape parameter (a>0) | -//| b : Second shape parameter (b>0) | -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathProbabilityDensityBeta(const double &x[],const double a,const double b,double &result[]) - { - return MathProbabilityDensityBeta(x,a,b,false,result); - } -//+------------------------------------------------------------------+ -//| Beta cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function returns the cumulative distribution function of | -//| the Beta distribution with shape parameters a and b, evaluated | -//| at x. | -//| | -//| Arguments: | -//| x : The desired quantile | -//| a : First shape parameter (a>0) | -//| b : Second shape parameter (b>0) | -//| 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 Beta cumulative distribution function with | -//| shape parameters a and b, evaluated at x. | -//+------------------------------------------------------------------+ -double MathCumulativeDistributionBeta(const double x,const double a,const double b,const bool tail,const bool log_mode,int &error_code) - { -//--- check NaN - if(!MathIsValidNumber(x) || !MathIsValidNumber(a) || !MathIsValidNumber(b)) - { - error_code=ERR_ARGUMENTS_NAN; - return QNaN; - } -//--- a and b must be positive - if(a<=0.0 || b<=0.0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } - - error_code=ERR_OK; -//--- check x range - if(x<=0.0) - return TailLog0(tail,log_mode); - if(x>=1.0) - return TailLog1(tail,log_mode); -//--- calculate probability and take into account round-off errors - double cdf=MathMin(MathBetaIncomplete(x,a,b),1.0); -//--- return result depending on arguments - return TailLogValue(cdf,tail,log_mode); - } -//+------------------------------------------------------------------+ -//| Beta cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function returns the cumulative distribution function of | -//| the Beta distribution with shape parameters a and b, evaluated | -//| at x. | -//| | -//| Arguments: | -//| x : The desired quantile | -//| a : First shape parameter (a>0) | -//| b : Second shape parameter (b>0) | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The value of the Beta cumulative distribution function with | -//| shape parameters a and b, evaluated at x. | -//+------------------------------------------------------------------+ -double MathCumulativeDistributionBeta(const double x,const double a,const double b,int &error_code) - { - return MathCumulativeDistributionBeta(x,a,b,true,false,error_code); - } -//+------------------------------------------------------------------+ -//| The Beta cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function returns the cumulative distribution function of | -//| the Beta distribution with shape parameters a and b for values | -//| in x[] array | -//| | -//| Arguments: | -//| x : Array with random variables | -//| a : First shape parameter (a>0) | -//| b : Second shape parameter (b>0) | -//| 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: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathCumulativeDistributionBeta(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.0 || b<=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; i=1.0) - result[i]=TailLog1(tail,log_mode); - else - { - //--- calculate probability and take into account round-off errors - double cdf=MathMin(MathBetaIncomplete(x_arg,a,b),1.0); - //--- return result depending on arguments - result[i]=TailLogValue(cdf,tail,log_mode); - } - } - else - return false; - } - return(true); - } -//+------------------------------------------------------------------+ -//| Beta cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function calculates the cumulative distribution function of | -//| the Beta distribution with shape parameters a and b for values | -//| in x[] array. | -//| | -//| Arguments: | -//| x : Array with random variables | -//| a : First shape parameter (a>0) | -//| b : Second shape parameter (b>0) | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathCumulativeDistributionBeta(const double &x[],const double a,const double b,double &result[]) - { - return MathCumulativeDistributionBeta(x,a,b,true,false,result); - } -//+------------------------------------------------------------------+ -//| Beta distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function returns the inverse cumulative distribution | -//| function of the Beta distribution with shape parameters a and b | -//| for the desired probability. | -//| | -//| Arguments: | -//| probability : The desired probability | -//| a : First shape parameter (a>0) | -//| b : Second shape parameter (b>0) | -//| tail : Flag to calculate lower tail | -//| log_mode : Logarithm mode flag,if true calculates Log values | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The value of the inverse cumulative distribution function of | -//| the Beta distribution with shape parameters a and b. | -//+------------------------------------------------------------------+ -double MathQuantileBeta(const double probability,const double a,const double b,const bool tail,const bool log_mode,int &error_code) - { -//--- check parameters - if(!MathIsValidNumber(probability) || !MathIsValidNumber(a) || !MathIsValidNumber(b)) - { - error_code=ERR_ARGUMENTS_NAN; - return QNaN; - } -//--- a and b must be positive - if(a<=0.0 || b<=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; - } - - error_code=ERR_OK; -//--- check probabilty - if(prob==0.0) - return 0.0; - if(prob==1.0) - return 1.0; - - const double eps=10e-16; -//--- set h and h_min - double h=1.0; - double h_min=MathSqrt(eps); - -//--- initial x value - double x=a/(a+b); - if(x==0.0) - x=h_min; - else - if(x==1.0) - x=1.0-h_min; - - int err_code=0; - const int max_iterations=100; - int iterations=0; -//--- Newton iterations - while(iterationsh_min*MathAbs(x)) && (MathAbs(h)>h_min))==false) - break; - //--- calculate pdf and cdf - double pdf=MathProbabilityDensityBeta(x,a,b,false,err_code); - double cdf=MathCumulativeDistributionBeta(x,a,b,true,false,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(iterations0) | -//| b : Second shape parameter (b>0) | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The value of the inverse cumulative distribution function | -//| of the Beta distribution with shape parameters a and b. | -//+------------------------------------------------------------------+ -double MathQuantileBeta(const double probability,const double a,const double b,int &error_code) - { - return MathQuantileBeta(probability,a,b,true,false,error_code); - } -//+------------------------------------------------------------------+ -//| Beta distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function calculates the the inverse cumulative distribution | -//| function of the Beta distribution with shape parameters a and b | -//| for the probability values from probability[] array. | -//| | -//| Arguments: | -//| probability : Array with probability values | -//| a : First shape parameter (a>0) | -//| b : Second shape parameter (b>0) | -//| tail : Lower tail flag (lower tail of probability used) | -//| log_mode : Logarithm mode flag (log probability used) | -//| result : Output array with quantile values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathQuantileBeta(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; -//--- a and b must be positive - if(a<=0.0 || b<=0.0) - return false; - - int data_count=ArraySize(probability); - if(data_count==0) - return false; - - int error_code=0; - ArrayResize(result,data_count); - - const double eps=10e-16; - double h_min=MathSqrt(eps); - - int err_code=0; - const int max_iterations=1000; - for(int i=0; i1.0) - return false; - //--- check probabilty - if(prob==0.0) - result[i]=0.0; - else - if(prob==1.0) - result[i]=1.0; - else - { - //--- initial x value - double x=a/(a+b); - if(x==0.0) - x=h_min; - else - if(x==1.0) - x=1.0-h_min; - - double h=1.0; - int iterations=0; - //--- Newton iterations - while(iterationsh_min*MathAbs(x)) && (MathAbs(h)>h_min))==false) - break; - //--- calculate pdf and cdf - double pdf=MathProbabilityDensityBeta(x,a,b,false,err_code); - double cdf=MathCumulativeDistributionBeta(x,a,b,true,false,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(iterations0) | -//| b : Second shape parameter (b>0) | -//| result : Output array with quantile values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathQuantileBeta(const double &probability[],const double a,const double b,double &result[]) - { - return MathQuantileBeta(probability,a,b,true,false,result); - } -//+------------------------------------------------------------------+ -//| Random variate from the Beta distribution | -//+------------------------------------------------------------------+ -//| The function returns a single random deviate from the Beta | -//| distribution with parameters a and b. | -//| | -//| Arguments: | -//| a : First shape parameter (a>0) | -//| b : Second shape parameter (b>0) | -//| | -//| Return value: | -//| The random value with Beta distribution. | -//| | -//| Reference: | -//| Russell Cheng, | -//| "Generating Beta Variates with Nonintegral Shape Parameters", | -//| Communications of the ACM, | -//| Volume 21, Number 4, April 1978, pages 317-322. | -//| | -//| Original FORTRAN77 version by Barry Brown, James Lovato. | -//| C version by John Burkardt. | -//+------------------------------------------------------------------+ -double MathRandomBeta(const double a,const double b) - { - const double log4 = MathLog(4); - const double log5 = MathLog(5); - double a1,b1,alpha,beta,gamma,delta,r,s,u1,u2,v,y,z; - double w=0.0; - double value=0; -//--- - if(1.00) | -//| b : Second shape parameter (b>0) | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The random value with Beta distribution. | -//+------------------------------------------------------------------+ -double MathRandomBeta(const double a,const double b,int &error_code) - { -//--- check parameters - if(!MathIsValidNumber(a) || !MathIsValidNumber(b)) - { - error_code=ERR_ARGUMENTS_NAN; - return QNaN; - } -//--- a and b must be positive - if(a<=0.0 || b<=0.0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } - - error_code=ERR_OK; -//--- return beta random value - return MathRandomBeta(a,b); - } -//+------------------------------------------------------------------+ -//| Random variate from Beta distribution | -//+------------------------------------------------------------------+ -//| The function generates random variables from Beta distribution | -//| with parameters a and b. | -//| | -//| Arguments: | -//| a : First shape parameter (a>0) | -//| b : Second shape parameter (b>0) | -//| data_count : Number of values needed | -//| result : Output array with random values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathRandomBeta(const double a,const double b,const int data_count,double &result[]) - { - if(data_count<=0) - return false; -//--- check parameters - if(!MathIsValidNumber(a) || !MathIsValidNumber(b)) - return false; -//--- a and b must be positive - if(a<=0.0 || b<=0.0) - return false; - -//--- prepare output array and calculate random values - ArrayResize(result,data_count); - for(int i=0; i0) | -//| b : Second shape parameter (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 MathMomentsBeta(const double a,const double b,double &mean,double &variance,double &skewness,double &kurtosis,int &error_code) - { -//--- initial 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.0 || b<=0.0) - { - error_code=ERR_ARGUMENTS_INVALID; - return false; - } - - error_code=ERR_OK; -//--- calculate moments - mean =a/(a+b); - variance=(a*b)/((a+b)*(a+b)*(a+b+1)); - skewness=2*(b-a)*MathSqrt(a+b+1)/(MathSqrt(a*b)*(a+b+2)); - kurtosis=6*(a*a*a+a*a*(1-2*b)+b*b*(1+b)-2*a*b*(2+b))/(a*b*(a+b+2)*(a+b+3)); -//--- successful - return true; - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Stat/Binomial.mqh b/Include/Math/Stat/Binomial.mqh deleted file mode 100644 index a47b736..0000000 --- a/Include/Math/Stat/Binomial.mqh +++ /dev/null @@ -1,874 +0,0 @@ -//+------------------------------------------------------------------+ -//| Binomial.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include "Math.mqh" -#include "Beta.mqh" - -//+------------------------------------------------------------------+ -//| Binomial probability mass function (PDF) | -//+------------------------------------------------------------------+ -//| The function returns the Binomial probability mass function | -//| with parameters n and p at x. | -//| | -//| f(x,n,p)= C(n,x)*(p^x)*(1-p)^(n-x) | -//| | -//| where binomial coefficient C(n,k)=n!/(k!*(n-k)!) | -//| | -//| Arguments: | -//| x : Integer random variable | -//| n : Number of trials | -//| p : Probability of success for each trial | -//| log_mode : Logarithm mode flag, if true it returns Log values | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The probability mass function evaluated at x. | -//+------------------------------------------------------------------+ -double MathProbabilityDensityBinomial(const double x,const double n,const double p,const bool log_mode,int &error_code) - { -//--- check NaN - if(!MathIsValidNumber(x) || !MathIsValidNumber(n) || !MathIsValidNumber(p)) - { - error_code=ERR_ARGUMENTS_NAN; - return QNaN; - } -//--- check n - if(n<0 || n!=MathRound(n)) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } -//--- check p range - if(p<0.0 || p>1.0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } - - error_code=ERR_OK; -//--- case p=0 - if(p==0.0 || p==1.0) - return TailLog0(true,log_mode); -//--- check x range - if(x<0 || x>n) - return TailLog0(true,log_mode); - - double log_result=MathGammaLog(n+1.0)-MathGammaLog(x+1.0)-MathGammaLog(n-x+1.0)+x*MathLog(p)+(n-x)*MathLog(1.0-p); - if(log_mode==true) - return log_result; -//--- return probability mass - return MathExp(log_result); - } -//+------------------------------------------------------------------+ -//| Binomial probability mass function (PDF) | -//+------------------------------------------------------------------+ -//| The function returns the Binomial probability mass function | -//| with parameters n and p at x. | -//| | -//| f(x,n,p)= C(n,x)*(p^x)*(1-p)^(n-x) | -//| | -//| where binomial coefficient C(n,k)=n!/(k!*(n-k)!) | -//| | -//| Arguments: | -//| x : Integer random variable | -//| n : Number of trials | -//| p : Probability of success for each trial | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The probability mass function evaluated at x. | -//+------------------------------------------------------------------+ -double MathProbabilityDensityBinomial(const double x,const double n,const double p,int &error_code) - { - return MathProbabilityDensityBinomial(x,n,p,false,error_code); - } -//+------------------------------------------------------------------+ -//| Binomial probability mass function (PDF) | -//+------------------------------------------------------------------+ -//| The function calculates the Binomial probability mass function | -//| with parameters n and p for values in x[] array. | -//| | -//| Arguments: | -//| x : Array with integer random variables | -//| n : Number of trials | -//| p : Probability of success for each trial | -//| log_mode : Logarithm mode flag,if true it calculates Log values| -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathProbabilityDensityBinomial(const double &x[],const double n,const double p,const bool log_mode,double &result[]) - { -//--- check NaN - if(!MathIsValidNumber(n) || !MathIsValidNumber(p)) - return false; -//--- check n - if(n<0 || n!=MathRound(n)) - return false; -//--- check p range - if(p<0.0 || p>1.0) - return false; - - int data_count=ArraySize(x); - if(data_count==0) - return false; - - int error_code=0; - ArrayResize(result,data_count); -//--- case p=0 or p=1 - if(p==0.0 || p==1.0) - { - for(int i=0; in) - result[i]=TailLog0(true,log_mode); - else - { - double log_result=MathGammaLog(n+1.0)-MathGammaLog(x_arg+1.0)-MathGammaLog(n-x_arg+1.0)+x_arg*MathLog(p)+(n-x_arg)*MathLog(1.0-p); - if(log_mode==true) - result[i]=log_result; - else - result[i]=MathExp(log_result); - } - } - else - return false; - } - return true; - } -//+------------------------------------------------------------------+ -//| Binomial probability mass function (PDF) | -//+------------------------------------------------------------------+ -//| The function calculates the Binomial probability mass function | -//| with parameters n and p for values in x[] array. | -//| | -//| Arguments: | -//| x : Array with integer random variables | -//| n : Number of trials | -//| p : Probability of success for each trial | -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathProbabilityDensityBinomial(const double &x[],const double n,const double p,double &result[]) - { - return MathProbabilityDensityBinomial(x,n,p,false,result); - } -//+------------------------------------------------------------------+ -//| Binomial cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function returns the value of the Binomial cumulative | -//| distribution function with given n and p at the desired x. | -//| | -//| Arguments: | -//| x : Integer random variable | -//| n : Number of trials | -//| p : Probability of success for each trial | -//| 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 cumulative distribution function evaluated at x. | -//+------------------------------------------------------------------+ -double MathCumulativeDistributionBinomial(const double x,const double n,double p,const bool tail,const bool log_mode,int &error_code) - { -//--- check NaN - if(!MathIsValidNumber(x) || !MathIsValidNumber(n) || !MathIsValidNumber(p)) - { - error_code=ERR_ARGUMENTS_NAN; - return QNaN; - } -//--- check n - if(n<0 || n!=MathRound(n)) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } -//--- check probability - if(p<0.0 || p>1.0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } - - error_code=ERR_OK; -//--- case p==0 - if(p==0.0) - { - if(x>=0) - return TailLog1(tail,log_mode); - else - return TailLog0(tail,log_mode); - } -//--- case p==1 - if(p==1.0) - { - if(x>n) - return TailLog1(tail,log_mode); - else - return TailLog0(tail,log_mode); - } -//--- x must be>=0 - if(x<0) - return TailLog0(tail,log_mode); -//--- check x - if(x>n) - return TailLog1(tail,log_mode); - int err_code=0; -//--- calculate using Beta distribution and correct round-off errors - double result=MathMin(1.0-MathCumulativeDistributionBeta(p,x+1.0,n-x,err_code),1.0); -//--- return result depending on arguments - return TailLogValue(result,tail,log_mode); - } -//+------------------------------------------------------------------+ -//| Binomial cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function returns the value of the Binomial cumulative | -//| distribution function with given n and p at the desired x. | -//| | -//| Arguments: | -//| x : Integer random variable | -//| n : Number of trials | -//| p : Probability of success for each trial | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The cumulative distribution function evaluated at x. | -//+------------------------------------------------------------------+ -double MathCumulativeDistributionBinomial(const double x,const double n,double p,int &error_code) - { - return MathCumulativeDistributionBinomial(x,n,p,true,false,error_code); - } -//+------------------------------------------------------------------+ -//| Binomial cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function returns the value of the Binomial cumulative | -//| distribution function with given n and p at the desired x. | -//| | -//| Arguments: | -//| x : Array with integer random variables | -//| n : Number of trials | -//| p : Probability of success for each trial | -//| 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: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathCumulativeDistributionBinomial(const double &x[],const double n,double p,const bool tail,const bool log_mode,double &result[]) - { -//--- check NaN - if(!MathIsValidNumber(n) || !MathIsValidNumber(p)) - return false; -//--- check n - if(n<0 || n!=MathRound(n)) - return false; -//--- check probability - if(p<0.0 || p>1.0) - return false; - - int data_count=ArraySize(x); - if(data_count==0) - return false; - - int error_code=0; - ArrayResize(result,data_count); - -//--- case p=0 and p==1 - if(p==0.0 || p==1.0) - { - if(p==0.0) - { - for(int i=0; i=0) - result[i]=TailLog1(tail,log_mode); - else - result[i]=TailLog0(tail,log_mode); - } - } - else - //--- p==1.0 - { - for(int i=0; in) - result[i]=TailLog1(tail,log_mode); - else - result[i]=TailLog0(tail,log_mode); - } - } - return true; - } - - int err_code=0; - for(int i=0; in) - result[i]=TailLog1(tail,log_mode); - else - { - double value=MathMin(1.0-MathCumulativeDistributionBeta(p,x_arg+1.0,n-x_arg,err_code),1.0); - //--- calculate result depending on arguments - result[i]=TailLogValue(value,tail,log_mode); - } - } - else - return false; - } - return true; - } -//+------------------------------------------------------------------+ -//| Binomial cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function returns the value of the Binomial cumulative | -//| distribution function with given n and p for values | -//| from x[] array. | -//| | -//| Arguments: | -//| x : Array with integer random variables | -//| n : Number of trials | -//| p : Probability of success for each trial | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathCumulativeDistributionBinomial(const double &x[],const double n,double p,double &result[]) - { - return MathCumulativeDistributionBinomial(x,n,p,true,false,result); - } -//+------------------------------------------------------------------+ -//| Binomial distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function returns the value of the inverse Binomial cumulative| -//| distribution function with parameters n and p for the desired | -//| probability. | -//| | -//| Arguments: | -//| probability : The desired probability | -//| n : Number of trials | -//| p : Probability of success for each trial | -//| tail : Lower tail flag (lower tail of probability used) | -//| log_mode : Logarithm mode flag (log probability used) | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The value of the inverse cumulative distribution function | -//| of the Binomial distribution with parameters n and p. | -//+------------------------------------------------------------------+ -double MathQuantileBinomial(const double probability,const double n,const double p,const bool tail,const bool log_mode,int &error_code) - { -//--- check NaN - if(!MathIsValidNumber(probability) || !MathIsValidNumber(n) || !MathIsValidNumber(p)) - { - error_code=ERR_ARGUMENTS_NAN; - return QNaN; - } -//--- check n - if(n<0 || n!=MathRound(n)) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } -//--- check p range - if(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; - } - - error_code=ERR_OK; - int iterations=0; - const int max_iterations=1000; -//--- direct cdf calculation - double sum=MathProbabilityDensityBinomial(0,n,p,false,error_code); - while(sum1.0) - return false; - - int data_count=ArraySize(probability); - if(data_count==0) - return false; - - int error_code=0; - ArrayResize(result,data_count); - - const int max_iterations=1000; - for(int i=0; i1.0) - return false; - - int iterations=0; - //--- direct cdf calculation - double sum=MathProbabilityDensityBinomial(0,n,p,false,error_code); - while(sum=1.0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } - - error_code=ERR_OK; -//--- return binomial random value - return MathRandomBinomial(n,p); - } -//+------------------------------------------------------------------+ -//| Random variate from Binomial distribution | -//+------------------------------------------------------------------+ -//| The function generates random variables from Binomial | -//| distribution with parameters n and p. | -//| | -//| Arguments: | -//| n : Number of trials | -//| p : Probability of success for each trial | -//| data_count : Number of values needed | -//| result : Output array with random values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathRandomBinomial(const double n,const double p,const int data_count,double &result[]) - { - if(data_count<=0) - return false; -//--- check NaN - if(!MathIsValidNumber(n) || !MathIsValidNumber(p)) - return false; -//--- check n - if(n<=0 || n!=MathRound(n)) - return false; -//--- check probability - if(p<=0 || p>=1.0) - return false; -//--- 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; -//--- prepare factors - double np=n*p; - double one_mp=(1.0-p); -//--- calculate moments - mean =np; - variance=np*one_mp; - skewness=(1-2*p)/MathSqrt(variance); - kurtosis=(1-6*p*one_mp)/variance; -//--- successful - return true; - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Stat/Cauchy.mqh b/Include/Math/Stat/Cauchy.mqh deleted file mode 100644 index 614a105..0000000 --- a/Include/Math/Stat/Cauchy.mqh +++ /dev/null @@ -1,539 +0,0 @@ -//+------------------------------------------------------------------+ -//| Cauchy.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include "Math.mqh" - -//+------------------------------------------------------------------+ -//| Cauchy density function (PDF) | -//+------------------------------------------------------------------+ -//| Computes the value of the Cauchy probability density function | -//| with parameters a and b at the desired quantile x. | -//| | -//| f(x,a,b)= 1/(pi*b*(1.0+((x-a)/b)^2) | -//| Arguments: | -//| x : Random variable | -//| a : Mean | -//| b : Scale | -//| 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 MathProbabilityDensityCauchy(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 scale - if(b<=0.0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } -//--- prepare argument - double y=(x-a)/b; -//--- check result - if(!MathIsValidNumber(y)) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } - - error_code=ERR_OK; - if(log_mode==true) - return -MathLog(M_PI*b*(1.0+y*y)); -//--- return Cauchy density - return 1.0/(M_PI*b*(1.0+y*y)); - } -//+------------------------------------------------------------------+ -//| Cauchy density function (PDF) | -//+------------------------------------------------------------------+ -//| Computes the value of the Cauchy probability density function | -//| with parameters a and b at the desired quantile x. | -//| | -//| f(x,a,b)= 1/(pi*b*(1.0+((x-a)/b)^2) | -//| Arguments: | -//| x : Random variable | -//| a : Mean | -//| b : Scale | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The probability density evaluated at x. | -//+------------------------------------------------------------------+ -double MathProbabilityDensityCauchy(const double x,const double a,const double b,int &error_code) - { - return MathProbabilityDensityCauchy(x,a,b,false,error_code); - } -//+------------------------------------------------------------------+ -//| Cauchy density function (PDF) | -//+------------------------------------------------------------------+ -//| The function calculates the probability density function of | -//| Cauchy distribution with parameters a and b for values | -//| from x[] array. | -//| | -//| Arguments: | -//| x : Array with random variables | -//| a : Mean | -//| b : Scale | -//| log_mode : Logarithm mode flag, if true it returns Log values | -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathProbabilityDensityCauchy(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 scale - if(b<=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; i-1.0) - cdf=MathMin(0.5+M_1_PI*MathArctan(y),1.0); - else - cdf=MathMin(M_1_PI*MathArctan(-1/y),1.0); - - return TailLogValue(cdf,tail,log_mode); - } -//+------------------------------------------------------------------+ -//| Cauchy cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function returns the cumulative distribution function of | -//| the Cauchy distribution with parameters a and b, evaluated at x. | -//| | -//| Arguments: | -//| x : The desired quantile | -//| a : Mean | -//| b : Scale | -//| error_code : Variable for error code | -//| | -//| The value of the Cauchy cumulative distribution function with | -//| parameters a and b, evaluated at x. | -//+------------------------------------------------------------------+ -double MathCumulativeDistributionCauchy(const double x,const double a,const double b,int &error_code) - { - return MathCumulativeDistributionCauchy(x,a,b,true,false,error_code); - } -//+------------------------------------------------------------------+ -//| Cauchy cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function calculates the cumulative distribution function of | -//| the Cauchy distribution with parameters a and b for values from | -//| x[] array. | -//| | -//| 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| -//| error_code : Variable for error code | -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathCumulativeDistributionCauchy(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 scale - if(b<=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; i-1.0) - cdf=MathMin(0.5+M_1_PI*MathArctan(y),1.0); - else - cdf=MathMin(M_1_PI*MathArctan(-1/y),1.0); - - result[i]=TailLogValue(cdf,tail,log_mode); - } - - return true; - } -//+------------------------------------------------------------------+ -//| Cauchy cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function calculates the cumulative distribution function | -//| of the Cauchy distribution with parameters a and b for values | -//| from x[] array. | -//| | -//| Arguments: | -//| x : Array with random variables | -//| a : Mean | -//| b : Scale | -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathCumulativeDistributionCauchy(const double &x[],const double a,const double b,double &result[]) - { - return MathCumulativeDistributionCauchy(x,a,b,true,false,result); - } -//+------------------------------------------------------------------+ -//| Cauchy distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function returns the inverse cumulative distribution | -//| function of the Cauchy distribution with parameters a and b | -//| for the desired probability. | -//| Q(p,a,b)=a+b*tan*(pi*(p-1/2)) | -//| Arguments: | -//| probability : The desired probability | -//| a : Mean | -//| b : Scale | -//| 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 Cauchy distribution with parameters a and b. | -//+------------------------------------------------------------------+ -double MathQuantileCauchy(const double probability,const double a,const double b,const bool tail,const bool log_mode,int &error_code) - { -//--- check NaN - if(!MathIsValidNumber(probability) || !MathIsValidNumber(a) || !MathIsValidNumber(b)) - { - error_code=ERR_ARGUMENTS_NAN; - return QNaN; - } -//--- check scale - if(b<=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; - } - -//--- f(1)= + infinity - if(prob==1.0) - { - error_code=ERR_RESULT_INFINITE; - return QPOSINF; - } -//--- f(0)= - infinity - if(prob==0.0) - { - error_code=ERR_RESULT_INFINITE; - return QNEGINF; - } - error_code=ERR_OK; -//--- return quantile - return a+b*MathTan(M_PI*(prob-0.5)); - } -//+------------------------------------------------------------------+ -//| Cauchy distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function returns the inverse cumulative distribution | -//| function of the Cauchy distribution with parameters a and b | -//| for the desired probability. | -//| | -//| Arguments: | -//| probability : The desired probability | -//| a : Mean | -//| b : Scale | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The value of the inverse cumulative distribution function | -//| of the Cauchy distribution with parameters a and b. | -//+------------------------------------------------------------------+ -double MathQuantileCauchy(const double probability,const double a,const double b,int &error_code) - { - return MathQuantileCauchy(probability,a,b,true,false,error_code); - } -//+------------------------------------------------------------------+ -//| Cauchy distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function returns the inverse cumulative distribution | -//| function of the Cauchy distribution with parameters a and b | -//| for the probability values from array. | -//| | -//| Arguments: | -//| probability : Array with probabilities | -//| a : Mean | -//| b : Scale | -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathQuantileCauchy(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; -//--- check scale - if(b<=0.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; - else - //--- f(0)= - infinity - if(prob==0.0) - result[i]=QNEGINF; - else - result[i]=a+b*MathTan(M_PI*(prob-0.5)); - } - return true; - } -//+------------------------------------------------------------------+ -//| Cauchy distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -bool MathQuantileCauchy(const double &probability[],const double a,const double b,double &result[]) - { - return MathQuantileCauchy(probability,a,b,true,false,result); - } -//+------------------------------------------------------------------+ -//| Random variate from the Cauchy distribution | -//+------------------------------------------------------------------+ -//| Compute the random variable from the Cauchy distribution | -//| with parameters a and b. | -//| | -//| Arguments: | -//| a : Mean | -//| b : Scale | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The random value with Cauchy distribution. | -//+------------------------------------------------------------------+ -double MathRandomCauchy(const double a,const double b,int &error_code) - { -//--- check parameters - if(!MathIsValidNumber(a) || !MathIsValidNumber(b)) - { - error_code=ERR_ARGUMENTS_NAN; - return QNaN; - } -//--- check scale - if(b<0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } - - error_code=ERR_OK; -//--- check scale=0 - if(b==0.0) - return a; -//--- generate random number - double rnd=MathRandomNonZero(); -//--- return result - return a+b*MathTan(M_PI*(rnd-0.5)); - } -//+------------------------------------------------------------------+ -//| Random variate from the Cauchy distribution | -//+------------------------------------------------------------------+ -//| Generates random variables from the Cauchy distribution with | -//| parameters a and b. | -//| | -//| Arguments: | -//| a : Mean | -//| b : Scale | -//| data_count : Number of values needed | -//| result : Output array with random values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathRandomCauchy(const double a,const double b,const int data_count,double &result[]) - { -//--- check parameters - if(!MathIsValidNumber(a) || !MathIsValidNumber(b)) - return false; -//--- check scale - if(b<0) - return false; - -//--- prepare output array - ArrayResize(result,data_count); - -//--- check scale=0 - if(b==0.0) - { - for(int i=0; i1.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; - -//---- calculate quantile using Gamma distribution - return MathQuantileGamma(prob,nu*0.5,2.0,error_code); - } -//+------------------------------------------------------------------+ -//| Chi-Square distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function returns the inverse cumulative distribution | -//| function of the Chi-Square distribution with parameter nu | -//| for the desired probability. | -//| | -//| Arguments: | -//| probability : The desired probability | -//| nu : Degrees of freedom | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The value of the inverse cumulative distribution function | -//| of the Chi-Square distribution with parameter nu. | -//+------------------------------------------------------------------+ -double MathQuantileChiSquare(const double probability,const double nu,int &error_code) - { - return MathQuantileChiSquare(probability,nu,true,false,error_code); - } -//+------------------------------------------------------------------+ -//| Chi-Square distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function calculates the inverse cumulative distribution | -//| function of the Chi-Square distribution with parameter nu | -//| for values from the probability[] array. | -//| | -//| Arguments: | -//| probability : Array with probabilities | -//| 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 MathQuantileChiSquare(const double &probability[],const double nu,const bool tail,const bool log_mode,double &result[]) - { -//--- check NaN - if(!MathIsValidNumber(nu)) - return false; -//--- nu must be positive - if(nu<=0) - return false; -//--- nu must be integer - if(nu!=MathRound(nu)) - 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; - - if(prob==0.0) - result[i]=0.0; - else - if(prob==1.0) - result[i]=QPOSINF; - else - { - //--- calculate using Gamma distribution - result[i]=MathQuantileGamma(prob,nu*0.5,2.0,error_code); - } - } - return true; - } -//+------------------------------------------------------------------+ -//| Chi-Square distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function calculates the inverse cumulative distribution | -//| function of the Chi-Square distribution with parameter nu | -//| for values from the probability[] array. | -//| | -//| Arguments: | -//| probability : Array with probabilities | -//| nu : Degrees of freedom | -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathQuantileChiSquare(const double &probability[],const double nu,double &result[]) - { - return MathQuantileChiSquare(probability,nu,true,false,result); - } -//+------------------------------------------------------------------+ -//| Random variate from the Chi-Square distribution | -//+------------------------------------------------------------------+ -//| Computes the random variable from the Chi-Square distribution | -//| with parameter nu. | -//| | -//| Arguments: | -//| nu : Degrees of freedom | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The random value with Chi-Square distribution. | -//+------------------------------------------------------------------+ -double MathRandomChiSquare(const double nu,int &error_code) - { -//--- NaN - if(!MathIsValidNumber(nu)) - { - error_code=ERR_ARGUMENTS_NAN; - return QNaN; - } -//--- nu must be integer - if(nu!=MathRound(nu)) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } -//--- nu must be positive - if(nu<=0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } - - error_code=ERR_OK; -//--- return gamma(nu/2,2) - return MathRandomGamma(nu*0.5,2.0,error_code); - } -//+------------------------------------------------------------------+ -//| Random variate from Chi-Square distribution | -//+------------------------------------------------------------------+ -//| Generates random variables from the Chi-Square 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 MathRandomChiSquare(const double nu,const int data_count,double &result[]) - { -//--- check NaN - if(!MathIsValidNumber(nu)) - return false; -//--- nu must be integer - if(nu!=MathRound(nu)) - return false; -//--- nu must be positive - if(nu<=0) - return false; - int error_code=0; -//--- prepare output array and calculate random values - ArrayResize(result,data_count); - for(int i=0; i1.0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } - - error_code=ERR_OK; -//--- check zero probability case - if(prob==0.0) - return 0.0; - else - if(prob==1.0) - return QPOSINF; -//--- return quantile - return -mu*MathLog(1.0-prob); - } -//+------------------------------------------------------------------+ -//| Exponential distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function returns the inverse cumulative distribution | -//| function of Exponential distribution with parameter mu | -//| for the desired probability. | -//| | -//| Arguments: | -//| probability : The desired probability | -//| mu : Mean | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The value of the inverse cumulative distribution function | -//| of the Exponential distribution with parameter mu. | -//+------------------------------------------------------------------+ -double MathQuantileExponential(const double probability,const double mu,int &error_code) - { - return MathQuantileExponential(probability,mu,true,false,error_code); - } -//+------------------------------------------------------------------+ -//| Exponential distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function calculates the inverse cumulative distribution | -//| function of the Exponential distribution with parameter mu | -//| for values from the probability[] array. | -//| | -//| Arguments: | -//| probability : Array with probabilities | -//| mu : Mean | -//| 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 MathQuantileExponential(const double &probability[],const double mu,const bool tail,const bool log_mode,double &result[]) - { -//--- check parameters - if(!MathIsValidNumber(mu)) - return false; -//--- mu must be positive - if(mu<=0.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; - - //--- check zero probability case - if(prob==0.0) - result[i]=0.0; - else - if(prob==1.0) - result[i]=QPOSINF; - else - result[i]=-mu*MathLog(1.0-prob); - } - return true; - } -//+------------------------------------------------------------------+ -//| Exponential distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function calculates the inverse cumulative distribution | -//| function of the Exponential distribution with parameter mu | -//| for values from the probability[] array. | -//| | -//| Arguments: | -//| probability : Array with probabilities | -//| mu : Mean | -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathQuantileExponential(const double &probability[],const double mu,double &result[]) - { - return MathQuantileExponential(probability,mu,true,false,result); - } -//+------------------------------------------------------------------+ -//| Random variate from the Exponential distribution | -//+------------------------------------------------------------------+ -//| Compute the random variable from the Exponential distribution | -//| with parameter mu using simple inversion method. | -//| | -//| Arguments: | -//| mu : Mean | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The random value with Exponential distribution. | -//| | -//| Reference: | -//| Devroye L. "Non-uniform random variate generation",Springer,1986.| -//+------------------------------------------------------------------+ -double MathRandomExponential(const double mu,int &error_code) - { -//--- check mu - if(!MathIsValidNumber(mu)) - { - error_code=ERR_ARGUMENTS_NAN; - return QNaN; - } -//--- mu must be positive - if(mu<=0.0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } - - error_code=ERR_OK; -//--- generate random number - double rnd=MathRandomNonZero(); -//--- return variate using quantile - return -mu*MathLog(1.0-rnd); - } -//+------------------------------------------------------------------+ -//| Random variate from the Exponential distribution | -//+------------------------------------------------------------------+ -//| Generates random variables from the Exponential distribution | -//| with parameter mu. | -//| | -//| Arguments: | -//| mu : Mean | -//| data_count : Number of values needed | -//| result : Output array with random values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathRandomExponential(const double mu,const int data_count,double &result[]) - { -//--- check mu - if(!MathIsValidNumber(mu)) - return false; -//--- mu must be positive - if(mu<=0.0) - return false; -//--- prepare output array and calculate random values - ArrayResize(result,data_count); - for(int i=0; i1.0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } -//--- check case probability==1 - if(prob==1.0) - { - error_code=ERR_RESULT_INFINITE; - return QPOSINF; - } - - error_code=ERR_OK; - if(prob==0.0) - return 0.0; -//--- calculate quantile using Beta distribution - double qBeta=MathQuantileBeta(1.0-prob,nu2*0.5,nu1*0.5,error_code); -//--- return quantile; - return (nu2/qBeta-nu2)/nu1; - } -//+------------------------------------------------------------------+ -//| F-distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function returns the inverse cumulative distribution | -//| function of F-distribution with parameters nu1 and nu2 | -//| for the desired probability. | -//| | -//| Arguments: | -//| probability : The desired probability | -//| nu1 : Numerator degrees of freedom | -//| nu2 : Denominator degrees of freedom | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The value of the inverse cumulative distribution function | -//| of F-distribution with parameters nu1 and nu2. | -//+------------------------------------------------------------------+ -double MathQuantileF(const double probability,const double nu1,const double nu2,int &error_code) - { - return MathQuantileF(probability,nu1,nu2,true,false,error_code); - } -//+------------------------------------------------------------------+ -//| F-distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function calculates the inverse cumulative distribution | -//| function of the F distribution with parameters nu1 and nu2 | -//| for values from the probability[] array. | -//| | -//| Arguments: | -//| probability : Array with probabilities | -//| nu1 : Numerator degrees of freedom | -//| nu2 : Denominator 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 MathQuantileF(const double &probability[],const double nu1,const double nu2,const bool tail,const bool log_mode,double &result[]) - { -//--- check NaN - if(!MathIsValidNumber(nu1) || !MathIsValidNumber(nu2)) - return false; -//--- check arguments - if(nu1!=MathRound(nu1) || nu2!=MathRound(nu2) || nu1<=0 || nu2<=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; - - //--- check case probability==1,0 - if(prob==0.0) - result[i]=0.0; - else - if(prob==1.0) - result[i]=QPOSINF; - else - { - //--- calculate quantile using Beta distribution - double qBeta=MathQuantileBeta(1.0-prob,nu2*0.5,nu1*0.5,error_code); - result[i]=(nu2/qBeta-nu2)/nu1; - } - } - return true; - } -//+------------------------------------------------------------------+ -//| F-distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function calculates the inverse cumulative distribution | -//| function of the F distribution with parameters nu1 and nu2 | -//| for values from probability[] array. | -//| | -//| Arguments: | -//| probability : Array with probabilities | -//| nu1 : Numerator degrees of freedom | -//| nu2 : Denominator degrees of freedom | -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathQuantileF(const double &probability[],const double nu1,const double nu2,double &result[]) - { - return MathQuantileF(probability,nu1,nu2,true,false,result); - } -//+------------------------------------------------------------------+ -//| Random variate from the F-distribution | -//+------------------------------------------------------------------+ -//| Compute the random variable from F-distribution | -//| with parameters nu1 and nu2. | -//| | -//| Arguments: | -//| nu1 : Numerator degrees of freedom | -//| nu2 : Denominator degrees of freedom | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The random value with F-distribution. | -//+------------------------------------------------------------------+ -double MathRandomF(const double nu1,const double nu2,int &error_code) - { -//--- check NaN - if(!MathIsValidNumber(nu1) || !MathIsValidNumber(nu2)) - { - 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; -//--- random F=ChiSquare(nu1)*nu2/ChiSquare(nu2)*nu1; - double xnum = MathRandomGamma(nu1*0.5,1.0,error_code)*nu2; - double xden = MathRandomGamma(nu2*0.5,1.0,error_code)*nu1; -//--- - double value=0.0; - if(xden!=0) - value= xnum/xden; - else - { - error_code=ERR_NON_CONVERGENCE; - value=QNaN; - } -//--- return random F - return value; - } -//+------------------------------------------------------------------+ -//| Random variate from the F distribution | -//+------------------------------------------------------------------+ -//| Generates random variables from the F distribution with | -//| parameters nu1 and nu2. | -//| | -//| Arguments: | -//| data_count : Number of values needed | -//| result : Output array with random values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathRandomF(const double nu1,const double nu2,const int data_count,double &result[]) - { -//--- check NaN - if(!MathIsValidNumber(nu1) || !MathIsValidNumber(nu2)) - return false; -//--- check arguments - if(nu1!=MathRound(nu1) || nu2!=MathRound(nu2) || nu1<=0 || nu2<=0) - return false; - -//--- prepare output array and calculate random values - ArrayResize(result,data_count); - for(int i=0; i2) - mean=nu2/(nu2-2); - if(nu2>4) - variance=2*nu2*nu2*(nu1+nu2-2)/(nu1*(nu2-2)*(nu2-2)*(nu2-4)); - if(nu2>6) - skewness=2*MathSqrt(2)*MathSqrt(nu2-4)*(2*nu1+nu2-2)/(MathSqrt(nu1*(nu1+nu2-2))*(nu2-6)); - if(nu2>8) - kurtosis=12*(nu1*(5*nu2-22)*(nu1+nu2-2)+(nu2-4)*(nu2-2)*(nu2-2))/(nu1*(nu2-8)*(nu2-6)*(nu1+nu2-2)); -//--- successful - return true; - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Stat/Gamma.mqh b/Include/Math/Stat/Gamma.mqh deleted file mode 100644 index 572ca44..0000000 --- a/Include/Math/Stat/Gamma.mqh +++ /dev/null @@ -1,764 +0,0 @@ -//+------------------------------------------------------------------+ -//| Gamma.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include "Normal.mqh" - -const double DoubleEpsilon=1.11022302462515654042E-16; -const double LogMax=7.09782712893383996732E2; -//+------------------------------------------------------------------+ -//| Inverse of the incomplete Gamma integral | -//+------------------------------------------------------------------+ -double MathInverseGammaIncomplete(const double a,const double y) - { -//--- bound the solution - double x0 = DBL_MAX; - double yl = 0; - double x1 = 0; - double yh = 1.0; - double dithresh=5.0*DoubleEpsilon; -//--- approximation to inverse function - double d=1.0/(9.0*a); - int err_code=0; - double q_normal=MathQuantileNormal(y,0,1,true,false,err_code); - double yy=(1.0-d-q_normal*MathSqrt(d)); - double x=a*yy*yy*yy; - double lgm=MathGammaLog(a); - for(int i=0; i<10; i++) - { - if(x>x0 || xyh) - break; - if(yy=y) - { - x1 = x; - yh = yy; - if(dir<0) - { - dir=0; - d=0.5; - } - else - if(dir>1) - d=0.5*d+0.5; - else - d=(y-yl)/(yh-yl); - dir+=1; - } - else - { - x0 = x; - yl = yy; - if(dir>0) - { - dir=0; - d=0.5; - } - else - if(dir<-1) - d=0.5*d; - else - d=(y-yl)/(yh-yl); - dir-=1; - } - } - if(x==0.0 || !MathIsValidNumber(x)) - { - Print("Errors in an arithmetic, casting, or conversion operation."); - return(QNaN); - } -//--- - return(x); - } -//+------------------------------------------------------------------+ -//| Gamma probability density function (PDF) | -//+------------------------------------------------------------------+ -//| The function returns the probability density function of | -//| of the Gamma distribution with shape parameters a and b. | -//| | -//| Arguments: | -//| x : Random variable | -//| a : Shape | -//| b : Scale | -//| 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 MathProbabilityDensityGamma(const double x,const double a,const double b,const bool log_mode,int &error_code) - { -//--- 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 negative x - if(x<=0) - return TailLog0(true,log_mode); -//--- calculate log Gamma density - double log_result=(a-1.0)*MathLog(x)-(x/b)-MathGammaLog(a)-a*MathLog(b); - if(log_mode==true) - return(log_result); -//--- return Gamma density - return MathExp(log_result); - } -//+------------------------------------------------------------------+ -//| Gamma probability density function (PDF) | -//+------------------------------------------------------------------+ -//| The function returns the probability density function of | -//| of the Gamma distribution with shape parameters a and b. | -//| | -//| Arguments: | -//| x : Random variable | -//| a : Shape | -//| b : Scale | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The probability density evaluated at x. | -//+------------------------------------------------------------------+ -double MathProbabilityDensityGamma(const double x,const double a,const double b,int &error_code) - { - return MathProbabilityDensityGamma(x,a,b,false,error_code); - } -//+------------------------------------------------------------------+ -//| Gamma probability density function (PDF) | -//+------------------------------------------------------------------+ -//| The function calculates the Gamma probability density function | -//| with parameters a and b for values in x[] array. | -//| | -//| Arguments: | -//| x : Array with random variables | -//| a : Shape | -//| b : Scale | -//| log_mode : Logarithm mode flag,if true it calculates Log values| -//| result : Output array for calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathProbabilityDensityGamma(const double &x[],const double a,const double b,const bool log_mode,double &result[]) - { -//--- check parameters - 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) - { - //--- calculate log Gamma density - double log_result=(a-1.0)*MathLog(x_arg)-(x_arg/b)-MathGammaLog(a)-a*MathLog(b); - if(log_mode==true) - result[i]=log_result; - else - result[i]=MathExp(log_result); - } - else - result[i]=TailLog0(true,log_mode); - } - return true; - } -//+------------------------------------------------------------------+ -//| Gamma probability density function (PDF) | -//+------------------------------------------------------------------+ -//| The function calculates the Gamma probability density function | -//| with parameters a and b for values from x[] array. | -//| | -//| Arguments: | -//| x : Array with random variables | -//| a : Shape | -//| b : Scale | -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathProbabilityDensityGamma(const double &x[],const double a,const double b,double &result[]) - { - return MathProbabilityDensityGamma(x,a,b,false,result); - } -//+------------------------------------------------------------------+ -//| Gamma cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function returns the cumulative distribution function of the | -//| Gamma distribution with parameters a and b. | -//| | -//| Arguments: | -//| x : The desired quantile | -//| a : Shape | -//| b : Scale | -//| 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 Gamma cumulative distribution function | -//| with parameters a and b, evaluated at x. | -//+------------------------------------------------------------------+ -double MathCumulativeDistributionGamma(const double x,const double a,const double b,const bool tail,const bool log_mode,int &error_code) - { -//--- check NaN - 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 using Incomplete Gamma function and take into account round-off errors - double cdf=MathMin(MathGammaIncomplete(x/b,a),1.0); - return TailLogValue(cdf,tail,log_mode); - } -//+------------------------------------------------------------------+ -//| Gamma cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function returns the cumulative distribution function of the | -//| Gamma distribution with parameters a and b. | -//| | -//| Arguments: | -//| x : The desired quantile | -//| a : Shape | -//| b : Scale | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The value of the Gamma cumulative distribution function | -//| with parameters a and b, evaluated at x. | -//+------------------------------------------------------------------+ -double MathCumulativeDistributionGamma(const double x,const double a,const double b,int &error_code) - { - return MathCumulativeDistributionGamma(x,a,b,true,false,error_code); - } -//+------------------------------------------------------------------+ -//| Gamma cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function calculates the values of the Gamma cumulative | -//| distribution function with given a and b for values in x[] array.| -//| | -//| Arguments: | -//| x : Array with random variables | -//| a : Shape | -//| b : Scale | -//| tail : Flag to calculate lower tail | -//| log_mode : Logarithm mode flag,if true it calculates Log values| -//| resut : Output array for calculated values | -//| | -//| Return value: | -//| true if successul, otherwise false. | -//+------------------------------------------------------------------+ -bool MathCumulativeDistributionGamma(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; i1.0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } - error_code=ERR_OK; -//--- case probability==0 - if(prob==0.0) - return 0.0; -//--- case probability==1 - if(prob==1.0) - { - error_code=ERR_RESULT_INFINITE; - return QPOSINF; - } -//--- calculate quantile - double quantile=MathInverseGammaIncomplete(a,1.0-prob)*b; - if(!MathIsValidNumber(quantile)) - error_code=ERR_NON_CONVERGENCE; -//--- - return(quantile); - } -//+------------------------------------------------------------------+ -//| Gamma distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function returns the inverse cumulative distribution | -//| function of the Gamma distribution with parameters a and b | -//| for the desired probability. | -//| | -//| Arguments: | -//| probability : The desired probability | -//| a : Shape | -//| b : Scale | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The value of the inverse cumulative distribution function | -//| of the Gamma distribution with parameters a and b. | -//+------------------------------------------------------------------+ -double MathQuantileGamma(const double probability,const double a,const double b,int &error_code) - { - return MathQuantileGamma(probability,a,b,true,false,error_code); - } -//+------------------------------------------------------------------+ -//| Gamma distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function returns the inverse cumulative distribution | -//| function of the Gamma distribution with parameters a and b | -//| for values from the probability[] array. | -//| | -//| Arguments: | -//| probability : Array with probabilities | -//| a : Shape | -//| b : Scale | -//| tail : Flag to calculate lower tail | -//| log_mode : Logarithm mode,if true it calculates for Log values| -//| result : Output array for calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathQuantileGamma(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); - - const double eps=10E-18; - double max_h=MathSqrt(eps); - const int max_iterations=1000; - - for(int i=0; i1.0) - return false; - - //--- case probability==0 - if(prob==0.0) - result[i]=0.0; - else - //--- case probability==1 - if(prob==1.0) - result[i]=QPOSINF; - else - { - double quantile=MathInverseGammaIncomplete(a,1.0-prob)*b; - if(MathIsValidNumber(quantile)) - result[i]=quantile; - else - return false; - } - } - return true; - } -//+------------------------------------------------------------------+ -//| Gamma distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function returns the inverse cumulative distribution | -//| function of the Gamma distribution with parameters a and b | -//| for the desired probability. | -//| | -//| Arguments: | -//| probability : The desired probability | -//| a : Shape | -//| b : Scale | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathQuantileGamma(const double &probability[],const double a,const double b,double &result[]) - { - return MathQuantileGamma(probability,a,b,true,false,result); - } -//+------------------------------------------------------------------+ -//| Random variate from the Gamma distribution | -//+------------------------------------------------------------------+ -//| Compute the random variable from the Gamma distribution | -//| with parameters a and b. | -//| | -//| Arguments: | -//| a : Shape | -//| b : Scale | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The random value with Gamma distribution. | -//+------------------------------------------------------------------+ -//| Author: Robert Kern | -//+------------------------------------------------------------------+ -double MathRandomGamma(const double a,const double b) - { - double bb,c,U,V,X=0,Y; -//--- check shape - if(a==1.0) - { - //--- exponential - return -MathLog(1.0-MathRandomNonZero()); - } - else - if(a<1.0) - { - for(;;) - { - U=MathRandomNonZero(); - //--- exponential - V=-MathLog(1.0-MathRandomNonZero()); - - if(U<=1.0-a) - { - X=MathPow(U,1.0/a); - if(X<=V) - return b*X; - } - else - { - Y = -MathLog((1-U)/a); - X = MathPow(1.0 - a + a*Y, 1.0/a); - if(X<=(V+Y)) - return(b*X); - } - } - } - else - { - bb= a-1.0/3.0; - c = 1.0/MathSqrt(9*bb); - for(;;) - { - do - { - //--- generate normal random variate - double f,x1,x2,r2; - do - { - x1=2.0*MathRandomNonZero()-1.0; - x2=2.0*MathRandomNonZero()-1.0; - r2=x1*x1+x2*x2; - } - while(r2>=1.0 || r2==0.0); - //--- Box-Muller transform - f=MathSqrt(-2.0*MathLog(r2)/r2); - X=f*x2; - - V=1.0+c*X; - } - while(V<=0.0); - - V = V*V*V; - U = MathRandomNonZero(); - - if(U<1.0-0.0331*(X*X)*(X*X)) - return(bb*V*b); - - if(MathLog(U)<0.5*X*X+bb*(1.0-V+MathLog(V))) - return(bb*V*b); - } - } - return(X*b); - } -//+------------------------------------------------------------------+ -//| Random variate from the Gamma distribution | -//+------------------------------------------------------------------+ -//| Compute the random variable from the Gamma distribution | -//| with parameters a and b. | -//| | -//| Arguments: | -//| a : Shape | -//| b : Scale | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The random value with Gamma distribution. | -//+------------------------------------------------------------------+ -double MathRandomGamma(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; - return MathRandomGamma(a,b); - } -//+------------------------------------------------------------------+ -//| Random variate from the Gamma distribution | -//+------------------------------------------------------------------+ -//| The function generates random variables from the Gamma | -//| distribution with parameters a and b. | -//| | -//| Arguments: | -//| a : First shape parameter (a>0) | -//| b : Second shape parameter (b>0) | -//| data_count : Number of values needed | -//| result : Output array for random values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathRandomGamma(const double a,const double b,const int data_count,double &result[]) - { - if(data_count<=0) - return false; -//--- 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 values - ArrayResize(result,data_count); - for(int i=0; i1.0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } -//--- check x - if(x!=MathRound(x)) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } - - error_code=ERR_OK; - if(x<0) - return TailLog0(true,log_mode); - - if(p==1.0) - { - if(x==0.0) - return TailLog1(true,log_mode); - else - return TailLog0(true,log_mode); - } -//--- return geometric density - return TailLogValue(p*MathPow(1.0-p,x),true,log_mode); - } -//+------------------------------------------------------------------+ -//| Geometric mass function (PDF) | -//+------------------------------------------------------------------+ -//| The function returns the probability mass function of | -//| the Geometric distribution with parameter p. | -//| | -//| Arguments: | -//| x : Random variable | -//| p : Probability parameter | -//| 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 MathProbabilityDensityGeometric(const double x,const double p,int &error_code) - { - return MathProbabilityDensityGeometric(x,p,false,error_code); - } -//+------------------------------------------------------------------+ -//| Geometric mass function (PDF) | -//+------------------------------------------------------------------+ -//| The function calculates the probability mass function of | -//| the Geometric distribution with parameter p for values in x[]. | -//| | -//| Arguments: | -//| x : Array with random variables | -//| p : Probability parameter | -//| log_mode : Logarithm mode, if true it calculates Log values | -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathProbabilityDensityGeometric(const double &x[],const double p,const bool log_mode,double &result[]) - { -//--- check NaN - if(!MathIsValidNumber(p)) - return false; -//--- check probability - if(p<=0.0 || p>1.0) - return false; - - int data_count=ArraySize(x); - if(data_count==0) - return false; - - int error_code=0; - ArrayResize(result,data_count); - -//--- special case p==1.0 - if(p==1.0) - { - for(int i=0; i1.0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } - error_code=ERR_OK; -//--- check x - if(x<0) - return TailLog0(true,log_mode); -//--- check p - if(p==1.0) - { - if(x==0.0) - return TailLog1(true,log_mode); - else - return TailLog0(true,log_mode); - } -//--- calculate cdf and take into account round-off errors for probability - double cdf=1.0-MathPow(1.0-p,x+1.0); - return TailLogValue(MathMin(cdf,1.0),tail,log_mode); - } -//+------------------------------------------------------------------+ -//| Geometric cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function returns the cumulative distribution function of | -//| the Geometric distribution with parameter p. | -//| | -//| Arguments: | -//| x : The desired quantile | -//| p : Probability parameter | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The value of the Geometric cumulative distribution function | -//| with parameter p, evaluated at x. | -//+------------------------------------------------------------------+ -double MathCumulativeDistributionGeometric(const double x,const double p,int &error_code) - { - return MathCumulativeDistributionGeometric(x,p,true,false,error_code); - } -//+------------------------------------------------------------------+ -//| Geometric cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function calculates the cumulative distribution function of | -//| the Geometric distribution with parameter p for values in x[]. | -//| | -//| Arguments: | -//| x : Array with random variables | -//| p : Probability parameter | -//| 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 MathCumulativeDistributionGeometric(const double &x[],const double p,const bool tail,const bool log_mode,double &result[]) - { -//--- check NaN - if(!MathIsValidNumber(p)) - return false; -//--- check probability range - if(p<=0.0 || p>1.0) - return false; - - int data_count=ArraySize(x); - if(data_count==0) - return false; - - int error_code=0; - ArrayResize(result,data_count); - -//--- special case p==1.0 - if(p==1.0) - { - for(int i=0; i=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; - } - - error_code=ERR_OK; -//--- +infinity - if(prob==1.0) - return QPOSINF; - if(prob==0.0) - return 0.0; - - double res=MathCeil(-1.0+MathLog(1.0-prob)/MathLog(1.0-p)-1e-12); - if(res<0) - res=0; -//--- return quantile - return res; - } -//+------------------------------------------------------------------+ -//| Geometric distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function returns the inverse cumulative distribution | -//| function of the Geometric distribution with parameter p | -//| for the desired probability. | -//| | -//| Arguments: | -//| probability : The desired probability | -//| p : Probability parameter | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The value of the Geometric quantile function for probability. | -//+------------------------------------------------------------------+ -double MathQuantileGeometric(const double probability,const double p,int &error_code) - { - return MathQuantileGeometric(probability,p,true,false,error_code); - } -//+------------------------------------------------------------------+ -//| Geometric distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function calculates the inverse cumulative distribution | -//| function of the Geometric distribution with parameter p | -//| for values form the probability[] array. | -//| | -//| Arguments: | -//| probability : Array with probabilities | -//| p : Probability parameter | -//| 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 MathQuantileGeometric(const double &probability[],const double p,const bool tail,const bool log_mode,double &result[]) - { -//--- check parameters - if(!MathIsValidNumber(p)) - return false; -//--- check p range - if(p<=0.0 || p>=1.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; - - //--- +infinity - if(prob==1.0) - result[i]=QPOSINF; - if(prob==0.0) - result[i]=0.0; - else - { - double res=MathCeil(-1.0+MathLog(1.0-prob)/MathLog(1.0-p)-1e-12); - if(res<0) - res=0; - result[i]=res; - } - } - return true; - } -//+------------------------------------------------------------------+ -//| Geometric distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function calculates the inverse cumulative distribution | -//| function of the Geometric distribution with parameter p | -//| for values from the probability[] array. | -//| | -//| Arguments: | -//| probability : Array with probabilities | -//| p : Probability parameter | -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathQuantileGeometric(const double &probability[],const double p,double &result[]) - { - return MathQuantileGeometric(probability,p,true,false,result); - } -//+------------------------------------------------------------------+ -//| Random variate from the Geometric distribution | -//+------------------------------------------------------------------+ -//| Computes the random variable from the Geometric distribution | -//| with parameter p. | -//| | -//| Arguments: | -//| p : Probability parameter | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The random value with Geometric distribution. | -//+------------------------------------------------------------------+ -double MathRandomGeometric(const double p,int &error_code) - { -//--- check parameters - if(!MathIsValidNumber(p)) - { - error_code=ERR_ARGUMENTS_NAN; - return QNaN; - } -//--- check probability range - if(p<0.0 || p>1.0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } - - error_code=ERR_OK; -//--- generate random number - double rnd=MathRandomNonZero(); - double res=MathCeil(-1.0+MathLog(rnd)/MathLog(1.0-p)-1e-12); - if(res<0) - res=0; - return res; - } -//+------------------------------------------------------------------+ -//| Random variate from the Geometric distribution | -//+------------------------------------------------------------------+ -//| Generates random variables from the Geometric distribution with | -//| parameter p. | -//| | -//| Arguments: | -//| p : Probability parameter | -//| data_count : Number of values needed | -//| result : Output array with random values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathRandomGeometric(const double p,const int data_count,double &result[]) - { -//--- check parameters - if(!MathIsValidNumber(p)) - return false; -//--- check probability range - if(p<0.0 || p>1.0) - return false; -//--- 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 =(1.0/p)-1; - variance=(1.0-p)/(p*p); - skewness=(2.0-p)/MathSqrt(1.0-p); - kurtosis=(p*p-6*p+6)/(1-p); -//--- successful - return true; - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Stat/Hypergeometric.mqh b/Include/Math/Stat/Hypergeometric.mqh deleted file mode 100644 index 25ab318..0000000 --- a/Include/Math/Stat/Hypergeometric.mqh +++ /dev/null @@ -1,754 +0,0 @@ -//+------------------------------------------------------------------+ -//| Hypergeometric.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include "Math.mqh" - -//+------------------------------------------------------------------+ -//| Hypergeometric probability mass function (PDF) | -//+------------------------------------------------------------------+ -//| The function returns the probability mass function | -//| of the Hypergeometric distribution with parameters m,n,k. | -//| f(x,m,k,n)=C(k,x)*C(m-k,n-x)/C(m,n) | -//| where binomial coefficient C(n,k)=n!/(k!*(n-k)! | -//| | -//| Arguments: | -//| x : The desired number of objects | -//| m : Size of the population | -//| k : Number of items with the desired characteristic | -//| in the population | -//| n : Number of samples drawn | -//| log_mode : Logarithm mode flag, if true it returns Log values | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The probability mass function, evaluated at x. | -//+------------------------------------------------------------------+ -double MathProbabilityDensityHypergeometric(const double x,const double m,const double k,const double n,const bool log_mode,int &error_code) - { -//--- check NaN - if(!MathIsValidNumber(x) || !MathIsValidNumber(m) || !MathIsValidNumber(k) || !MathIsValidNumber(n)) - { - error_code=ERR_ARGUMENTS_NAN; - return(QNaN); - } -//--- m,k,n must be integer - if(m!=MathRound(m) || k!=MathRound(k) || n!=MathRound(n)) - { - error_code=ERR_ARGUMENTS_INVALID; - return(QNaN); - } -//--- m,k,n must be positive - if(m<0 || k<0 || n<0) - { - error_code=ERR_ARGUMENTS_INVALID; - return(QNaN); - } -//--- check ranges - if(n>m || k>m) - { - error_code=ERR_ARGUMENTS_INVALID; - return(QNaN); - } - - error_code=ERR_OK; -//--- check ranges - if(x>n) - return TailLog0(true,log_mode); - if(x>k || m-k-n+x+1<=0) - return TailLog0(true,log_mode); -//--- calculate log binomial coefficients - double log_pdf=MathBinomialCoefficientLog(k,x)+MathBinomialCoefficientLog(m-k,n-x)-MathBinomialCoefficientLog(m,n); - if(log_mode==true) - return log_pdf; -//--- return hypergeometric density - return MathExp(log_pdf); - } -//+------------------------------------------------------------------+ -//| Hypergeometric probability mass function (PDF) | -//+------------------------------------------------------------------+ -//| The function returns the probability mass function | -//| of the Hypergeometric distribution with parameters m,n,k. | -//| f(x,m,k,n)=C(k,x)*C(m-k,n-x)/C(m,n) | -//| where binomial coefficient C(n,k)=n!/(k!*(n-k)! | -//| | -//| Arguments: | -//| x : The desired number of objects | -//| m : Size of the population | -//| k : Number of items with the desired characteristic | -//| in the population | -//| n : Number of samples drawn | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The probability mass function, evaluated at x. | -//+------------------------------------------------------------------+ -double MathProbabilityDensityHypergeometric(const double x,const double m,const double k,const double n,int &error_code) - { - return MathProbabilityDensityHypergeometric(x,m,k,n,false,error_code); - } -//+------------------------------------------------------------------+ -//| Hypergeometric probability mass function (PDF) | -//+------------------------------------------------------------------+ -//| The function calculates the probability mass function of the | -//| Hypergeometric distribution with parameter m,k,n for values in x.| -//| | -//| Arguments: | -//| x : Array with random variables | -//| x : The desired number of objects | -//| m : Size of the population | -//| k : Number of items with the desired characteristic | -//| in the population | -//| n : Number of samples drawn | -//| log_mode : Logarithm mode, if true it calculates Log values | -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathProbabilityDensityHypergeometric(const double &x[],const double m,const double k,const double n,const bool log_mode,double &result[]) - { -//--- check NaN - if(!MathIsValidNumber(m) || !MathIsValidNumber(k) || !MathIsValidNumber(n)) - return false; -//--- m,k,n must be integer - if(m!=MathRound(m) || k!=MathRound(k) || n!=MathRound(n)) - return false; -//--- m,k,n must be positive - if(m<0 || k<0 || n<0) - return false; -//--- check ranges - if(n>m || k>m) - return false; - - int data_count=ArraySize(x); - if(data_count==0) - return false; - - double m_k=m-k; - int error_code=0; - ArrayResize(result,data_count); - for(int i=0; in) - result[i]=TailLog0(true,log_mode); - else - //--- check ranges - if(x_arg>k || m_k-n+x_arg+1<=0) - result[i]=TailLog0(true,log_mode); - else - { - //--- calculate log binomial coefficients - double log_pdf=MathBinomialCoefficientLog(k,x_arg)+MathBinomialCoefficientLog(m_k,n-x_arg)-MathBinomialCoefficientLog(m,n); - if(log_mode==true) - result[i]=log_pdf; - else - result[i]=MathExp(log_pdf); - } - } - return true; - } -//+------------------------------------------------------------------+ -//| Hypergeometric probability mass function (PDF) | -//+------------------------------------------------------------------+ -//| The function calculates the probability mass function of the | -//| Hypergeometric distribution with parameter m,k,n for values in x.| -//| | -//| Arguments: | -//| x : Array with random variables | -//| x : The desired number of objects | -//| m : Size of the population | -//| k : Number of items with the desired characteristic | -//| in the population | -//| n : Number of samples drawn | -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathProbabilityDensityHypergeometric(const double &x[],const double m,const double k,const double n,double &result[]) - { - return MathProbabilityDensityHypergeometric(x,m,k,n,false,result); - } -//+------------------------------------------------------------------+ -//| Hypergeometric cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function returns the probability that an observation | -//| from the Hypergeometric distribution with parameters m,n,k | -//| is less than or equal to x. | -//| | -//| Arguments: | -//| x : The desired number of objects | -//| m : Size of the population | -//| k : Number of items with the desired characteristic | -//| in the population | -//| n : Number of samples drawn | -//| 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 Hypergeometric cumulative distribution function | -//| with parameters m,n,k, evaluated at x. | -//+------------------------------------------------------------------+ -//| Based on algorithm by John Burkardt | -//+------------------------------------------------------------------+ -double MathCumulativeDistributionHypergeometric(const double x,const double m,const double k,const double n,const bool tail,const bool log_mode,int &error_code) - { -//--- check NaN - if(!MathIsValidNumber(x) || !MathIsValidNumber(m) || !MathIsValidNumber(k) || !MathIsValidNumber(n)) - { - error_code=ERR_ARGUMENTS_NAN; - return QNaN; - } -//--- m,k,n,x must be integer - if(m!=MathRound(m) || k!=MathRound(k) || n!=MathRound(n) || x!=MathRound(x)) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } -//--- m,k,n,x must be positive - if(m<0 || k<0 || n<0 || x<0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } -//--- check ranges - if(n>m || k>m) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } - - error_code=ERR_OK; - if(x>=n || x>=k) - return TailLog1(tail,log_mode); -//--- calculate cdf - double pdf = MathExp(MathBinomialCoefficientLog(m-k,n)-MathBinomialCoefficientLog(m,n)); - double cdf = pdf; - double coef=m-k-n+1; - for(int j=0; j<=x-1; j++) - { - pdf = pdf*(k-j)*(n-j)/((j+1)*(coef+j)); - cdf = cdf + pdf; - } - return TailLogValue(MathMin(cdf,1.0),tail,log_mode); - } -//+------------------------------------------------------------------+ -//| Hypergeometric cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function returns the probability that an observation | -//| from the Hypergeometric distribution with parameters m,n,k | -//| is less than or equal to x. | -//| | -//| Arguments: | -//| x : The desired number of objects | -//| m : Size of the population | -//| k : Number of items with the desired characteristic | -//| in the population | -//| n : Number of samples drawn | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The value of the Hypergeometric cumulative distribution function | -//| with parameters m,n,k, evaluated at x. | -//+------------------------------------------------------------------+ -double MathCumulativeDistributionHypergeometric(const double x,const double m,const double k,const double n,int &error_code) - { - return MathCumulativeDistributionHypergeometric(x,m,k,n,true,false,error_code); - } -//+------------------------------------------------------------------+ -//| Hypergeometric cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function calculates the cumulative distribution function of | -//| the Hypergeometric distribution with parameters m,k,n for | -//| the values in x[] array. | -//| | -//| Arguments: | -//| x : Array with random variables | -//| m : Size of the population | -//| k : Number of items with the desired characteristic | -//| in the population | -//| n : Number of samples drawn | -//| 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. | -//+------------------------------------------------------------------+ -//| Based on algorithm by John Burkardt | -//+------------------------------------------------------------------+ -bool MathCumulativeDistributionHypergeometric(const double &x[],const double m,const double k,const double n,const bool tail,const bool log_mode,double &result[]) - { -//--- check NaN - if(!MathIsValidNumber(m) || !MathIsValidNumber(k) || !MathIsValidNumber(n)) - return false; -//--- m,k,n,x must be integer - if(m!=MathRound(m) || k!=MathRound(k) || n!=MathRound(n)) - return false; -//--- m,k,n must be positive - if(m<0 || k<0 || n<0) - return false; -//--- check ranges - if(n>m || k>m) - return false; - - int data_count=ArraySize(x); - if(data_count==0) - return false; - - double coef=m-k-n+1; - - ArrayResize(result,data_count); - for(int i=0; i=n || x_arg>=k) - result[i]=TailLog1(tail,log_mode); - else - { - //--- calculate cdf - double pdf = MathExp(MathBinomialCoefficientLog(m-k,n)-MathBinomialCoefficientLog(m,n)); - double cdf = pdf; - for(int j=0; j<=x_arg-1; j++) - { - pdf = pdf*(k-j)*(n-j)/((j+1)*(coef+j)); - cdf = cdf + pdf; - } - result[i]=TailLogValue(MathMin(cdf,1.0),tail,log_mode); - } - } - return true; - } -//+------------------------------------------------------------------+ -//| Hypergeometric cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function calculates the cumulative distribution function of | -//| the Hypergeometric distribution with parameters m,k,n for | -//| the values in x[] array. | -//| | -//| Arguments: | -//| x : Array with random variables | -//| m : Size of the population | -//| k : Number of items with the desired characteristic | -//| in the population | -//| n : Number of samples drawn | -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathCumulativeDistributionHypergeometric(const double &x[],const double m,const double k,const double n,double &result[]) - { - return MathCumulativeDistributionHypergeometric(x,m,k,n,true,false,result); - } -//+------------------------------------------------------------------+ -//| Hypergeometric distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| Computes the inverse cumulative distribution function of the | -//| Hypergeometric distribution with parameters m,n,k for the | -//| desired probability. | -//| | -//| Arguments: | -//| probability : The probability | -//| m : Size of the population | -//| k : Number of items with the desired characteristic | -//| in the population | -//| n : Number of samples drawn | -//| 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 smallest value x, such that the hypergeometric CDF(x) | -//| equals or exceeds the desired probability. | -//+------------------------------------------------------------------+ -//| Based on algorithm by John Burkardt | -//+------------------------------------------------------------------+ -double MathQuantileHypergeometric(const double probability,const double m,const double k,const double n,const bool tail,const bool log_mode,int &error_code) - { -//--- check NaN - if(!MathIsValidNumber(probability) || !MathIsValidNumber(m) || !MathIsValidNumber(k) || !MathIsValidNumber(n)) - { - error_code=ERR_ARGUMENTS_NAN; - return QNaN; - } -//--- m,k,n,x must be integer - if(m!=MathRound(m) || k!=MathRound(k) || n!=MathRound(n)) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } -//--- m,k,n must be positive - if(m<0 || k<0 || n<0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } -//--- check ranges - if(n>m || k>m) - { - 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 probability - if(prob==0) - return 0.0; - if(prob==1.0) - return QPOSINF; - - int max_terms=1000; - prob*=1-1000*DBL_EPSILON; - double m_k=m-k; - double pdf = MathExp(MathBinomialCoefficientLog(m_k,n)-MathBinomialCoefficientLog(m,n)); - double cdf = pdf; - double coef=m_k-n+1; - int j=0; - while(cdfm || k>m) - return false; - - int data_count=ArraySize(probability); - if(data_count==0) - return false; - - int max_terms=1000; - double m_k=m-k; - double pdf0= MathExp(MathBinomialCoefficientLog(m_k,n)-MathBinomialCoefficientLog(m,n)); - double coef=m_k-n+1; - - ArrayResize(result,data_count); - for(int i=0; i1.0) - return false; - - //--- check probability - if(prob==0.0) - result[i]=0.0; - else - if(prob==1.0) - result[i]=QPOSINF; - else - { - prob*=1-1000*DBL_EPSILON; - double pdf = pdf0; - double cdf = pdf; - int j=0; - while(cdfm || k>m) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } - - error_code=ERR_OK; -//--- generate random number - double prob=MathRandomNonZero(); - prob*=1-1000*DBL_EPSILON; - int max_terms=1000; - double m_k=m-k; - double coef=m_k-n+1; - double pdf= MathExp(MathBinomialCoefficientLog(m_k,n)-MathBinomialCoefficientLog(m,n)); - double cdf= pdf; - int j=0; - while(cdfm || k>m) - return false; -//--- prepare coefficients - int max_terms=1000; - double m_k=m-k; - double coef=m_k-n+1; - double pdf0= MathExp(MathBinomialCoefficientLog(m_k,n)-MathBinomialCoefficientLog(m,n)); -//--- prepare output array and calculate random values - ArrayResize(result,data_count); - for(int i=0; im || k>m) - { - error_code=ERR_ARGUMENTS_INVALID; - return false; - } - - error_code=ERR_OK; -//--- calculate moments - mean =n*k/m; - variance=k*n*(1-k/m)*(m-n)/(m*(m-1)); - skewness=MathSqrt(m-1)*(m-2*k)*(m-2*n)/((m-2)*MathSqrt(k*n*(m-k)*(m-n))); - kurtosis=(m-1)*m*m/(k*n*(m-3)*(m-2)*(m-k)*(m-n)); - kurtosis*=3*k*(m-k)*(m*m*(n-2)-m*n*n+6*n*(m-n))/(m*m)-6*n*(m-n)+m*(m+1); - kurtosis-=3; -//--- successful - return true; - } -//+------------------------------------------------------------------+ diff --git a/Include/Math/Stat/Logistic.mqh b/Include/Math/Stat/Logistic.mqh deleted file mode 100644 index 0ead3fc..0000000 --- a/Include/Math/Stat/Logistic.mqh +++ /dev/null @@ -1,592 +0,0 @@ -//+------------------------------------------------------------------+ -//| Logistic.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include "Math.mqh" - -//+------------------------------------------------------------------+ -//| Logistic distribution density function (PDF) | -//+------------------------------------------------------------------+ -//| The function returns the probability density function of | -//| the Logistic distribution with parameters mu and sigma. | -//| f(x,mu,sigma)=exp[-(x-mu)/sigma]/(sigma*(exp[-(x-mu)/sigma])^2) | -//| | -//| Arguments: | -//| x : Random variable | -//| mu : Mean | -//| sigma : Scale 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 MathProbabilityDensityLogistic(const double x,const double mu,const double sigma,const bool log_mode,int &error_code) - { -//--- check parameters - if(!MathIsValidNumber(x) || !MathIsValidNumber(mu) || !MathIsValidNumber(sigma)) - { - error_code=ERR_ARGUMENTS_NAN; - return QNaN; - } -//--- check sigma - if(sigma<=0.0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } -//--- prepare argument - double y=(x-mu)/sigma; -//--- check result - if(!MathIsValidNumber(y)) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } - - error_code=ERR_OK; - -//--- calculate exponents - double e=MathExp(-y); - double e1=(1+e); - double pdf=e/(sigma*(e1*e1)); - if(log_mode==true) - return MathLog(pdf); -//--- return logistic density - return pdf; - } -//+------------------------------------------------------------------+ -//| Logistic distribution density function (PDF) | -//+------------------------------------------------------------------+ -//| The function returns the probability density function of | -//| the Logistic distribution with parameters mu and sigma. | -//| f(x,mu,sigma)=exp[-(x-mu)/sigma]/(sigma*(exp[-(x-mu)/sigma])^2) | -//| | -//| Arguments: | -//| x : Random variable | -//| mu : Mean | -//| sigma : Scale parameter | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The probability density evaluated at x. | -//+------------------------------------------------------------------+ -double MathProbabilityDensityLogistic(const double x,const double mu,const double sigma,int &error_code) - { - return MathProbabilityDensityLogistic(x,mu,sigma,false,error_code); - } -//+------------------------------------------------------------------+ -//| Logistic distribution density function (PDF) | -//+------------------------------------------------------------------+ -//| The function calculates the probability density function of | -//| the Logistic distribution with parameters mu and sigma | -//| for values in x[] array. | -//| | -//| Arguments: | -//| x : Array with random variables | -//| mu : Mean | -//| sigma : Scale parameter | -//| log_mode : Logarithm mode flag, if true it returns Log values | -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathProbabilityDensityLogistic(const double &x[],const double mu,const double sigma,const bool log_mode,double &result[]) - { -//--- check parameters - if(!MathIsValidNumber(mu) || !MathIsValidNumber(sigma)) - return false; -//--- check sigma - if(sigma<=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; i1.0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } - - if(prob==0.0 || prob==1.0) - { - if(sigma==0.0) - { - error_code=ERR_OK; - return mu; - } - else - { - error_code=ERR_RESULT_INFINITE; - if(prob==0.0) - return QNEGINF; - else - return QPOSINF; - } - } - - error_code=ERR_OK; -//--- calculate quantile - double q=MathLog(prob/(1.0-prob)); -//--- return rescaled/shifted quantile - return mu+sigma*q; - } -//+------------------------------------------------------------------+ -//| Logistic distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function returns the inverse cumulative distribution | -//| function of the Logistic distribution with parameters mu | -//| and sigma for the desired probability. | -//| | -//| Arguments: | -//| probability : The desired probability | -//| mu : Mean | -//| sigma : Scale parameter | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The value of the inverse cumulative distribution function | -//| of the Logistic distribution with parameters mu and sigma. | -//+------------------------------------------------------------------+ -double MathQuantileLogistic(const double probability,const double mu,const double sigma,int &error_code) - { - return MathQuantileLogistic(probability,mu,sigma,true,false,error_code); - } -//+------------------------------------------------------------------+ -//| Logistic distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function calculates the inverse cumulative distribution | -//| function of the Logistic distribution with parameters mu and | -//| sigma for values from the probability[] array. | -//| | -//| Arguments: | -//| probability : Array with probabilities | -//| mu : Mean | -//| sigma : Scale parameter | -//| 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 MathQuantileLogistic(const double &probability[],const double mu,const double sigma,const bool tail,const bool log_mode,double &result[]) - { -//--- check parameters - if(!MathIsValidNumber(mu) || !MathIsValidNumber(sigma)) - return false; -//--- check sigma - if(sigma<0.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; - - if(prob==0.0 || prob==1.0) - { - if(sigma==0.0) - result[i]=mu; - else - { - if(prob==0.0) - result[i]=QNEGINF; - else - result[i]=QPOSINF; - } - } - else - { - //--- calculate quantile - double q=MathLog(prob/(1.0-prob)); - //--- rescaled/shifted quantile - result[i]=mu+sigma*q; - } - } - return true; - } -//+------------------------------------------------------------------+ -//| Logistic distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function calculates the inverse cumulative distribution | -//| function of the Logistic distribution with parameters mu and | -//| sigma for values from the probability[] array. | -//| | -//| Arguments: | -//| probability : Array with probabilities | -//| mu : Mean | -//| sigma : Scale parameter | -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathQuantileLogistic(const double &probability[],const double mu,const double sigma,double &result[]) - { - return MathQuantileLogistic(probability,mu,sigma,true,false,result); - } -//+------------------------------------------------------------------+ -//| Random variate from the Logistic distribution | -//+------------------------------------------------------------------+ -//| Compute the random variable from the Logistic distribution | -//| with parameters mu and sigma. | -//| | -//| Arguments: | -//| mu : Mean | -//| sigma : Scale parameter | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The random value with Logistic distribution. | -//+------------------------------------------------------------------+ -double MathRandomLogistic(const double mu,const double sigma,int &error_code) - { -//--- check parameters - if(!MathIsValidNumber(mu) || !MathIsValidNumber(sigma)) - { - error_code=ERR_ARGUMENTS_NAN; - return QNaN; - } -//--- check sigma - if(sigma<0.0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } - - error_code=ERR_OK; -//--- check sigma - if(sigma==0.0) - return mu; -//--- generate random number - double rnd=MathRandomNonZero(); -//--- return value - return mu+sigma*MathLog(rnd/(1.0-rnd)); - } -//+------------------------------------------------------------------+ -//| Random variate from the Logistic distribution | -//+------------------------------------------------------------------+ -//| Generates random variables from the Logistic distribution | -//| with parameters mu and sigma. | -//| | -//| Arguments: | -//| mu : Mean | -//| sigma : Scale parameter | -//| data_count : Number of values needed | -//| result : Output array with random values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathRandomLogistic(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.0) - return false; - -//--- prepare output array - ArrayResize(result,data_count); -//--- check sigma - if(sigma==0.0) - { - for(int i=0; i=2*MathSqrt(DBL_MAX)) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } -//--- return lognormal density - return TailLogValue(M_1_SQRT_2PI*MathExp(-0.5*y*y)/(x*sigma),true,log_mode); - } -//+------------------------------------------------------------------+ -//| Lognormal density function (PDF) | -//+------------------------------------------------------------------+ -//| The function calculates the probability density function of | -//| the Lognormal distribution with parameters mu and sigma | -//| for values in x. | -//| | -//| Arguments: | -//| x : Array with random variables | -//| mu : Log mean | -//| sigma : Log standard deviation | -//| log_mode : Logarithm mode flag,if true it calculates Log values| -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathProbabilityDensityLognormal(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); - -//--- check case sigma==0 - if(sigma==0) - { - for(int i=0; i=2*MathSqrt(DBL_MAX)) - return false; - //--- return lognormal density - result[i]=TailLogValue(M_1_SQRT_2PI*MathExp(-0.5*y*y)/(x_arg*sigma),true,log_mode); - } - } - return true; - } -//+------------------------------------------------------------------+ -//| Lognormal density function (PDF) | -//+------------------------------------------------------------------+ -//| The function calculates the probability density function of | -//| the Lognormal distribution with parameters mu and sigma | -//| for values in x[] array. | -//| | -//| Arguments: | -//| x : Array with random variables | -//| mu : Log mean | -//| sigma : Log standard deviation | -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathProbabilityDensityLognormal(const double &x[],const double mu,const double sigma,double &result[]) - { - return MathProbabilityDensityLognormal(x,mu,sigma,false,result); - } -//+------------------------------------------------------------------+ -//| Lognormal density function (PDF) | -//+------------------------------------------------------------------+ -//| The function returns the probability density function | -//| of the Lognormal distribution with parameters mu and sigma. | -//| | -//| f(x,mu,sigma)=[1/(x*sigma*sqrt(2pi)]*exp(-(ln(x)-mu)/(2*sigma^2))| -//| | -//| Arguments: | -//| x : Random variable | -//| mu : Log mean | -//| sigma : Log standard deviation | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The probability density evaluated at x. | -//+------------------------------------------------------------------+ -double MathProbabilityDensityLognormal(const double x,const double mu,const double sigma,int &error_code) - { - return MathProbabilityDensityLognormal(x,mu,sigma,false,error_code); - } -//+------------------------------------------------------------------+ -//| Lognormal cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function returns the probability that an observation | -//| from the Lognormal distribution with parameters mu and sigma | -//| is less than or equal to x. | -//| | -//| Arguments: | -//| x : The desired quantile | -//| mu : Log mean | -//| sigma : Log standard deviation | -//| 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 Lognormal cumulative distribution function | -//| with parameters mu and sigma, evaluated at x. | -//+------------------------------------------------------------------+ -double MathCumulativeDistributionLognormal(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; -//--- check x - if(x<=0.0) - return TailLog0(tail,log_mode); -//--- return lognormal cdf using Normal cdf - return MathCumulativeDistributionNormal(MathLog(x),mu,sigma,tail,log_mode,error_code); - } -//+------------------------------------------------------------------+ -//| Lognormal cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function returns the probability that an observation | -//| from the Lognormal distribution with parameters mu and sigma | -//| is less than or equal to x. | -//| | -//| Arguments: | -//| x : The desired quantile | -//| mu : Log mean | -//| sigma : Log standard deviation | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The value of the Lognormal cumulative distribution function | -//| with parameters mu and sigma, evaluated at x. | -//+------------------------------------------------------------------+ -double MathCumulativeDistributionLognormal(const double x,const double mu,const double sigma,int &error_code) - { - return MathCumulativeDistributionLognormal(x,mu,sigma,true,false,error_code); - } -//+------------------------------------------------------------------+ -//| Lognormal cumulative distribution function (CDF) | -//+------------------------------------------------------------------+ -//| The function calculates the cumulative distribution function of | -//| the Lognormal distribution with parameters mu and sigma | -//| for values in x[] array. | -//| | -//| Arguments: | -//| x : Array with random variables | -//| mu : Log mean | -//| sigma : Log standard deviation | -//| 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 MathCumulativeDistributionLognormal(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; i1.0) - { - error_code=ERR_ARGUMENTS_INVALID; - return QNaN; - } - -//--- special cases exp(a+b-+infinity) - if(prob==0.0 || prob==1.0) - { - if(sigma==0.0) - { - error_code=ERR_OK; - return MathExp(mu); - } - else - if(prob==0.0) - { - if(sigma>0) - { - error_code=ERR_OK; - return 0.0; - } - else - if(sigma<0) - { - error_code=ERR_RESULT_INFINITE; - return QPOSINF; - } - } - else - { - if(sigma<0) - { - error_code=ERR_OK; - return 0.0; - } - else - if(sigma>0) - { - error_code=ERR_RESULT_INFINITE; - return QPOSINF; - } - } - } -//--- return lognormal quantile using Normal distribution - return MathExp(MathQuantileNormal(prob,mu,sigma,error_code)); - } -//+------------------------------------------------------------------+ -//| Lognormal distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function returns the inverse cumulative distribution | -//| function of Lognormal distribution with parameters mu and sigma | -//| for the desired probability. | -//| | -//| Arguments: | -//| probability : The desired probability | -//| mu : Log mean | -//| sigma : Log standard deviation | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The quantile value of the Lognormal distribution. | -//+------------------------------------------------------------------+ -double MathQuantileLognormal(const double probability,const double mu,const double sigma,int &error_code) - { - return MathQuantileLognormal(probability,mu,sigma,true,false,error_code); - } -//+------------------------------------------------------------------+ -//| Lognormal distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function calculates the inverse cumulative distribution | -//| function of the Lognormal distribution with parameters mu and | -//| sigma for values from the probability[] array. | -//| | -//| Arguments: | -//| probability : Array with probabilities | -//| mu : Log mean | -//| sigma : Log standard deviation | -//| tail : Flag to calculate lower tail | -//| log_mode : Logarithm mode,if true it calculates for Log values| -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathQuantileLognormal(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); - for(int i=0; i1.0) - return false; - - //--- special cases exp(a+b-+infinity) - if(prob==0.0 || prob==1.0) - { - if(sigma==0.0) - result[i]=MathExp(mu); - else - if(prob==0.0) - { - if(sigma>0) - result[i]=0.0; - else - if(sigma<0) - result[i]=QPOSINF; - } - else - { - if(sigma<0) - result[i]=0.0; - else - if(sigma>0) - result[i]=QPOSINF; - } - } - else - //--- calculate lognormal quantile using Normal distribution - result[i]=MathExp(MathQuantileNormal(prob,mu,sigma,error_code)); - } - return true; - } -//+------------------------------------------------------------------+ -//| Lognormal distribution quantile function (inverse CDF) | -//+------------------------------------------------------------------+ -//| The function calculates the inverse cumulative distribution | -//| function of the Lognormal distribution with parameters mu and | -//| sigma for values from the probability[] array. | -//| | -//| Arguments: | -//| probability : Array with probabilities | -//| mu : Log mean | -//| sigma : Log standard deviation | -//| result : Array with calculated values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathQuantileLognormal(const double &probability[],const double mu,const double sigma,double &result[]) - { - return MathQuantileLognormal(probability,mu,sigma,true,false,result); - } -//+------------------------------------------------------------------+ -//| Random variate from the Lognormal distribution | -//+------------------------------------------------------------------+ -//| Computes the random variable from the Lognormal distribution | -//| with parameters mu and sigma. | -//| | -//| Arguments: | -//| mu : Log mean | -//| sigma : Log standard deviation | -//| error_code : Variable for error code | -//| | -//| Return value: | -//| The random value with Lognormal distribution. | -//+------------------------------------------------------------------+ -double MathRandomLognormal(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; -//--- generate random number - double rnd=MathRandomNonZero(); -//--- - rnd=MathQuantileNormal(rnd,mu,sigma,true,false,error_code); - return MathExp(rnd); - } -//+------------------------------------------------------------------+ -//| Random variate from the Lognormal distribution | -//+------------------------------------------------------------------+ -//| Generates random variables from the Lognormal distribution | -//| with parameters mu and sigma. | -//| | -//| Arguments: | -//| mu : Log mean | -//| sigma : Log standard deviation | -//| data_count : Number of values needed | -//| result : Output array with random values | -//| | -//| Return value: | -//| true if successful, otherwise false. | -//+------------------------------------------------------------------+ -bool MathRandomLognormal(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); - int err_code=0; - for(int i=0; i|czU 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 Rkw}eSyk}WAzB(x8{{ewwz?lF5 diff --git a/Include/Math/Stat/NegativeBinomial.mqh b/Include/Math/Stat/NegativeBinomial.mqh deleted file mode 100644 index 165cbe5..0000000 --- a/Include/Math/Stat/NegativeBinomial.mqh +++ /dev/null @@ -1,643 +0,0 @@ -//+------------------------------------------------------------------+ -//| NegativeBinomial.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| 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 deleted file mode 100644 index bf4375d..0000000 --- a/Include/Math/Stat/NoncentralBeta.mqh +++ /dev/null @@ -1,955 +0,0 @@ -//+------------------------------------------------------------------+ -//| NoncentralBeta.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| 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 deleted file mode 100644 index beba9b1..0000000 --- a/Include/Math/Stat/NoncentralF.mqh +++ /dev/null @@ -1,790 +0,0 @@ -//+------------------------------------------------------------------+ -//| NoncentralF.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| 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 deleted file mode 100644 index 1cbdad7..0000000 --- a/Include/Math/Stat/NoncentralT.mqh +++ /dev/null @@ -1,1192 +0,0 @@ -//+------------------------------------------------------------------+ -//| NoncentralT.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| 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 deleted file mode 100644 index 65fd836..0000000 --- a/Include/Math/Stat/Normal.mqh +++ /dev/null @@ -1,914 +0,0 @@ -//+------------------------------------------------------------------+ -//| Normal.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| 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 deleted file mode 100644 index fc22b5f..0000000 --- a/Include/Math/Stat/Poisson.mqh +++ /dev/null @@ -1,791 +0,0 @@ -//+------------------------------------------------------------------+ -//| Poisson.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| 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 deleted file mode 100644 index e8d4569..0000000 --- a/Include/Math/Stat/T.mqh +++ /dev/null @@ -1,654 +0,0 @@ -//+------------------------------------------------------------------+ -//| T.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| 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 deleted file mode 100644 index 98d1a17..0000000 --- a/Include/Math/Stat/Uniform.mqh +++ /dev/null @@ -1,539 +0,0 @@ -//+------------------------------------------------------------------+ -//| Uniform.mqh | -//| Copyright 2016-2017, MetaQuotes Software Corp. | -//| 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 deleted file mode 100644 index a58bc02..0000000 --- a/Include/MovingAverages.mqh +++ /dev/null @@ -1,317 +0,0 @@ -//+------------------------------------------------------------------+ -//| MovingAverages.mqh | -//| Copyright 2009-2020, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ - -//+------------------------------------------------------------------+ -//| Simple Moving Average | -//+------------------------------------------------------------------+ -double SimpleMA(const int position,const int period,const double &price[]) - { - double result=0.0; -//--- check period - if(period>0 && period<=(position+1)) - { - 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 period - if(period>0 && period<=(position+1)) - { - if(position==period-1) - { - for(int i=0; i0 && period<=(position+1)) - { - double sum =0.0; - int wsum=0; - - for(int 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[]) - { -//--- check period - if(period<=1 || period>(rates_total-begin)) - return(0); -//--- save as_series flags - bool as_series_price=ArrayGetAsSeries(price); - bool as_series_buffer=ArrayGetAsSeries(buffer); - - ArraySetAsSeries(price,false); - ArraySetAsSeries(buffer,false); -//--- calculate start position - int start_position; - - if(prev_calculated==0) // first calculation or number of bars was changed - { - //--- set empty value for first bars - start_position=period+begin; - - for(int i=0; i(rates_total-begin)) - return(0); -//--- save and clear 'as_series' flags - bool as_series_price=ArrayGetAsSeries(price); - bool as_series_buffer=ArrayGetAsSeries(buffer); - - ArraySetAsSeries(price,false); - ArraySetAsSeries(buffer,false); -//--- calculate start position - int start_position; - double smooth_factor=2.0/(1.0+period); - - if(prev_calculated==0) // first calculation or number of bars was changed - { - //--- set empty value for first bars - for(int i=0; i(rates_total-begin)) - return(0); -//--- save as_series flags - bool as_series_price=ArrayGetAsSeries(price); - bool as_series_buffer=ArrayGetAsSeries(buffer); - - ArraySetAsSeries(price,false); - ArraySetAsSeries(buffer,false); -//--- calculate start position - int i,start_position; - - if(prev_calculated<=period+begin+2) // first calculation or number of bars was changed - { - //--- set empty value for first bars - start_position=period+begin; - - for(i=0; i(rates_total-begin)) - return(0); -//--- save as_series flags - bool as_series_price=ArrayGetAsSeries(price); - bool as_series_buffer=ArrayGetAsSeries(buffer); - - ArraySetAsSeries(price,false); - ArraySetAsSeries(buffer,false); -//--- calculate start position - int start_position; - - if(prev_calculated==0) // first calculation or number of bars was changed - { - //--- set empty value for first bars - start_position=period+begin; - - for(int i=0; i(rates_total-begin)) - return(0); -//--- save as_series flags - bool as_series_price=ArrayGetAsSeries(price); - bool as_series_buffer=ArrayGetAsSeries(buffer); - - ArraySetAsSeries(price,false); - ArraySetAsSeries(buffer,false); -//--- calculate start position - int start_position; - - if(prev_calculated==0) // first calculation or number of bars was changed - { - //--- set empty value for first bars - start_position=period+begin; - - for(int i=0; i - 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 deleted file mode 100644 index 355bead..0000000 --- a/Include/StdLibErr.mqh +++ /dev/null @@ -1,10 +0,0 @@ -//+------------------------------------------------------------------+ -//| 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 deleted file mode 100644 index adcb3d0..0000000 --- a/Include/Strings/String.mqh +++ /dev/null @@ -1,377 +0,0 @@ -//+------------------------------------------------------------------+ -//| 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 deleted file mode 100644 index 94d405b..0000000 --- a/Include/Tools/DateTime.mqh +++ /dev/null @@ -1,581 +0,0 @@ -//+------------------------------------------------------------------+ -//| 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 deleted file mode 100644 index 5181e2e..0000000 --- a/Include/Trade/AccountInfo.mqh +++ /dev/null @@ -1,397 +0,0 @@ -//+------------------------------------------------------------------+ -//| AccountInfo.mqh | -//| Copyright 2009-2020, 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 deleted file mode 100644 index 0f12b47..0000000 --- a/Include/Trade/DealInfo.mqh +++ /dev/null @@ -1,430 +0,0 @@ -//+------------------------------------------------------------------+ -//| DealInfo.mqh | -//| Copyright 2009-2020, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -//+------------------------------------------------------------------+ -//| 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(CDealInfo::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 - { -//--- 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 - { -//--- 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; - long tmp_long; -//--- set up - string symbol_name=this.Symbol(); - int digits=_Digits; - if(SymbolInfoInteger(symbol_name,SYMBOL_DIGITS,tmp_long)) - digits=(int)tmp_long; -//--- 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_name, - 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), - this.Comment()); - break; - - default: - str="unknown deal type "+(string)DealType(); - } -//--- 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 deleted file mode 100644 index 735033d..0000000 --- a/Include/Trade/HistoryOrderInfo.mqh +++ /dev/null @@ -1,472 +0,0 @@ -//+------------------------------------------------------------------+ -//| HistoryOrderInfo.mqh | -//| Copyright 2009-2020, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -//+------------------------------------------------------------------+ -//| 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 - { -//--- 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; - } -//--- return the result - return(str); - } -//+------------------------------------------------------------------+ -//| Converts the order status to text | -//+------------------------------------------------------------------+ -string CHistoryOrderInfo::FormatStatus(string &str,const uint status) const - { -//--- 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; - } -//--- return the result - return(str); - } -//+------------------------------------------------------------------+ -//| Converts the order filling type to text | -//+------------------------------------------------------------------+ -string CHistoryOrderInfo::FormatTypeFilling(string &str,const uint type) const - { -//--- 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; - } -//--- return the result - return(str); - } -//+------------------------------------------------------------------+ -//| Converts the type of order by expiration to text | -//+------------------------------------------------------------------+ -string CHistoryOrderInfo::FormatTypeTime(string &str,const uint type) const - { -//--- 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; - } -//--- return the result - return(str); - } -//+------------------------------------------------------------------+ -//| Converts the order parameters to text | -//+------------------------------------------------------------------+ -string CHistoryOrderInfo::FormatOrder(string &str) const - { - string type,price; - long tmp_long; -//--- set up - string symbol_name=this.Symbol(); - int digits=_Digits; - if(SymbolInfoInteger(symbol_name,SYMBOL_DIGITS,tmp_long)) - digits=(int)tmp_long; -//--- form the order description - str=StringFormat("#%I64u %s %s %s", - Ticket(), - FormatType(type,OrderType()), - DoubleToString(VolumeInitial(),2), - symbol_name); -//--- 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; -//--- 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 deleted file mode 100644 index ba52c37..0000000 --- a/Include/Trade/OrderInfo.mqh +++ /dev/null @@ -1,553 +0,0 @@ -//+------------------------------------------------------------------+ -//| OrderInfo.mqh | -//| Copyright 2009-2020, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -//+------------------------------------------------------------------+ -//| 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); - //--- additional 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 - { -//--- 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; - } -//--- return the result - return(str); - } -//+------------------------------------------------------------------+ -//| Converts the order status to text | -//+------------------------------------------------------------------+ -string COrderInfo::FormatStatus(string &str,const uint status) const - { -//--- 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; - } -//--- return the result - return(str); - } -//+------------------------------------------------------------------+ -//| Converts the order filling type to text | -//+------------------------------------------------------------------+ -string COrderInfo::FormatTypeFilling(string &str,const uint type) const - { -//--- 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; - } -//--- return the result - return(str); - } -//+------------------------------------------------------------------+ -//| Converts the type of order by expiration to text | -//+------------------------------------------------------------------+ -string COrderInfo::FormatTypeTime(string &str,const uint type) const - { -//--- 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; - } -//--- return the result - return(str); - } -//+------------------------------------------------------------------+ -//| Converts the order parameters to text | -//+------------------------------------------------------------------+ -string COrderInfo::FormatOrder(string &str) const - { - string type,price; - long tmp_long; -//--- set up - string symbol_name=this.Symbol(); - int digits=_Digits; - if(SymbolInfoInteger(symbol_name,SYMBOL_DIGITS,tmp_long)) - digits=(int)tmp_long; -//--- form the order description - str=StringFormat("#%I64u %s %s %s", - Ticket(), - FormatType(type,OrderType()), - DoubleToString(VolumeInitial(),2), - symbol_name); -//--- 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; -//--- 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 by 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 deleted file mode 100644 index 71a66aa..0000000 --- a/Include/Trade/PositionInfo.mqh +++ /dev/null @@ -1,364 +0,0 @@ -//+------------------------------------------------------------------+ -//| PositionInfo.mqh | -//| Copyright 2009-2020, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -//+------------------------------------------------------------------+ -//| 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 - { -//--- 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; - long tmp_long; - ENUM_ACCOUNT_MARGIN_MODE margin_mode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE); -//--- set up - string symbol_name=this.Symbol(); - int digits=_Digits; - if(SymbolInfoInteger(symbol_name,SYMBOL_DIGITS,tmp_long)) - digits=(int)tmp_long; -//--- 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_name, - DoubleToString(PriceOpen(),digits+3)); - else - str=StringFormat("%s %s %s %s", - FormatType(type,PositionType()), - DoubleToString(Volume(),2), - symbol_name, - 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; i0); - } -//+------------------------------------------------------------------+ -//| Stored position's current state | -//+------------------------------------------------------------------+ -void CPositionInfo::StoreState(void) - { - m_type =PositionType(); - m_volume =Volume(); - m_price =PriceOpen(); - m_stop_loss =StopLoss(); - m_take_profit=TakeProfit(); - } -//+------------------------------------------------------------------+ -//| Check position change | -//+------------------------------------------------------------------+ -bool CPositionInfo::CheckState(void) - { - if(m_type==PositionType() && - m_volume==Volume() && - m_price==PriceOpen() && - m_stop_loss==StopLoss() && - m_take_profit==TakeProfit()) - return(false); -//--- - return(true); - } -//+------------------------------------------------------------------+ diff --git a/Include/Trade/SymbolInfo.mqh b/Include/Trade/SymbolInfo.mqh deleted file mode 100644 index 0a56c68..0000000 --- a/Include/Trade/SymbolInfo.mqh +++ /dev/null @@ -1,789 +0,0 @@ -//+------------------------------------------------------------------+ -//| SymbolInfo.mqh | -//| Copyright 2009-2020, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -//+------------------------------------------------------------------+ -//| 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 - bool m_margin_hedged_use_leg; // calculate hedged margin using larger leg - double m_margin_hedged; // symbol margin hedged - 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); } - bool MarginHedgedUseLeg(void) const { return(m_margin_hedged_use_leg); } - double MarginHedged(void) const { return(m_margin_hedged); } - //--- left for backward compatibility - double MarginLong(void) const { return(0.0); } - double MarginShort(void) const { return(0.0); } - double MarginLimit(void) const { return(0.0); } - double MarginStop(void) const { return(0.0); } - double MarginStopLimit(void) const { return(0.0); } - //--- 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; - bool InfoMarginRate(const ENUM_ORDER_TYPE order_type,double& initial_margin_rate,double& maintenance_margin_rate) const; - //--- service methods - double NormalizePrice(const double price) const; - bool CheckMarketWatch(void); - }; -//+------------------------------------------------------------------+ -//| Constructor | -//+------------------------------------------------------------------+ -CSymbolInfo::CSymbolInfo(void) : m_name(NULL), - 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_hedged_use_leg(false), - m_margin_hedged(0.0), - m_trade_time_flags(0), - m_trade_fill_flags(0) - { - } -//+------------------------------------------------------------------+ -//| Destructor | -//+------------------------------------------------------------------+ -CSymbolInfo::~CSymbolInfo(void) - { - } -//+------------------------------------------------------------------+ -//| Set name | -//+------------------------------------------------------------------+ -bool CSymbolInfo::Name(const string name) - { - string symbol_name=StringLen(name)>0 ? name : _Symbol; -//--- check previous set name - if(m_name!=symbol_name) - { - m_name=symbol_name; - //--- - if(!CheckMarketWatch()) - return(false); - //--- - if(!Refresh()) - { - m_name=""; - Print(__FUNCTION__+": invalid data of symbol '"+symbol_name+"'"); - return(false); - } - } -//--- succeed - return(true); - } -//+------------------------------------------------------------------+ -//| Refresh cached data | -//+------------------------------------------------------------------+ -bool CSymbolInfo::Refresh(void) - { - long tmp_long=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_long)) - return(false); - m_digits=(int)tmp_long; - if(!SymbolInfoInteger(m_name,SYMBOL_ORDER_MODE,tmp_long)) - return(false); - m_order_mode=(int)tmp_long; - if(!SymbolInfoInteger(m_name,SYMBOL_TRADE_EXEMODE,tmp_long)) - return(false); - m_trade_execution=(ENUM_SYMBOL_TRADE_EXECUTION)tmp_long; - if(!SymbolInfoInteger(m_name,SYMBOL_TRADE_CALC_MODE,tmp_long)) - return(false); - m_trade_calcmode=(ENUM_SYMBOL_CALC_MODE)tmp_long; - if(!SymbolInfoInteger(m_name,SYMBOL_TRADE_MODE,tmp_long)) - return(false); - m_trade_mode=(ENUM_SYMBOL_TRADE_MODE)tmp_long; - if(!SymbolInfoInteger(m_name,SYMBOL_SWAP_MODE,tmp_long)) - return(false); - m_swap_mode=(ENUM_SYMBOL_SWAP_MODE)tmp_long; - if(!SymbolInfoInteger(m_name,SYMBOL_SWAP_ROLLOVER3DAYS,tmp_long)) - return(false); - m_swap3=(ENUM_DAY_OF_WEEK)tmp_long; - 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_HEDGED,m_margin_hedged)) - return(false); - if(!SymbolInfoInteger(m_name,SYMBOL_MARGIN_HEDGED_USE_LEG,tmp_long)) - return(false); - m_margin_hedged_use_leg=(bool)tmp_long; - if(!SymbolInfoInteger(m_name,SYMBOL_EXPIRATION_MODE,tmp_long)) - return(false); - m_trade_time_flags=(int)tmp_long; - if(!SymbolInfoInteger(m_name,SYMBOL_FILLING_MODE,tmp_long)) - return(false); - m_trade_fill_flags=(int)tmp_long; -//--- 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)); - } -//+------------------------------------------------------------------+ -//| Access functions SymbolInfoMarginRate(...) | -//+------------------------------------------------------------------+ -bool CSymbolInfo::InfoMarginRate(const ENUM_ORDER_TYPE order_type,double& initial_margin_rate,double& maintenance_margin_rate) const - { - return(SymbolInfoMarginRate(m_name,order_type,initial_margin_rate,maintenance_margin_rate)); - } -//+------------------------------------------------------------------+ -//| 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 deleted file mode 100644 index 3c24618..0000000 --- a/Include/Trade/TerminalInfo.mqh +++ /dev/null @@ -1,225 +0,0 @@ -//+------------------------------------------------------------------+ -//| 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 deleted file mode 100644 index 399fc20..0000000 --- a/Include/Trade/Trade.mqh +++ /dev/null @@ -1,1710 +0,0 @@ -//+------------------------------------------------------------------+ -//| Trade.mqh | -//| Copyright 2009-2020, MetaQuotes Software Corp. | -//| http://www.mql5.com | -//+------------------------------------------------------------------+ -#include -#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_TESTING)) - m_log_level=LOG_LEVEL_ALL; - if(MQL5InfoInteger(MQL5_OPTIMIZATION)) - m_log_level=LOG_LEVEL_NO; - } -//+------------------------------------------------------------------+ -//| 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); -//--- check order existence - if(!OrderSelect(ticket)) - return(false); -//--- clean - ClearStructures(); -//--- setting request - m_request.symbol =OrderGetString(ORDER_SYMBOL); - 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; i -#include -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -#import "kernel32.dll" -void RaiseException(uint exception_code,uint exception_flags,uint number_of_arguments,const ulong &arguments[]); -int UnhandledExceptionFilter(EXCEPTION_POINTERS &exception_info); -PVOID SetUnhandledExceptionFilter(PVOID top_level_exception_filter); -uint GetLastError(void); -void SetLastError(uint err_code); -uint GetErrorMode(void); -uint SetErrorMode(uint mode); -PVOID AddVectoredExceptionHandler(uint first,PVOID handler); -uint RemoveVectoredExceptionHandler(PVOID handle); -PVOID AddVectoredContinueHandler(uint first,PVOID handler); -uint RemoveVectoredContinueHandler(PVOID handle); -void RestoreLastError(uint err_code); -void RaiseFailFastException(EXCEPTION_RECORD &exception_record,CONTEXT &context_record,uint flags); -void FatalAppExitW(uint action,const string message_text); -uint GetThreadErrorMode(void); -int SetThreadErrorMode(uint new_mode,uint& old_mode); -#import diff --git a/Include/WinAPI/fileapi.mqh b/Include/WinAPI/fileapi.mqh deleted file mode 100644 index eec5408..0000000 --- a/Include/WinAPI/fileapi.mqh +++ /dev/null @@ -1,146 +0,0 @@ -//+------------------------------------------------------------------+ -//| fileapi.mqh | -//| Copyright 2020, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include - -//--- -enum STREAM_INFO_LEVELS - { - FindStreamInfoStandard, - FindStreamInfoMaxInfoLevel - }; -//--- -struct BY_HANDLE_FILE_INFORMATION - { - uint dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - uint dwVolumeSerialNumber; - uint nFileSizeHigh; - uint nFileSizeLow; - uint nNumberOfLinks; - uint nFileIndexHigh; - uint nFileIndexLow; - }; -//--- -struct CREATEFILE2_EXTENDED_PARAMETERS - { - uint dwSize; - uint dwFileAttributes; - uint dwFileFlags; - uint dwSecurityQosFlags; - PVOID lpSecurityAttributes; - HANDLE hTemplateFile; - }; -//--- -struct FILE_ATTRIBUTE_DATA - { - uint dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - uint nFileSizeHigh; - uint nFileSizeLow; - }; -//--- -struct FIND_STREAM_DATA - { - long StreamSize; - short cStreamName[MAX_PATH+36]; - }; -//--- -struct FIND_DATAW - { - uint dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - uint nFileSizeHigh; - uint nFileSizeLow; - uint dwReserved0; - uint dwReserved1; - short cFileName[MAX_PATH]; - short cAlternateFileName[14]; - }; -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -#import "kernel32.dll" -int AreFileApisANSI(void); -int CompareFileTime(FILETIME &file_time1,FILETIME &file_time2); -int CreateDirectoryW(const string path_name,PVOID security_attributes); -HANDLE CreateFile2(const string file_name,uint desired_access,uint share_mode,uint creation_disposition,CREATEFILE2_EXTENDED_PARAMETERS &create_ex_params); -HANDLE CreateFileW(const string file_name,uint desired_access,uint share_mode,PVOID security_attributes,uint creation_disposition,uint flags_and_attributes,HANDLE template_file); -int DefineDosDeviceW(uint flags,const string device_name,const string target_path); -int DeleteFileW(const string file_name); -int DeleteVolumeMountPointW(const string volume_mount_point); -int FileTimeToLocalFileTime(FILETIME &file_time,FILETIME &local_file_time); -int FindClose(HANDLE find_file); -int FindCloseChangeNotification(HANDLE change_handle); -HANDLE FindFirstChangeNotificationW(const string path_name,int watch_subtree,uint notify_filter); -HANDLE FindFirstFileExW(const string file_name,FINDEX_INFO_LEVELS info_level_id,FIND_DATAW &find_file_data,FINDEX_SEARCH_OPS search_op,PVOID search_filter,uint additional_flags); -HANDLE FindFirstFileNameW(const string file_name,uint flags,uint &StringLength,ushort &LinkName[]); -HANDLE FindFirstFileW(const string file_name,FIND_DATAW &find_file_data); -HANDLE FindFirstStreamW(const string file_name,STREAM_INFO_LEVELS InfoLevel,FIND_STREAM_DATA &find_stream_data,uint flags); -HANDLE FindFirstVolumeW(ushort &volume_name[],uint &buffer_length); -int FindNextChangeNotification(HANDLE change_handle); -int FindNextFileNameW(HANDLE find_stream,uint &StringLength,ushort &LinkName[]); -int FindNextFileW(HANDLE find_file,FIND_DATAW &find_file_data); -int FindNextStreamW(HANDLE find_stream,FIND_STREAM_DATA &find_stream_data); -int FindNextVolumeW(HANDLE find_volume,ushort &volume_name[],uint &buffer_length); -int FindVolumeClose(HANDLE find_volume); -int FlushFileBuffers(HANDLE file); -uint GetCompressedFileSizeW(const string file_name,uint &file_size_high); -int GetDiskFreeSpaceExW(const string directory_name,ulong &free_bytes_available_to_caller,ulong &total_number_of_bytes,ulong &total_number_of_free_bytes); -int GetDiskFreeSpaceW(const string root_path_name,uint §ors_per_cluster,uint &bytes_per_sector,uint &number_of_free_clusters,uint &total_number_of_clusters); -uint GetDriveTypeW(const string root_path_name); -int GetFileAttributesExW(const string file_name,GET_FILEEX_INFO_LEVELS info_level_id,FILE_ATTRIBUTE_DATA &file_information); -uint GetFileAttributesW(const string file_name); -int GetFileInformationByHandle(HANDLE file,BY_HANDLE_FILE_INFORMATION &file_information); -uint GetFileSize(HANDLE file,uint &file_size_high); -int GetFileSizeEx(HANDLE file,long &file_size); -int GetFileTime(HANDLE file,FILETIME &creation_time,FILETIME &last_access_time,FILETIME &last_write_time); -uint GetFileType(HANDLE file); -uint GetFinalPathNameByHandleW(HANDLE file,ushort &file_path[],uint file_path,uint flags); -uint GetFullPathNameW(const string file_name,uint buffer_length,ushort &buffer[],ushort &file_part[]); -uint GetLogicalDrives(void); -uint GetLogicalDriveStringsW(uint buffer_length,ushort &buffer[]); -uint GetLongPathNameW(const string short_path,string &long_path,uint buffer); -uint GetShortPathNameW(const string long_path,string &short_path,uint buffer); -uint GetTempFileNameW(const string path_name,const string prefix_string,uint unique,ushort &temp_file_name[]); -uint GetTempPathW(uint buffer_length,ushort &buffer[]); -int GetVolumeInformationByHandleW(HANDLE file,ushort &volume_name_buffer[],uint volume_name_size,uint &volume_serial_number,uint &maximum_component_length,uint &file_system_flags,ushort &file_system_name_buffer[],uint file_system_name_size); -int GetVolumeInformationW(const string root_path_name,ushort &volume_name_buffer[],uint volume_name_size,uint &volume_serial_number,uint &maximum_component_length,uint &file_system_flags,ushort &file_system_name_buffer[],uint file_system_name_size); -int GetVolumeNameForVolumeMountPointW(const string volume_mount_point,string volume_name,uint buffer_length); -int GetVolumePathNamesForVolumeNameW(const string volume_name,string volume_path_names,uint buffer_length,uint &return_length); -int GetVolumePathNameW(const string file_name,ushort &volume_path_name[],uint buffer_length); -int LocalFileTimeToFileTime(FILETIME &local_file_time,FILETIME &file_time); -int LockFile(HANDLE file,uint file_offset_low,uint file_offset_high,uint number_of_bytes_to_lock_low,uint number_of_bytes_to_lock_high); -int LockFileEx(HANDLE file,uint flags,uint reserved,uint number_of_bytes_to_lock_low,uint number_of_bytes_to_lock_high,OVERLAPPED &overlapped); -uint QueryDosDeviceW(const string device_name,ushort &target_path[],uint max); -int ReadFile(HANDLE file,ushort &buffer[],uint number_of_bytes_to_read,uint &number_of_bytes_read,OVERLAPPED &overlapped); -int ReadFile(HANDLE file,ushort &buffer[],uint number_of_bytes_to_read,uint &number_of_bytes_read,PVOID overlapped); -int ReadFileScatter(HANDLE file,FILE_SEGMENT_ELEMENT &segment_array[],uint number_of_bytes_to_read,uint &reserved,OVERLAPPED &overlapped); -int ReadFileScatter(HANDLE file,FILE_SEGMENT_ELEMENT &segment_array[],uint number_of_bytes_to_read,uint &reserved,PVOID overlapped); -int RemoveDirectoryW(const string path_name); -int SetEndOfFile(HANDLE file); -void SetFileApisToANSI(void); -void SetFileApisToOEM(void); -int SetFileAttributesW(const string file_name,uint file_attributes); -int SetFileInformationByHandle(HANDLE file,FILE_INFO_BY_HANDLE_CLASS FileInformationClass,FILE_INFO &file_information,uint buffer_size); -int SetFileIoOverlappedRange(HANDLE FileHandle,uchar &OverlappedRangeStart,uint Length); -uint SetFilePointer(HANDLE file,long distance_to_move,long &distance_to_move_high,uint move_method); -int SetFilePointerEx(HANDLE file,long distance_to_move,long &new_file_pointer,uint move_method); -int SetFileTime(HANDLE file,FILETIME &creation_time,FILETIME &last_access_time,FILETIME &last_write_time); -int SetFileValidData(HANDLE file,long ValidDataLength); -int UnlockFile(HANDLE file,uint file_offset_low,uint file_offset_high,uint number_of_bytes_to_unlock_low,uint number_of_bytes_to_unlock_high); -int UnlockFileEx(HANDLE file,uint reserved,uint number_of_bytes_to_unlock_low,uint number_of_bytes_to_unlock_high,OVERLAPPED &overlapped); -int WriteFile(HANDLE file,const ushort &buffer[],uint number_of_bytes_to_write,uint &number_of_bytes_written,OVERLAPPED &overlapped); -int WriteFile(HANDLE file,const ushort &buffer[],uint number_of_bytes_to_write,uint &number_of_bytes_written,PVOID overlapped); -int WriteFileGather(HANDLE file,FILE_SEGMENT_ELEMENT &segment_array[],uint number_of_bytes_to_write,uint &reserved,OVERLAPPED &overlapped); -int WriteFileGather(HANDLE file,FILE_SEGMENT_ELEMENT &segment_array[],uint number_of_bytes_to_write,uint &reserved,PVOID overlapped); -#import -//+------------------------------------------------------------------+ diff --git a/Include/WinAPI/handleapi.mqh b/Include/WinAPI/handleapi.mqh deleted file mode 100644 index a03b303..0000000 --- a/Include/WinAPI/handleapi.mqh +++ /dev/null @@ -1,21 +0,0 @@ -//+------------------------------------------------------------------+ -//| handleapi.mqh | -//| Copyright 2018, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include - -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -#import "kernel32.dll" -int CloseHandle(HANDLE object); -int DuplicateHandle(HANDLE source_process_handle,HANDLE source_handle,HANDLE target_process_handle,HANDLE &target_handle,uint desired_access,int inherit_handle,uint options); -int GetHandleInformation(HANDLE object,uint& flags); -int SetHandleInformation(HANDLE object,uint mask,uint flags); -#import - -#import "kernelbase.dll" -int CompareObjectHandles(HANDLE first_object_handle, HANDLE second_object_handle); -#import -//+------------------------------------------------------------------+ \ No newline at end of file diff --git a/Include/WinAPI/libloaderapi.mqh b/Include/WinAPI/libloaderapi.mqh deleted file mode 100644 index 58f0f09..0000000 --- a/Include/WinAPI/libloaderapi.mqh +++ /dev/null @@ -1,47 +0,0 @@ -//+------------------------------------------------------------------+ -//| libloaderapi.mqh | -//| Copyright 2018, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include - -//--- -struct ENUMUILANG - { - uint NumOfEnumUILang; - uint SizeOfEnumUIBuffer; - PVOID EnumUIBuffer; - }; -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -#import "kernel32.dll" -int DisableThreadLibraryCalls(HANDLE lib_module); -HANDLE FindResourceExW(HANDLE module,const string type,const string name,ushort language); -int FindStringOrdinal(uint find_string_ordinal_flags,const string string_source,int source,const string string_value,int value,int ignore_case); -int FreeLibrary(HANDLE lib_module); -void FreeLibraryAndExitThread(HANDLE lib_module,uint exit_code); -int FreeResource(HANDLE res_data); -uint GetModuleFileNameW(HANDLE module,ushort &filename[],uint size); -HANDLE GetModuleHandleW(const string module_name); -int GetModuleHandleExW(uint flags,const string module_name,HANDLE &module); -PVOID GetProcAddress(HANDLE module,uchar &proc_name[]); -HANDLE LoadLibraryExW(const string lib_file_name,HANDLE file,uint flags); -HANDLE LoadResource(HANDLE module,HANDLE res_info); -PVOID LockResource(HANDLE res_data); -uint SizeofResource(HANDLE module,HANDLE res_info); -PVOID AddDllDirectory(const string new_directory); -int RemoveDllDirectory(PVOID cookie); -int SetDefaultDllDirectories(uint directory_flags); -int EnumResourceLanguagesExW(HANDLE module,const string type,const string name,PVOID enum_func,long param,uint flags,ushort lang_id); -int EnumResourceNamesExW(HANDLE module,const string type,PVOID enum_func,long param,uint flags,ushort lang_id); -int EnumResourceTypesExW(HANDLE module,PVOID enum_func,long param,uint flags,ushort lang_id); -HANDLE FindResourceW(HANDLE module,const string name,const string type); -HANDLE LoadLibraryW(const string lib_file_name); -int EnumResourceNamesW(HANDLE module,const string type,PVOID enum_func,long param); -#import - -#import "user32.dll" -int LoadStringW(HANDLE instance,uint id,string buffer,int buffer_max); -#import -//+------------------------------------------------------------------+ diff --git a/Include/WinAPI/memoryapi.mqh b/Include/WinAPI/memoryapi.mqh deleted file mode 100644 index 1dfa008..0000000 --- a/Include/WinAPI/memoryapi.mqh +++ /dev/null @@ -1,85 +0,0 @@ -//+------------------------------------------------------------------+ -//| memoryapi.mqh | -//| Copyright 2020, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include -#include - -//--- -enum MEMORY_RESOURCE_NOTIFICATION_TYPE - { - LowMemoryResourceNotification, - HighMemoryResourceNotification - }; -//--- -enum OFFER_PRIORITY - { - VmOfferPriorityVeryLow=1, - VmOfferPriorityLow, - VmOfferPriorityBelowNormal, - VmOfferPriorityNormal - }; -//--- -enum WIN32_MEMORY_INFORMATION_CLASS - { - MemoryRegionInfo - }; -//--- -struct WIN32_MEMORY_RANGE_ENTRY - { - PVOID VirtualAddress; - ulong NumberOfBytes; - }; -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -#import "kernel32.dll" -int AllocateUserPhysicalPages(HANDLE hProcess,ulong &NumberOfPages,ulong &PageArray[]); -int AllocateUserPhysicalPagesNuma(HANDLE hProcess,ulong &NumberOfPages,ulong &PageArray[],uint nndPreferred); -HANDLE CreateFileMappingFromApp(HANDLE hFile,PVOID SecurityAttributes,uint PageProtection,ulong MaximumSize,const string Name); -HANDLE CreateFileMappingNumaW(HANDLE hFile,PVOID lpFileMappingAttributes,uint flProtect,uint dwMaximumSizeHigh,uint dwMaximumSizeLow,const string lpName,uint nndPreferred); -HANDLE CreateFileMappingW(HANDLE hFile,PVOID lpFileMappingAttributes,uint flProtect,uint dwMaximumSizeHigh,uint dwMaximumSizeLow,const string lpName); -HANDLE CreateMemoryResourceNotification(MEMORY_RESOURCE_NOTIFICATION_TYPE NotificationType); -uint DiscardVirtualMemory(PVOID VirtualAddress,ulong Size); -int FlushViewOfFile(const PVOID lpBaseAddress,ulong dwNumberOfBytesToFlush); -int FreeUserPhysicalPages(HANDLE hProcess,ulong &NumberOfPages,ulong &PageArray[]); -ulong GetLargePageMinimum(void); -int GetMemoryErrorHandlingCapabilities(uint &Capabilities); -int GetProcessWorkingSetSizeEx(HANDLE hProcess,ulong &lpMinimumWorkingSetSize,ulong &lpMaximumWorkingSetSize,uint &Flags); -int GetSystemFileCacheSize(ulong &lpMinimumFileCacheSize,ulong &lpMaximumFileCacheSize,uint &lpFlags); -uint GetWriteWatch(uint dwFlags,PVOID lpBaseAddress,ulong dwRegionSize,PVOID &lpAddresses[],uint &lpdwCount,uint &lpdwGranularity); -int MapUserPhysicalPages(PVOID VirtualAddress,ulong &NumberOfPages,ulong &PageArray[]); -PVOID MapViewOfFile(HANDLE hFileMappingObject,uint dwDesiredAccess,uint dwFileOffsetHigh,uint dwFileOffsetLow,ulong dwNumberOfBytesToMap); -PVOID MapViewOfFileEx(HANDLE hFileMappingObject,uint dwDesiredAccess,uint dwFileOffsetHigh,uint dwFileOffsetLow,ulong dwNumberOfBytesToMap,PVOID lpBaseAddress); -PVOID MapViewOfFileFromApp(HANDLE hFileMappingObject,uint DesiredAccess,ulong FileOffset,ulong NumberOfBytesToMap); -uint OfferVirtualMemory(PVOID VirtualAddress,ulong Size,OFFER_PRIORITY Priority); -HANDLE OpenFileMappingW(uint dwDesiredAccess,int bInheritHandle,const string lpName); -int PrefetchVirtualMemory(HANDLE hProcess,uint &NumberOfEntries,WIN32_MEMORY_RANGE_ENTRY &VirtualAddresses,uint Flags); -int QueryMemoryResourceNotification(HANDLE ResourceNotificationHandle,int &ResourceState); -int ReadProcessMemory(HANDLE hProcess,const PVOID lpBaseAddress,PVOID lpBuffer,ulong nSize,ulong &lpNumberOfBytesRead); -uint ReclaimVirtualMemory(const PVOID VirtualAddress,ulong Size); -PVOID RegisterBadMemoryNotification(PVOID Callback); -uint ResetWriteWatch(PVOID lpBaseAddress,ulong dwRegionSize); -int SetProcessWorkingSetSizeEx(HANDLE hProcess,ulong dwMinimumWorkingSetSize,ulong dwMaximumWorkingSetSize,uint Flags); -int SetSystemFileCacheSize(ulong MinimumFileCacheSize,ulong MaximumFileCacheSize,uint Flags); -int UnmapViewOfFile(const PVOID lpBaseAddress); -int UnmapViewOfFileEx(PVOID BaseAddress,uint UnmapFlags); -int UnregisterBadMemoryNotification(PVOID RegistrationHandle); -PVOID VirtualAlloc(PVOID lpAddress,ulong dwSize,uint flAllocationType,uint flProtect); -PVOID VirtualAllocEx(HANDLE hProcess,PVOID lpAddress,ulong dwSize,uint flAllocationType,uint flProtect); -PVOID VirtualAllocExNuma(HANDLE hProcess,PVOID lpAddress,ulong dwSize,uint flAllocationType,uint flProtect,uint nndPreferred); -int VirtualFree(PVOID lpAddress,ulong dwSize,uint dwFreeType); -int VirtualFreeEx(HANDLE hProcess,PVOID lpAddress,ulong dwSize,uint dwFreeType); -int VirtualLock(PVOID lpAddress,ulong dwSize); -int VirtualProtect(PVOID lpAddress,ulong dwSize,uint flNewProtect,uint &lpflOldProtect); -int VirtualProtectEx(HANDLE hProcess,PVOID lpAddress,ulong dwSize,uint flNewProtect,uint &lpflOldProtect); -ulong VirtualQuery(const PVOID lpAddress,MEMORY_BASIC_INFORMATION &lpBuffer,ulong dwLength); -ulong VirtualQueryEx(HANDLE hProcess,const PVOID lpAddress,MEMORY_BASIC_INFORMATION &lpBuffer,ulong dwLength); -int VirtualUnlock(PVOID lpAddress,ulong dwSize); -int WriteProcessMemory(HANDLE hProcess,PVOID lpBaseAddress,PVOID lpBuffer,ulong nSize,ulong &lpNumberOfBytesWritten); -int WriteProcessMemory(HANDLE hProcess,PVOID lpBaseAddress,uchar &lpBuffer[],ulong nSize,ulong &lpNumberOfBytesWritten); -int WriteProcessMemory(HANDLE hProcess,uchar &lpBaseAddress[],PVOID lpBuffer,ulong nSize,ulong &lpNumberOfBytesWritten); -int WriteProcessMemory(HANDLE hProcess,uchar &lpBaseAddress[],uchar &lpBuffer[],ulong nSize,ulong &lpNumberOfBytesWritten); -#import -//+------------------------------------------------------------------+ diff --git a/Include/WinAPI/processenv.mqh b/Include/WinAPI/processenv.mqh deleted file mode 100644 index bbf83bb..0000000 --- a/Include/WinAPI/processenv.mqh +++ /dev/null @@ -1,27 +0,0 @@ -//+------------------------------------------------------------------+ -//| processenv.mqh | -//| Copyright 2018, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include - -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -#import "kernel32.dll" -int SetEnvironmentStringsW(string new_environment); -HANDLE GetStdHandle(uint std_handle); -int SetStdHandle(uint std_handle,HANDLE handle); -int SetStdHandleEx(uint std_handle,HANDLE handle,HANDLE &prev_value); -string GetCommandLineW(void); -string GetEnvironmentStringsW(void); -int FreeEnvironmentStringsW(string v); -uint GetEnvironmentVariableW(const string name,ushort &buffer[],uint size); -int SetEnvironmentVariableW(const string name,const string value); -uint ExpandEnvironmentStringsW(const string src,string dst,uint size); -int SetCurrentDirectoryW(const string path_name); -uint GetCurrentDirectoryW(uint buffer_length,ushort &buffer[]); -uint GetCurrentDirectoryW(uint buffer_length,string &buffer); -uint SearchPathW(const string path,const string file_name,const string extension,uint buffer_length,ushort &buffer[],string &file_part); -int NeedCurrentDirectoryForExePathW(const string exe_name); -#import diff --git a/Include/WinAPI/processthreadsapi.mqh b/Include/WinAPI/processthreadsapi.mqh deleted file mode 100644 index bc81fa1..0000000 --- a/Include/WinAPI/processthreadsapi.mqh +++ /dev/null @@ -1,202 +0,0 @@ -//+------------------------------------------------------------------+ -//| processthreadsapi.mqh | -//| Copyright 2018, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include -#include - -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -//--- -enum THREAD_INFORMATION_CLASS - { - ThreadMemoryPriority, - ThreadAbsoluteCpuPriority, - ThreadDynamicCodePolicy, - ThreadPowerThrottling, - ThreadInformationClassMax - }; -//--- -enum PROCESS_INFORMATION_CLASS - { - ProcessMemoryPriority, - ProcessMemoryExhaustionInfo, - ProcessAppMemoryInfo, - ProcessInPrivateInfo, - ProcessPowerThrottling, - ProcessReservedValue1, - ProcessTelemetryCoverageInfo, - ProcessProtectionLevelInfo, - ProcessInformationClassMax - }; -//--- -enum PROCESS_MEMORY_EXHAUSTION_TYPE - { - PMETypeFailFastOnCommitFailure, - PMETypeMax - }; -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -//--- -struct PROCESS_INFORMATION - { - HANDLE hProcess; - HANDLE hThread; - uint dwProcessId; - uint dwThreadId; - }; -//--- -struct STARTUPINFOW - { - uint cb; - string lpReserved; - string lpDesktop; - string lpTitle; - uint dwX; - uint dwY; - uint dwXSize; - uint dwYSize; - uint dwXCountChars; - uint dwYCountChars; - uint dwFillAttribute; - uint dwFlags; - ushort wShowWindow; - ushort cbReserved2; - PVOID lpReserved2; - HANDLE hStdInput; - HANDLE hStdOutput; - HANDLE hStdError; - }; -//--- -struct MEMORY_PRIORITY_INFORMATION - { - uint MemoryPriority; - }; -//--- -struct THREAD_POWER_THROTTLING_STATE - { - uint Version; - uint ControlMask; - uint StateMask; - }; -//--- -struct APP_MEMORY_INFORMATION - { - ulong AvailableCommit; - ulong PrivateCommitUsage; - ulong PeakPrivateCommitUsage; - ulong TotalCommitUsage; - }; -//--- -struct PROCESS_MEMORY_EXHAUSTION_INFO - { - ushort Version; - ushort Reserved; - PROCESS_MEMORY_EXHAUSTION_TYPE Type; - ulong Value; - }; -//--- -struct PROCESS_POWER_THROTTLING_STATE - { - uint Version; - uint ControlMask; - uint StateMask; - }; -//--- -struct PROCESS_PROTECTION_LEVEL_INFORMATION - { - uint ProtectionLevel; - }; -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -#import "kernel32.dll" -uint QueueUserAPC(PVOID apc,HANDLE thread,ulong data); -int GetProcessTimes(HANDLE process,FILETIME &creation_time,FILETIME &exit_time,FILETIME &kernel_time,FILETIME &user_time); -HANDLE GetCurrentProcess(void); -uint GetCurrentProcessId(void); -void ExitProcess(uint exit_code); -int TerminateProcess(HANDLE process,uint exit_code); -int GetExitCodeProcess(HANDLE process,uint &exit_code); -int SwitchToThread(void); -HANDLE CreateThread(PVOID thread_attributes,ulong stack_size,PVOID start_address,PVOID parameter,uint creation_flags,uint &thread_id); -HANDLE CreateRemoteThread(HANDLE process,PVOID thread_attributes,ulong stack_size,PVOID start_address,PVOID parameter,uint creation_flags,uint &thread_id); -HANDLE GetCurrentThread(void); -uint GetCurrentThreadId(void); -HANDLE OpenThread(uint desired_access,int inherit_handle,uint thread_id); -int SetThreadPriority(HANDLE thread,int priority); -int SetThreadPriorityBoost(HANDLE thread,int disable_priority_boost); -int GetThreadPriorityBoost(HANDLE thread,int &disable_priority_boost); -int GetThreadPriority(HANDLE thread); -void ExitThread(uint exit_code); -int TerminateThread(HANDLE thread,uint exit_code); -int GetExitCodeThread(HANDLE thread,uint &exit_code); -uint SuspendThread(HANDLE thread); -uint ResumeThread(HANDLE thread); -uint TlsAlloc(void); -PVOID TlsGetValue(uint tls_index); -int TlsSetValue(uint tls_index,PVOID tls_value); -int TlsFree(uint tls_index); -int CreateProcessW(const string application_name,string command_line,PVOID process_attributes,PVOID thread_attributes,int inherit_handles,uint creation_flags,PVOID environment,const string current_directory,STARTUPINFOW &startup_info,PROCESS_INFORMATION &process_information); -int SetProcessShutdownParameters(uint level,uint flags); -uint GetProcessVersion(uint process_id); -void GetStartupInfoW(STARTUPINFOW &startup_info); -int SetPriorityClass(HANDLE process,uint priority_class); -uint GetPriorityClass(HANDLE process); -int SetThreadStackGuarantee(ulong stack_size_in_bytes); -int ProcessIdToSessionId(uint process_id,uint &session_id); -uint GetProcessId(HANDLE process); -uint GetThreadId(HANDLE thread); -void FlushProcessWriteBuffers(void); -uint GetProcessIdOfThread(HANDLE thread); -int InitializeProcThreadAttributeList(PVOID attribute_list,uint attribute_count,uint flags,ulong &size); -void DeleteProcThreadAttributeList(PVOID attribute_list); -int SetProcessAffinityUpdateMode(HANDLE process,uint flags); -int QueryProcessAffinityUpdateMode(HANDLE process,uint &flags); -int UpdateProcThreadAttribute(PVOID attribute_list,uint flags,uint attribute,PVOID value,ulong size,PVOID previous_value,ulong &return_size); -HANDLE CreateRemoteThreadEx(HANDLE process,PVOID thread_attributes,ulong stack_size,PVOID start_address,PVOID parameter,uint creation_flags,PVOID attribute_list,uint &thread_id); -void GetCurrentThreadStackLimits(ulong &low_limit,ulong &high_limit); -int GetThreadContext(HANDLE thread,CONTEXT &context); -int GetProcessMitigationPolicy(HANDLE process,PROCESS_MITIGATION_POLICY mitigation_policy,PVOID buffer,ulong length); -int SetThreadContext(HANDLE thread,const CONTEXT &context); -int SetProcessMitigationPolicy(PROCESS_MITIGATION_POLICY mitigation_policy,PVOID buffer,ulong length); -int FlushInstructionCache(HANDLE process,const PVOID base_address,ulong size); -int GetThreadTimes(HANDLE thread,FILETIME &creation_time,FILETIME &exit_time,FILETIME &kernel_time,FILETIME &user_time); -HANDLE OpenProcess(uint desired_access,int inherit_handle,uint process_id); -int IsProcessorFeaturePresent(uint processor_feature); -int GetProcessHandleCount(HANDLE process,uint &handle_count); -uint GetCurrentProcessorNumber(void); -int SetThreadIdealProcessorEx(HANDLE thread,PROCESSOR_NUMBER &ideal_processor,PROCESSOR_NUMBER &previous_ideal_processor); -int GetThreadIdealProcessorEx(HANDLE thread,PROCESSOR_NUMBER &ideal_processor); -void GetCurrentProcessorNumberEx(PROCESSOR_NUMBER &proc_number); -int GetProcessPriorityBoost(HANDLE process,int &disable_priority_boost); -int SetProcessPriorityBoost(HANDLE process,int disable_priority_boost); -int GetThreadIOPendingFlag(HANDLE thread,int &io_is_pending); -int GetSystemTimes(FILETIME &idle_time,FILETIME &kernel_time,FILETIME &user_time); -int GetThreadInformation(HANDLE thread,THREAD_INFORMATION_CLASS thread_information_class,PVOID thread_information,uint thread_information_size); -int SetThreadInformation(HANDLE thread,THREAD_INFORMATION_CLASS thread_information_class,PVOID thread_information,uint thread_information_size); -int IsProcessCritical(HANDLE process,int &critical); -int SetProtectedPolicy(const GUID &policy_guid,ulong policy_value,ulong &old_policy_value); -int QueryProtectedPolicy(const GUID &policy_guid,ulong &policy_value); -uint SetThreadIdealProcessor(HANDLE thread,uint ideal_processor); -int SetProcessInformation(HANDLE process,PROCESS_INFORMATION_CLASS process_information_class,PVOID process_information,uint process_information_size); -int GetProcessInformation(HANDLE process,PROCESS_INFORMATION_CLASS process_information_class,PVOID process_information,uint process_information_size); -int GetSystemCpuSetInformation(SYSTEM_CPU_SET_INFORMATION &information,uint buffer_length,ulong returned_length,HANDLE process,uint flags); -int GetProcessDefaultCpuSets(HANDLE process,ulong &cpu_set_ids,uint cpu_set_id_count,ulong required_id_count); -int SetProcessDefaultCpuSets(HANDLE process,const uint &cpu_set_ids,uint cpu_set_id_count); -int GetThreadSelectedCpuSets(HANDLE thread,ulong &cpu_set_ids,uint cpu_set_id_count,ulong required_id_count); -int SetThreadSelectedCpuSets(HANDLE thread,const uint &cpu_set_ids,uint cpu_set_id_count); -int GetProcessShutdownParameters(uint &level,uint &flags); -int SetThreadDescription(HANDLE thread,const string thread_description); -int GetThreadDescription(HANDLE thread,string &thread_description); -#import -#import "advapi32.dll" -int CreateProcessAsUserW(HANDLE token,const string application_name,string command_line,PVOID process_attributes,PVOID thread_attributes,int inherit_handles,uint creation_flags,PVOID environment,const string current_directory,STARTUPINFOW &startup_info,PROCESS_INFORMATION &process_information); -int SetThreadToken(HANDLE thread,HANDLE token); -int OpenProcessToken(HANDLE process_handle,uint desired_access,HANDLE &token_handle); -int OpenThreadToken(HANDLE thread_handle,uint desired_access,int open_as_self,HANDLE &token_handle); -#import -//+------------------------------------------------------------------+ diff --git a/Include/WinAPI/securitybaseapi.mqh b/Include/WinAPI/securitybaseapi.mqh deleted file mode 100644 index f27838b..0000000 --- a/Include/WinAPI/securitybaseapi.mqh +++ /dev/null @@ -1,119 +0,0 @@ -//+------------------------------------------------------------------+ -//| securitybaseapi.mqh | -//| Copyright 2018, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include -#include -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -#import "advapi32.dll" -int AccessCheck(SECURITY_DESCRIPTOR &security_descriptor,HANDLE client_token,uint desired_access,GENERIC_MAPPING &generic_mapping,PRIVILEGE_SET &privilege_set,uint &privilege_set_length,uint &granted_access,int &access_status); -int AccessCheckAndAuditAlarmW(const string subsystem_name,PVOID handle_id,string object_type_name,string object_name,SECURITY_DESCRIPTOR &security_descriptor,uint desired_access,GENERIC_MAPPING &generic_mapping,int object_creation,uint &granted_access,int &access_status,int &generate_on_close); -int AccessCheckByType(SECURITY_DESCRIPTOR &security_descriptor,SID &principal_self_sid,HANDLE client_token,uint desired_access,OBJECT_TYPE_LIST &object_type_list,uint object_type_list_length,GENERIC_MAPPING &generic_mapping,PRIVILEGE_SET &privilege_set,uint &privilege_set_length,uint &granted_access,int &access_status); -int AccessCheckByTypeResultList(SECURITY_DESCRIPTOR &security_descriptor,SID &principal_self_sid,HANDLE client_token,uint desired_access,OBJECT_TYPE_LIST &object_type_list,uint object_type_list_length,GENERIC_MAPPING &generic_mapping,PRIVILEGE_SET &privilege_set,uint &privilege_set_length,uint &granted_access_list,uint &access_status_list); -int AccessCheckByTypeAndAuditAlarmW(const string subsystem_name,PVOID handle_id,const string object_type_name,const string object_name,SECURITY_DESCRIPTOR &security_descriptor,SID &principal_self_sid,uint desired_access,AUDIT_EVENT_TYPE audit_type,uint flags,OBJECT_TYPE_LIST &object_type_list,uint object_type_list_length,GENERIC_MAPPING &generic_mapping,int object_creation,uint &granted_access,int &access_status,int &generate_on_close); -int AccessCheckByTypeResultListAndAuditAlarmW(const string subsystem_name,PVOID handle_id,const string object_type_name,const string object_name,SECURITY_DESCRIPTOR &security_descriptor,SID &principal_self_sid,uint desired_access,AUDIT_EVENT_TYPE audit_type,uint flags,OBJECT_TYPE_LIST &object_type_list,uint object_type_list_length,GENERIC_MAPPING &generic_mapping,int object_creation,uint &granted_access_list,uint &access_status_list,int &generate_on_close); -int AccessCheckByTypeResultListAndAuditAlarmByHandleW(const string subsystem_name,PVOID handle_id,HANDLE client_token,const string object_type_name,const string object_name,SECURITY_DESCRIPTOR &security_descriptor,SID &principal_self_sid,uint desired_access,AUDIT_EVENT_TYPE audit_type,uint flags,OBJECT_TYPE_LIST &object_type_list,uint object_type_list_length,GENERIC_MAPPING &generic_mapping,int object_creation,uint &granted_access_list,uint &access_status_list,int &generate_on_close); -int AddAccessAllowedAce(ACL &acl,uint ace_revision,uint access_mask,SID &sid); -int AddAccessAllowedAceEx(ACL &acl,uint ace_revision,uint ace_flags,uint access_mask,SID &sid); -int AddAccessAllowedObjectAce(ACL &acl,uint ace_revision,uint ace_flags,uint access_mask,GUID &object_type_guid,GUID &inherited_object_type_guid,SID &sid); -int AddAccessDeniedAce(ACL &acl,uint ace_revision,uint access_mask,SID &sid); -int AddAccessDeniedAceEx(ACL &acl,uint ace_revision,uint ace_flags,uint access_mask,SID &sid); -int AddAccessDeniedObjectAce(ACL &acl,uint ace_revision,uint ace_flags,uint access_mask,GUID &object_type_guid,GUID &inherited_object_type_guid,SID &sid); -int AddAce(ACL &acl,uint ace_revision,uint starting_ace_index,PVOID ace_list,uint ace_list_length); -int AddAuditAccessAce(ACL &acl,uint ace_revision,uint access_mask,SID &sid,int audit_success,int audit_failure); -int AddAuditAccessAceEx(ACL &acl,uint ace_revision,uint ace_flags,uint access_mask,SID &sid,int audit_success,int audit_failure); -int AddAuditAccessObjectAce(ACL &acl,uint ace_revision,uint ace_flags,uint access_mask,GUID &object_type_guid,GUID &inherited_object_type_guid,SID &sid,int audit_success,int audit_failure); -int AddMandatoryAce(ACL &acl,uint ace_revision,uint ace_flags,uint mandatory_policy,SID &label_sid); -int AdjustTokenGroups(HANDLE token_handle,int reset_to_default,TOKEN_GROUPS &new_state,uint buffer_length,TOKEN_GROUPS &previous_state,uint &return_length); -int AdjustTokenPrivileges(HANDLE token_handle,int disable_all_privileges,TOKEN_PRIVILEGES &new_state,uint buffer_length,TOKEN_PRIVILEGES &previous_state,uint &return_length); -int AllocateAndInitializeSid(SID_IDENTIFIER_AUTHORITY &identifier_authority,uchar sub_authority_count,uint sub_authority0,uint sub_authority1,uint sub_authority2,uint sub_authority3,uint sub_authority4,uint sub_authority5,uint sub_authority6,uint sub_authority7,SID &sid); -int AllocateLocallyUniqueId(LUID &luid); -int AreAllAccessesGranted(uint granted_access,uint desired_access); -int AreAnyAccessesGranted(uint granted_access,uint desired_access); -int CheckTokenMembership(HANDLE token_handle,SID &sid_to_check,int &is_member); -int ConvertToAutoInheritPrivateObjectSecurity(SECURITY_DESCRIPTOR &parent_descriptor,SECURITY_DESCRIPTOR ¤t_security_descriptor,SECURITY_DESCRIPTOR &new_security_descriptor,GUID &object_type,uchar is_directory_object,GENERIC_MAPPING &generic_mapping); -int CopySid(uint destination_sid_length,SID &destination_sid,SID &source_sid); -int CreatePrivateObjectSecurity(SECURITY_DESCRIPTOR &parent_descriptor,SECURITY_DESCRIPTOR &creator_descriptor,SECURITY_DESCRIPTOR &new_descriptor,int is_directory_object,HANDLE token,GENERIC_MAPPING &generic_mapping); -int CreatePrivateObjectSecurityEx(SECURITY_DESCRIPTOR &parent_descriptor,SECURITY_DESCRIPTOR &creator_descriptor,SECURITY_DESCRIPTOR &new_descriptor,GUID &object_type,int is_container_object,uint auto_inherit_flags,HANDLE token,GENERIC_MAPPING &generic_mapping); -int CreatePrivateObjectSecurityWithMultipleInheritance(SECURITY_DESCRIPTOR &parent_descriptor,SECURITY_DESCRIPTOR &creator_descriptor,SECURITY_DESCRIPTOR &new_descriptor,GUID &object_types,uint guid_count,int is_container_object,uint auto_inherit_flags,HANDLE token,GENERIC_MAPPING &generic_mapping); -int CreateRestrictedToken(HANDLE existing_token_handle,uint flags,uint disable_sid_count,SID_AND_ATTRIBUTES &sids_to_disable,uint delete_privilege_count,LUID_AND_ATTRIBUTES &privileges_to_delete,uint restricted_sid_count,SID_AND_ATTRIBUTES &sids_to_restrict,HANDLE &new_token_handle); -int CreateWellKnownSid(WELL_KNOWN_SID_TYPE well_known_sid_type,SID &domain_sid,SID &sid,uint &sid); -int EqualDomainSid(SID &sid1,SID &sid2,int &equal); -int DeleteAce(ACL &acl,uint ace_index); -int DestroyPrivateObjectSecurity(SECURITY_DESCRIPTOR &object_descriptor); -int DuplicateToken(HANDLE existing_token_handle,SECURITY_IMPERSONATION_LEVEL impersonation_level,HANDLE &duplicate_token_handle); -int DuplicateTokenEx(HANDLE existing_token,uint desired_access,PVOID token_attributes,SECURITY_IMPERSONATION_LEVEL impersonation_level,TOKEN_TYPE token_type,HANDLE &new_token); -int EqualPrefixSid(SID &sid1,SID &sid2); -int EqualSid(SID &sid1,SID &sid2); -int FindFirstFreeAce(ACL &acl,PVOID &ace); -PVOID FreeSid(SID &sid); -int GetAce(ACL &acl,uint ace_index,PVOID &ace); -int GetAclInformation(ACL &acl,PVOID acl_information,uint acl_information_length,ACL_INFORMATION_CLASS acl_information_class); -int GetFileSecurityW(const string file_name,uint requested_information,SECURITY_DESCRIPTOR &security_descriptor,uint length,uint &length_needed); -int GetKernelObjectSecurity(HANDLE handle,uint requested_information,SECURITY_DESCRIPTOR &security_descriptor,uint length,uint &length_needed); -uint GetLengthSid(SID &sid); -int GetPrivateObjectSecurity(SECURITY_DESCRIPTOR &object_descriptor,uint security_information,SECURITY_DESCRIPTOR &resultant_descriptor,uint descriptor_length,uint &return_length); -int GetSecurityDescriptorControl(SECURITY_DESCRIPTOR &security_descriptor,ushort &control,uint &revision); -int GetSecurityDescriptorDacl(SECURITY_DESCRIPTOR &security_descriptor,int &dacl_present,ACL &dacl,int &dacl_defaulted); -int GetSecurityDescriptorGroup(SECURITY_DESCRIPTOR &security_descriptor,SID &group,int &group_defaulted); -uint GetSecurityDescriptorLength(SECURITY_DESCRIPTOR &security_descriptor); -int GetSecurityDescriptorOwner(SECURITY_DESCRIPTOR &security_descriptor,SID &owner,int &owner_defaulted); -uint GetSecurityDescriptorRMControl(SECURITY_DESCRIPTOR &security_descriptor,uchar &rm_control); -int GetSecurityDescriptorSacl(SECURITY_DESCRIPTOR &security_descriptor,int &sacl_present,ACL &sacl,int &sacl_defaulted); -PVOID GetSidIdentifierAuthority(SID &sid); -uint GetSidLengthRequired(uchar sub_authority_count); -PVOID GetSidSubAuthority(SID &sid,uint sub_authority); -PVOID GetSidSubAuthorityCount(SID &sid); -int GetTokenInformation(HANDLE token_handle,TOKEN_INFORMATION_CLASS token_information_class,PVOID &token_information,uint token_information_length,uint &return_length); -int GetWindowsAccountDomainSid(SID &sid,SID &domain_sid,uint &domain_sid); -int ImpersonateAnonymousToken(HANDLE thread_handle); -int ImpersonateLoggedOnUser(HANDLE token); -int ImpersonateSelf(SECURITY_IMPERSONATION_LEVEL impersonation_level); -int InitializeAcl(ACL &acl,uint acl_length,uint acl_revision); -int InitializeSecurityDescriptor(SECURITY_DESCRIPTOR &security_descriptor,uint revision); -int InitializeSid(SID &sid,SID_IDENTIFIER_AUTHORITY &identifier_authority,uchar sub_authority_count); -int IsTokenRestricted(HANDLE token_handle); -int IsValidAcl(ACL &acl); -int IsValidSecurityDescriptor(SECURITY_DESCRIPTOR &security_descriptor); -int IsValidSid(SID &sid); -int IsWellKnownSid(SID &sid,WELL_KNOWN_SID_TYPE well_known_sid_type); -int MakeAbsoluteSD(SECURITY_DESCRIPTOR &self_relative_security_descriptor,SECURITY_DESCRIPTOR &absolute_security_descriptor,uint &absolute_security_descriptor_size,ACL &dacl,uint &dacl_size,ACL &sacl,uint &sacl_size,SID &owner,uint &owner_size,SID &primary_group,uint &primary_group_size); -int MakeSelfRelativeSD(SECURITY_DESCRIPTOR &absolute_security_descriptor,SECURITY_DESCRIPTOR &self_relative_security_descriptor,uint &buffer_length); -void MapGenericMask(uint &access_mask,GENERIC_MAPPING &generic_mapping); -int ObjectCloseAuditAlarmW(const string subsystem_name,PVOID handle_id,int generate_on_close); -int ObjectDeleteAuditAlarmW(const string subsystem_name,PVOID handle_id,int generate_on_close); -int ObjectOpenAuditAlarmW(const string subsystem_name,PVOID handle_id,string object_type_name,string object_name,SECURITY_DESCRIPTOR &security_descriptor,HANDLE client_token,uint desired_access,uint granted_access,PRIVILEGE_SET &privileges,int object_creation,int access_granted,int &generate_on_close); -int ObjectPrivilegeAuditAlarmW(const string subsystem_name,PVOID handle_id,HANDLE client_token,uint desired_access,PRIVILEGE_SET &privileges,int access_granted); -int PrivilegeCheck(HANDLE client_token,PRIVILEGE_SET &required_privileges,int &result); -int PrivilegedServiceAuditAlarmW(const string subsystem_name,const string service_name,HANDLE client_token,PRIVILEGE_SET &privileges,int access_granted); -void QuerySecurityAccessMask(uint security_information,uint &desired_access); -int RevertToSelf(void); -int SetAclInformation(ACL &acl,PVOID acl_information,uint acl_information_length,ACL_INFORMATION_CLASS acl_information_class); -int SetFileSecurityW(const string file_name,uint security_information,SECURITY_DESCRIPTOR &security_descriptor); -int SetKernelObjectSecurity(HANDLE handle,uint security_information,SECURITY_DESCRIPTOR &security_descriptor); -int SetPrivateObjectSecurity(uint security_information,SECURITY_DESCRIPTOR &modification_descriptor,SECURITY_DESCRIPTOR &objects_security_descriptor,GENERIC_MAPPING &generic_mapping,HANDLE token); -int SetPrivateObjectSecurityEx(uint security_information,SECURITY_DESCRIPTOR &modification_descriptor,SECURITY_DESCRIPTOR &objects_security_descriptor,uint auto_inherit_flags,GENERIC_MAPPING &generic_mapping,HANDLE token); -void SetSecurityAccessMask(uint security_information,uint &desired_access); -int SetSecurityDescriptorControl(SECURITY_DESCRIPTOR &security_descriptor,ushort control_bits_of_interest,ushort control_bits_to_set); -int SetSecurityDescriptorDacl(SECURITY_DESCRIPTOR &security_descriptor,int dacl_present,ACL &dacl,int dacl_defaulted); -int SetSecurityDescriptorGroup(SECURITY_DESCRIPTOR &security_descriptor,SID &group,int group_defaulted); -int SetSecurityDescriptorOwner(SECURITY_DESCRIPTOR &security_descriptor,SID &owner,int owner_defaulted); -uint SetSecurityDescriptorRMControl(SECURITY_DESCRIPTOR &security_descriptor,uchar &rm_control); -int SetSecurityDescriptorSacl(SECURITY_DESCRIPTOR &security_descriptor,int sacl_present,ACL &sacl,int sacl_defaulted); -int SetTokenInformation(HANDLE token_handle,TOKEN_INFORMATION_CLASS token_information_class,PVOID token_information,uint token_information_length); -int CveEventWrite(const string cve_id,const string additional_details); -#import - -#import "kernel32.dll" -int AddResourceAttributeAce(ACL &acl,uint ace_revision,uint ace_flags,uint access_mask,SID &sid,CLAIM_SECURITY_ATTRIBUTES_INFORMATION &attribute_info,uint &return_length); -int AddScopedPolicyIDAce(ACL &acl,uint ace_revision,uint ace_flags,uint access_mask,SID &sid); -int CheckTokenCapability(HANDLE token_handle,SID &capability_sid_to_check,int &has_capability); -int GetAppContainerAce(ACL &acl,uint starting_ace_index,PVOID &app_container_ace,uint &app_container_ace_index); -int CheckTokenMembershipEx(HANDLE token_handle,SID &sid_to_check,uint flags,int &is_member); -int SetCachedSigningLevel(HANDLE &source_files,uint source_file_count,uint flags,HANDLE target_file); -int GetCachedSigningLevel(HANDLE file,ulong flags,ulong signing_level,uchar &thumbprint[],ulong thumbprint_size,ulong thumbprint_algorithm); -#import -//+------------------------------------------------------------------+ diff --git a/Include/WinAPI/sysinfoapi.mqh b/Include/WinAPI/sysinfoapi.mqh deleted file mode 100644 index 5bbc515..0000000 --- a/Include/WinAPI/sysinfoapi.mqh +++ /dev/null @@ -1,95 +0,0 @@ -//+------------------------------------------------------------------+ -//| sysinfoapi.mqh | -//| Copyright 2018, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include -#include - -//--- -enum COMPUTER_NAME_FORMAT - { - ComputerNameNetBIOS, - ComputerNameDnsHostname, - ComputerNameDnsDomain, - ComputerNameDnsFullyQualified, - ComputerNamePhysicalNetBIOS, - ComputerNamePhysicalDnsHostname, - ComputerNamePhysicalDnsDomain, - ComputerNamePhysicalDnsFullyQualified, - ComputerNameMax - }; -//--- -struct DUMMYSTRUCTNAME - { - uint dwOemId; - ushort wProcessorArchitecture; - ushort wReserved; - }; -//--- -struct MEMORYSTATUSEX - { - uint dwLength; - uint dwMemoryLoad; - ulong ullTotalPhys; - ulong ullAvailPhys; - ulong ullTotalPageFile; - ulong ullAvailPageFile; - ulong ullTotalVirtual; - ulong ullAvailVirtual; - ulong ullAvailExtendedVirtual; - }; -//--- -struct SYSTEM_INFO - { - uint dwOemId; - uint dwPageSize; - PVOID lpMinimumApplicationAddress; - PVOID lpMaximumApplicationAddress; - ulong dwActiveProcessorMask; - uint dwNumberOfProcessors; - uint dwProcessorType; - uint dwAllocationGranularity; - ushort wProcessorLevel; - ushort wProcessorRevision; - }; -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -#import "kernel32.dll" -int GlobalMemoryStatusEx(MEMORYSTATUSEX &buffer); -void GetSystemInfo(SYSTEM_INFO &system_info); -void GetSystemTime(SYSTEMTIME &system_time); -void GetSystemTimeAsFileTime(FILETIME &system_time_as_file_time); -void GetLocalTime(SYSTEMTIME &system_time); -uint GetVersion(void); -int SetLocalTime(const SYSTEMTIME &system_time); -uint GetTickCount(void); -ulong GetTickCount64(void); -int GetSystemTimeAdjustment(uint &time_adjustment,uint &time_increment,int &time_adjustment_disabled); -uint GetSystemDirectoryW(ushort &buffer[],uint size); -uint GetWindowsDirectoryW(ushort &buffer[],uint size); -uint GetSystemWindowsDirectoryW(ushort &buffer[],uint size); -int GetComputerNameExW(COMPUTER_NAME_FORMAT name_type,ushort &buffer[],uint &size); -int SetComputerNameExW(COMPUTER_NAME_FORMAT name_type,const string buffer); -int SetSystemTime(const SYSTEMTIME &system_time); -int GetVersionExW(OSVERSIONINFOW &version_information); -int GetLogicalProcessorInformation(SYSTEM_LOGICAL_PROCESSOR_INFORMATION &buffer[],uint &returned_length); -int GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP relationship_type,SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX &buffer[],uint &returned_length); -void GetNativeSystemInfo(SYSTEM_INFO &system_info); -void GetSystemTimePreciseAsFileTime(FILETIME &system_time_as_file_time); -int GetProductInfo(uint os_major_version,uint os_minor_version,uint sp_major_version,uint sp_minor_version,uint &returned_product_type); -uint EnumSystemFirmwareTables(uint firmware_table_provider_signature,PVOID &firmware_table_enum_buffer,uint buffer_size); -uint EnumSystemFirmwareTables(uint firmware_table_provider_signature,uchar &firmware_table_enum_buffer[],uint buffer_size); -uint GetSystemFirmwareTable(uint firmware_table_provider_signature,uint firmware_table_id,PVOID firmware_table_buffer,uint buffer_size); -uint GetSystemFirmwareTable(uint firmware_table_provider_signature,uint firmware_table_id,uchar &firmware_table_buffer[],uint buffer_size); -int DnsHostnameToComputerNameExW(const string hostname,ushort &computer_name[],uint &size); -int GetPhysicallyInstalledSystemMemory(ulong &total_memory_in_kilobytes); -int SetComputerNameEx2W(COMPUTER_NAME_FORMAT name_type,uint flags,const string buffer); -int SetSystemTimeAdjustment(uint time_adjustment,int time_adjustment_disabled); -int InstallELAMCertificateInfo(HANDLE elam_file); -int GetProcessorSystemCycleTime(ushort group,PVOID &buffer,uint &returned_length); -int GetProcessorSystemCycleTime(ushort group,SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION &buffer[],uint &returned_length); -int SetComputerNameW(const string computer_name); -#import -//+------------------------------------------------------------------+ diff --git a/Include/WinAPI/winapi.mqh b/Include/WinAPI/winapi.mqh deleted file mode 100644 index 47105b1..0000000 --- a/Include/WinAPI/winapi.mqh +++ /dev/null @@ -1,21 +0,0 @@ -//+------------------------------------------------------------------+ -//| winapi.mqh | -//| Copyright 2018, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include "windef.mqh" -#include "winnt.mqh" -#include "fileapi.mqh" -#include "winbase.mqh" -#include "winuser.mqh" -#include "wingdi.mqh" -#include "winreg.mqh" -#include "handleapi.mqh" -#include "processthreadsapi.mqh" -#include "securitybaseapi.mqh" -#include "errhandlingapi.mqh" -#include "sysinfoapi.mqh" -#include "processenv.mqh" -#include "libloaderapi.mqh" -#include "memoryapi.mqh" -//+------------------------------------------------------------------+ diff --git a/Include/WinAPI/winbase.mqh b/Include/WinAPI/winbase.mqh deleted file mode 100644 index 529fad1..0000000 --- a/Include/WinAPI/winbase.mqh +++ /dev/null @@ -1,814 +0,0 @@ -//+------------------------------------------------------------------+ -//| WinBase.mqh | -//| Copyright 2020, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include -#include -#include - -//--- -#define OFS_MAXPATHNAME 128 -#define HW_PROFILE_GUIDLEN 39 -#define MAX_PROFILE_LEN 80 -#define RESTART_MAX_CMD_LINE 1024 - -//--- -enum COPYFILE2_COPY_PHASE - { - COPYFILE2_PHASE_NONE=0, - COPYFILE2_PHASE_PREPARE_SOURCE, - COPYFILE2_PHASE_PREPARE_DEST, - COPYFILE2_PHASE_READ_SOURCE, - COPYFILE2_PHASE_WRITE_DESTINATION, - COPYFILE2_PHASE_SERVER_COPY, - COPYFILE2_PHASE_NAMEGRAFT_COPY, - COPYFILE2_PHASE_MAX - }; -//--- -enum COPYFILE2_MESSAGE_ACTION - { - COPYFILE2_PROGRESS_CONTINUE=0, - COPYFILE2_PROGRESS_CANCEL, - COPYFILE2_PROGRESS_STOP, - COPYFILE2_PROGRESS_QUIET, - COPYFILE2_PROGRESS_PAUSE - }; -//--- -enum COPYFILE2_MESSAGE_TYPE - { - COPYFILE2_CALLBACK_NONE=0, - COPYFILE2_CALLBACK_CHUNK_STARTED, - COPYFILE2_CALLBACK_CHUNK_FINISHED, - COPYFILE2_CALLBACK_STREAM_STARTED, - COPYFILE2_CALLBACK_STREAM_FINISHED, - COPYFILE2_CALLBACK_POLL_CONTINUE, - COPYFILE2_CALLBACK_ERROR, - COPYFILE2_CALLBACK_MAX - }; -//--- -enum DEP_SYSTEM_POLICY_TYPE - { - DEPPolicyAlwaysOff=0, - DEPPolicyAlwaysOn, - DEPPolicyOptIn, - DEPPolicyOptOut, - DEPTotalPolicyCount - }; -//--- -enum FILE_ID_TYPE - { - FileIdType, - ObjectIdType, - ExtendedFileIdType, - MaximumFileIdType - }; -//--- -enum PRIORITY_HINT - { - IoPriorityHintVeryLow=0, - IoPriorityHintLow, - IoPriorityHintNormal, - MaximumIoPriorityHintType - }; -//--- -enum PROC_THREAD_ATTRIBUTE_NUM - { - ProcThreadAttributeParentProcess=0, - ProcThreadAttributeHandleList=2, - ProcThreadAttributeGroupAffinity=3, - ProcThreadAttributePreferredNode=4, - ProcThreadAttributeIdealProcessor=5, - ProcThreadAttributeUmsThread=6, - ProcThreadAttributeMitigationPolicy=7, - ProcThreadAttributeSecurityCapabilities=9, - ProcThreadAttributeProtectionLevel=11, - ProcThreadAttributeJobList=13, - ProcThreadAttributeChildProcessPolicy=14, - ProcThreadAttributeAllApplicationPackagesPolicy=15, - ProcThreadAttributeWin32kFilter=16, - ProcThreadAttributeSafeOpenPromptOriginClaim=17, - ProcThreadAttributeDesktopAppPolicy=18 - }; -//--- -struct ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA - { - PVOID lpInformation; - PVOID lpSectionBase; - uint ulSectionLength; - PVOID lpSectionGlobalDataBase; - uint ulSectionGlobalDataLength; - }; -//--- -struct ACTCTX_SECTION_KEYED_DATA - { - uint cbSize; - uint ulDataFormatVersion; - PVOID lpData; - uint ulLength; - PVOID lpSectionGlobalData; - uint ulSectionGlobalDataLength; - PVOID lpSectionBase; - uint ulSectionTotalLength; - HANDLE hActCtx; - uint ulAssemblyRosterIndex; - uint ulFlags; - ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA AssemblyMetadata; - }; -//--- -struct ACTCTX_SECTION_KEYED_DATA_2600 - { - uint cbSize; - uint ulDataFormatVersion; - PVOID lpData; - uint ulLength; - PVOID lpSectionGlobalData; - uint ulSectionGlobalDataLength; - PVOID lpSectionBase; - uint ulSectionTotalLength; - HANDLE hActCtx; - uint ulAssemblyRosterIndex; - }; -//--- -struct ACTCTXW - { - uint cbSize; - uint dwFlags; - PVOID lpSource; - ushort wProcessorArchitecture; - ushort wLangId; - PVOID lpAssemblyDirectory; - PVOID lpResourceName; - PVOID lpApplicationName; - HANDLE hModule; - }; -//--- -struct ACTIVATION_CONTEXT_BASIC_INFORMATION - { - HANDLE hActCtx; - uint dwFlags; - }; -//--- -struct DCB - { - uint DCBlength; - uint BaudRate; - uint Flags; - ushort wReserved; - ushort XonLim; - ushort XoffLim; - uchar ByteSize; - uchar Parity; - uchar StopBits; - char XonChar; - char XoffChar; - char ErrorChar; - char EofChar; - char EvtChar; - ushort wReserved1; - }; -//--- -struct COMMCONFIG - { - uint dwSize; - ushort wVersion; - ushort wReserved; - DCB dcb; - uint dwProviderSubType; - uint dwProviderOffset; - uint dwProviderSize; - short wcProviderData[2]; - }; -//--- -struct COMMPROP - { - ushort wPacketLength; - ushort wPacketVersion; - uint dwServiceMask; - uint dwReserved1; - uint dwMaxTxQueue; - uint dwMaxRxQueue; - uint dwMaxBaud; - uint dwProvSubType; - uint dwProvCapabilities; - uint dwSettableParams; - uint dwSettableBaud; - ushort wSettableData; - ushort wSettableStopParity; - uint dwCurrentTxQueue; - uint dwCurrentRxQueue; - uint dwProvSpec1; - uint dwProvSpec2; - short wcProvChar[1]; - }; -//--- -struct COMMTIMEOUTS - { - uint ReadIntervalTimeout; - uint ReadTotalTimeoutMultiplier; - uint ReadTotalTimeoutConstant; - uint WriteTotalTimeoutMultiplier; - uint WriteTotalTimeoutConstant; - }; -//--- -struct COMSTAT - { - uint cbInQue; - uint cbOutQue; - }; -//--- -struct COPYFILE2_EXTENDED_PARAMETERS - { - uint dwSize; - uint dwCopyFlags; - PVOID pfCancel; - PVOID pProgressRoutine; - PVOID pvCallbackContext; - }; -//--- -struct EVENTLOG_FULL_INFORMATION - { - uint dwFull; - }; -//--- -struct FILE_ALIGNMENT_INFO: public FILE_INFO - { - uint AlignmentRequirement; - }; -//--- -struct FILE_ALLOCATION_INFO: public FILE_INFO - { - long AllocationSize; - }; -//--- -struct FILE_ATTRIBUTE_TAG_INFO: public FILE_INFO - { - uint FileAttributes; - uint ReparseTag; - }; -//--- -struct FILE_BASIC_INFO: public FILE_INFO - { - long CreationTime; - long LastAccessTime; - long LastWriteTime; - long ChangeTime; - uint FileAttributes; - }; -//--- -struct FILE_COMPRESSION_INFO: public FILE_INFO - { - long CompressedFileSize; - ushort CompressionFormat; - uchar CompressionUnitShift; - uchar ChunkShift; - uchar ClusterShift; - uchar Reserved[3]; - }; -//--- -struct FILE_DISPOSITION_INFO: public FILE_INFO - { - uchar DeleteFile; - }; -//--- -struct FILE_DISPOSITION_INFO_EX: public FILE_INFO - { - uint Flags; - }; -//--- -struct FILE_END_OF_FILE_INFO: public FILE_INFO - { - long EndOfFile; - }; -//--- -struct FILE_FULL_DIR_INFO: public FILE_INFO - { - uint NextEntryOffset; - uint FileIndex; - long CreationTime; - long LastAccessTime; - long LastWriteTime; - long ChangeTime; - long EndOfFile; - long AllocationSize; - uint FileAttributes; - uint FileNameLength; - uint EaSize; - short FileName[1]; - }; -//--- -struct FILE_ID_BOTH_DIR_INFO: public FILE_INFO - { - uint NextEntryOffset; - uint FileIndex; - long CreationTime; - long LastAccessTime; - long LastWriteTime; - long ChangeTime; - long EndOfFile; - long AllocationSize; - uint FileAttributes; - uint FileNameLength; - uint EaSize; - char ShortNameLength; - short ShortName[12]; - long FileId; - short FileName[1]; - }; -//--- -struct FILE_ID_EXTD_DIR_INFO: public FILE_INFO - { - uint NextEntryOffset; - uint FileIndex; - long CreationTime; - long LastAccessTime; - long LastWriteTime; - long ChangeTime; - long EndOfFile; - long AllocationSize; - uint FileAttributes; - uint FileNameLength; - uint EaSize; - uint ReparsePointTag; - FILE_ID_128 FileId; - short FileName[1]; - }; -//--- -struct FILE_ID_INFO: public FILE_INFO - { - ulong VolumeSerialNumber; - FILE_ID_128 FileId; - }; -//--- -struct FILE_IO_PRIORITY_HINT_INFO: public FILE_INFO - { - PRIORITY_HINT PriorityHint; - }; -//--- -struct FILE_NAME_INFO - { - uint FileNameLength; - short FileName[2]; - }; -//--- -struct FILE_STANDARD_INFO: public FILE_INFO - { - long AllocationSize; - long EndOfFile; - uint NumberOfLinks; - uchar DeletePending; - uchar Directory; - }; -//--- -struct FILE_STORAGE_INFO: public FILE_INFO - { - uint LogicalBytesPerSector; - uint PhysicalBytesPerSectorForAtomicity; - uint PhysicalBytesPerSectorForPerformance; - uint FileSystemEffectivePhysicalBytesPerSectorForAtomicity; - uint Flags; - uint ByteOffsetForSectorAlignment; - uint ByteOffsetForPartitionAlignment; - }; -//--- -struct FILE_STREAM_INFO: public FILE_INFO - { - uint NextEntryOffset; - uint StreamNameLength; - long StreamSize; - long StreamAllocationSize; - short StreamName[1]; - }; -//--- -struct HW_PROFILE_INFOW - { - uint dwDockInfo; - short szHwProfileGuid[HW_PROFILE_GUIDLEN]; - short szHwProfileName[MAX_PROFILE_LEN]; - }; -//--- -struct JIT_DEBUG_INFO - { - uint dwSize; - uint dwProcessorArchitecture; - uint dwThreadID; - uint dwReserved0; - ulong lpExceptionAddress; - ulong lpExceptionRecord; - ulong lpContextRecord; - }; -//--- -struct MEMORYSTATUS - { - uint dwLength; - uint dwMemoryLoad; - ulong dwTotalPhys; - ulong dwAvailPhys; - ulong dwTotalPageFile; - ulong dwAvailPageFile; - ulong dwTotalVirtual; - ulong dwAvailVirtual; - }; -//--- -struct OFSTRUCT - { - uchar cBytes; - uchar fFixedDisk; - ushort nErrCode; - ushort Reserved1; - ushort Reserved2; - char szPathName[OFS_MAXPATHNAME]; - }; -//--- -struct OPERATION_END_PARAMETERS - { - uint Version; - uint OperationId; - uint Flags; - }; -//--- -struct OPERATION_START_PARAMETERS - { - uint Version; - uint OperationId; - uint Flags; - }; -//--- -struct SYSTEM_POWER_STATUS - { - uchar ACLineStatus; - uchar BatteryFlag; - uchar BatteryLifePercent; - uchar SystemStatusFlag; - uint BatteryLifeTime; - uint BatteryFullLifeTime; - }; -//--- -struct UMS_SCHEDULER_STARTUP_INFO - { - uint UmsVersion; - PVOID CompletionList; - PVOID SchedulerProc; - PVOID SchedulerParam; - }; -//--- -struct WIN32_STREAM_ID - { - uint dwStreamId; - uint dwStreamAttributes; - long Size; - uint dwStreamNameSize; - }; -//--- -struct UMS_SYSTEM_THREAD_INFORMATION - { - uint UmsVersion; - uint ThreadUmsFlags; - }; -//--- -struct FILE_ID_DESCRIPTOR - { - uint dwSize; - FILE_ID_TYPE Type; - long FileId; - }; -//--- -struct SYSTEMTIME - { - ushort wYear; - ushort wMonth; - ushort wDayOfWeek; - ushort wDay; - ushort wHour; - ushort wMinute; - ushort wSecond; - ushort wMilliseconds; - }; -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -#import "kernel32.dll" -int ActivateActCtx(HANDLE act_ctx,PVOID &cookie); -int ActivateActCtx(ACTCTXW &act_ctx,PVOID &cookie); -ushort AddAtomW(const string str); -int AddIntegrityLabelToBoundaryDescriptor(HANDLE &BoundaryDescriptor,SID &IntegrityLabel); -void AddRefActCtx(HANDLE act_ctx); -void AddRefActCtx(ACTCTXW &act_ctx); -int AddSecureMemoryCacheCallback(PVOID call_back); -void ApplicationRecoveryFinished(int success); -int ApplicationRecoveryInProgress(int &cancelled); -int BackupRead(HANDLE file,uchar &buffer[],uint number_of_bytes_to_read,uint &number_of_bytes_read,int abort,int process_security,PVOID &context); -int BackupSeek(HANDLE file,uint low_bytes_to_seek,uint high_bytes_to_seek,uint &low_byte_seeked,uint &high_byte_seeked,PVOID &context); -int BackupWrite(HANDLE file,uchar &buffer[],uint number_of_bytes_to_write,uint &number_of_bytes_written,int abort,int process_security,PVOID &context); -HANDLE BeginUpdateResourceW(const string file_name,int delete_existing_resources); -int BindIoCompletionCallback(HANDLE FileHandle,PVOID Function,uint Flags); -int BuildCommDCBAndTimeoutsW(const string def,DCB &lpDCB,COMMTIMEOUTS &comm_timeouts); -int BuildCommDCBW(const string def,DCB &lpDCB); -int CancelDeviceWakeupRequest(HANDLE device); -int CancelTimerQueueTimer(HANDLE TimerQueue,HANDLE Timer); -int CheckNameLegalDOS8Dot3W(const string name,char &oem_name[],uint oem_name_size,int &name_contains_spaces,int &name_legal); -int ClearCommBreak(HANDLE file); -int ClearCommError(HANDLE file,uint &errors,COMSTAT &stat); -int CommConfigDialogW(const string name,HANDLE wnd,COMMCONFIG &lpCC); -int ConvertFiberToThread(void); -PVOID ConvertThreadToFiber(PVOID parameter); -PVOID ConvertThreadToFiberEx(PVOID parameter,uint flags); -int CopyContext(CONTEXT &Destination,uint ContextFlags,CONTEXT &Source); -int CopyFile2(const string existing_file_name,const string new_file_name,COPYFILE2_EXTENDED_PARAMETERS &extended_parameters); -int CopyFileExW(const string existing_file_name,const string new_file_name,PVOID progress_routine,PVOID data,int &cancel,uint copy_flags); -int CopyFileTransactedW(const string existing_file_name,const string new_file_name,PVOID progress_routine,PVOID data,int &cancel,uint copy_flags,HANDLE transaction); -int CopyFileW(const string existing_file_name,const string new_file_name,int fail_if_exists); -HANDLE CreateActCtxW(const ACTCTXW &act_ctx); -int CreateDirectoryExW(const string template_directory,const string new_directory,PVOID security_attributes); -int CreateDirectoryTransactedW(const string template_directory,const string new_directory,PVOID security_attributes,HANDLE transaction); -PVOID CreateFiber(ulong stack_size,PVOID start_address,PVOID parameter); -PVOID CreateFiberEx(ulong stack_commit_size,ulong stack_reserve_size,uint flags,PVOID start_address,PVOID parameter); -HANDLE CreateFileTransactedW(const string file_name,uint desired_access,uint share_mode,PVOID security_attributes,uint creation_disposition,uint flags_and_attributes,HANDLE template_file,HANDLE transaction,ushort &mini_version,PVOID extended_parameter); -int CreateHardLinkTransactedW(const string file_name,const string existing_file_name,PVOID security_attributes,HANDLE transaction); -int CreateHardLinkW(const string file_name,const string existing_file_name,PVOID security_attributes); -int CreateJobSet(uint NumJob,JOB_SET_ARRAY &UserJobSet,uint Flags); -HANDLE CreateMailslotW(const string name,uint max_message_size,uint read_timeout,PVOID security_attributes); -uchar CreateSymbolicLinkTransactedW(const string symlink_file_name,const string target_file_name,uint flags,HANDLE transaction); -uchar CreateSymbolicLinkW(const string symlink_file_name,const string target_file_name,uint flags); -uint CreateTapePartition(HANDLE device,uint partition_method,uint count,uint size); -int CreateUmsCompletionList(PVOID &UmsCompletionList); -int CreateUmsThreadContext(PVOID &ums_thread); -int DeactivateActCtx(uint flags,ulong cookie); -int DebugBreakProcess(HANDLE Process); -int DebugSetProcessKillOnExit(int KillOnExit); -ushort DeleteAtom(ushort atom); -void DeleteFiber(PVOID fiber); -int DeleteFileTransactedW(const string file_name,HANDLE transaction); -int DeleteTimerQueue(HANDLE TimerQueue); -int DeleteUmsCompletionList(PVOID UmsCompletionList); -int DeleteUmsThreadContext(PVOID UmsThread); -int DequeueUmsCompletionListItems(PVOID UmsCompletionList,uint WaitTimeOut,PVOID &UmsThreadList); -uint DisableThreadProfiling(HANDLE PerformanceDataHandle); -int DnsHostnameToComputerNameW(const string hostname,ushort &computer_name[],uint &size); -int DosDateTimeToFileTime(ushort fat_date,ushort fat_time,FILETIME &file_time); -uint EnableThreadProfiling(HANDLE ThreadHandle,uint Flags,ulong HardwareCounters,HANDLE &PerformanceDataHandle); -int EndUpdateResourceW(HANDLE update,int discard); -int EnterUmsSchedulingMode(UMS_SCHEDULER_STARTUP_INFO &SchedulerStartupInfo); -int EnumResourceLanguagesW(HANDLE module,const string type,const string name,PVOID enum_func,long param); -int EnumResourceTypesW(HANDLE module,PVOID enum_func,long param); -uint EraseTape(HANDLE device,uint erase_type,int immediate); -int EscapeCommFunction(HANDLE file,uint func); -int ExecuteUmsThread(PVOID UmsThread); -void FatalExit(int ExitCode); -int FileTimeToDosDateTime(FILETIME &file_time,ushort &fat_date,ushort &fat_time); -int FindActCtxSectionGuid(uint flags,const GUID &extension_guid[],uint section_id,const GUID &guid_to_find[],ACTCTX_SECTION_KEYED_DATA &ReturnedData); -int FindActCtxSectionStringW(uint flags,const GUID &extension_guid[],uint section_id,const string string_to_find,ACTCTX_SECTION_KEYED_DATA &ReturnedData); -ushort FindAtomW(const string str); -HANDLE FindFirstFileNameTransactedW(const string file_name,uint flags,uint &StringLength,string LinkName,HANDLE transaction); -HANDLE FindFirstFileTransactedW(const string file_name,FINDEX_INFO_LEVELS info_level_id,FIND_DATAW &find_file_data,FINDEX_SEARCH_OPS search_op,PVOID search_filter,uint additional_flags,HANDLE transaction); -HANDLE FindFirstStreamTransactedW(const string file_name,STREAM_INFO_LEVELS InfoLevel,FIND_STREAM_DATA &find_stream_data,uint flags,HANDLE transaction); -HANDLE FindFirstVolumeMountPointW(const string root_path_name,ushort &volume_mount_point[],uint buffer_length); -int FindNextVolumeMountPointW(HANDLE find_volume_mount_point,string volume_mount_point,uint buffer_length); -int FindVolumeMountPointClose(HANDLE find_volume_mount_point); -uint FormatMessageW(uint flags,const uchar &source[],uint message_id,uint language_id,ushort &buffer[],uint size,PVOID &Arguments[]); -uint GetActiveProcessorCount(ushort GroupNumber); -ushort GetActiveProcessorGroupCount(void); -int GetApplicationRecoveryCallback(HANDLE process,PVOID &recovery_callback,PVOID ¶meter,uint &ping_interval,uint &flags); -int GetApplicationRestartSettings(HANDLE process,ushort &commandline[],uint &size,uint &flags); -uint GetAtomNameW(ushort atom,ushort &buffer[],int size); -int GetBinaryTypeW(const string application_name,uint &binary_type); -int GetCommConfig(HANDLE comm_dev,COMMCONFIG &lpCC,uint &size); -int GetCommMask(HANDLE file,uint &evt_mask); -int GetCommModemStatus(HANDLE file,uint &modem_stat); -int GetCommProperties(HANDLE file,COMMPROP &comm_prop); -int GetCommState(HANDLE file,DCB &lpDCB); -int GetCommTimeouts(HANDLE file,COMMTIMEOUTS &comm_timeouts); -uint GetCompressedFileSizeTransactedW(const string file_name,uint &file_size_high,HANDLE transaction); -int GetComputerNameW(ushort &buffer[],uint &size); -int GetCurrentActCtx(HANDLE &act_ctx); -int GetCurrentActCtx(ACTCTXW &act_ctx); -PVOID GetCurrentUmsThread(void); -int GetDefaultCommConfigW(const string name,COMMCONFIG &lpCC,uint &size); -int GetDevicePowerState(HANDLE device,int &on); -uint GetDllDirectoryW(uint buffer_length,ushort &buffer[]); -ulong GetEnabledXStateFeatures(void); -int GetFileAttributesTransactedW(const string file_name,GET_FILEEX_INFO_LEVELS info_level_id,PVOID file_information,HANDLE transaction); -int GetFileBandwidthReservation(HANDLE file,uint &period_milliseconds,uint &bytes_per_period,int &discardable,uint &transfer_size,uint &num_outstanding_requests); -int GetFileInformationByHandleEx(HANDLE file,FILE_INFO_BY_HANDLE_CLASS FileInformationClass,PVOID file_information,uint buffer_size); -int GetFileInformationByHandleEx(HANDLE file,FILE_INFO_BY_HANDLE_CLASS FileInformationClass,uchar &file_information[],uint buffer_size); -uint GetFirmwareEnvironmentVariableExW(const string name,const string guid,PVOID buffer,uint size,uint &attribubutes); -uint GetFirmwareEnvironmentVariableW(const string name,const string guid,PVOID buffer,uint size); -int GetFirmwareType(FIRMWARE_TYPE &FirmwareType); -uint GetFullPathNameTransactedW(const string file_name,uint buffer_length,string buffer,string &file_part,HANDLE transaction); -uint GetLongPathNameTransactedW(const string short_path,string long_path,uint buffer,HANDLE transaction); -int GetMailslotInfo(HANDLE mailslot,uint &max_message_size,uint &next_size,uint &message_count,uint &read_timeout); -uint GetMaximumProcessorCount(ushort GroupNumber); -ushort GetMaximumProcessorGroupCount(void); -int GetNamedPipeClientProcessId(HANDLE Pipe,uint &ClientProcessId); -int GetNamedPipeClientSessionId(HANDLE Pipe,uint &ClientSessionId); -int GetNamedPipeServerProcessId(HANDLE Pipe,uint &ServerProcessId); -int GetNamedPipeServerSessionId(HANDLE Pipe,uint &ServerSessionId); -PVOID GetNextUmsListItem(PVOID UmsContext); -int GetNumaAvailableMemoryNode(uchar Node,ulong &AvailableBytes); -int GetNumaAvailableMemoryNodeEx(ushort Node,ulong &AvailableBytes); -int GetNumaNodeNumberFromHandle(HANDLE file,ushort &NodeNumber); -int GetNumaNodeProcessorMask(uchar Node,ulong &ProcessorMask); -int GetNumaProcessorNode(uchar Processor,uchar &NodeNumber); -int GetNumaProcessorNodeEx(PROCESSOR_NUMBER &Processor,ushort &NodeNumber); -int GetNumaProximityNode(uint ProximityId,uchar &NodeNumber); -uint GetPrivateProfileIntW(const string app_name,const string key_name,int default_value,const string file_name); -uint GetPrivateProfileSectionNamesW(string return_buffer,uint size,const string file_name); -uint GetPrivateProfileSectionW(const string app_name,string returned_string,uint size,const string file_name); -uint GetPrivateProfileStringW(const string app_name,const string key_name,const string default_value,string returned_string,uint size,const string file_name); -int GetPrivateProfileStructW(const string section,const string key,PVOID struct_obj,uint size_struct,const string file); -int GetProcessAffinityMask(HANDLE process,ulong &process_affinity_mask,ulong &system_affinity_mask); -int GetProcessDEPPolicy(HANDLE process,uint &flags,int &permanent); -int GetProcessIoCounters(HANDLE process,IO_COUNTERS &io_counters); -int GetProcessWorkingSetSize(HANDLE process,ulong &minimum_working_set_size,ulong &maximum_working_set_size); -uint GetProfileIntW(const string app_name,const string key_name,int default_value); -uint GetProfileSectionW(const string app_name,string returned_string,uint size); -uint GetProfileStringW(const string app_name,const string key_name,const string default_value,string returned_string,uint size); -DEP_SYSTEM_POLICY_TYPE GetSystemDEPPolicy(void); -int GetSystemPowerStatus(SYSTEM_POWER_STATUS &system_power_status); -int GetSystemRegistryQuota(uint "a_allowed,uint "a_used); -uint GetTapeParameters(HANDLE device,uint operation,uint &size,PVOID tape_information); -uint GetTapePosition(HANDLE device,uint position_type,uint &partition,uint &offset_low,uint &offset_high); -uint GetTapeStatus(HANDLE device); -int GetThreadSelectorEntry(HANDLE thread,uint selector,LDT_ENTRY &selector_entry); -int GetUmsCompletionListEvent(PVOID UmsCompletionList,HANDLE &UmsCompletionEvent); -int GetUmsSystemThreadInformation(HANDLE ThreadHandle,UMS_SYSTEM_THREAD_INFORMATION &SystemThreadInfo); -int GetXStateFeaturesMask(CONTEXT &Context,ulong &FeatureMask); -ushort GlobalAddAtomExW(const string str,uint Flags); -ushort GlobalAddAtomW(const string str); -HANDLE GlobalAlloc(uint flags,ulong bytes); -ulong GlobalCompact(uint min_free); -ushort GlobalDeleteAtom(ushort atom); -ushort GlobalFindAtomW(const string str); -void GlobalFix(HANDLE mem); -uint GlobalFlags(HANDLE mem); -HANDLE GlobalFree(HANDLE mem); -uint GlobalGetAtomNameW(ushort atom,ushort &buffer[],int size); -HANDLE GlobalHandle(const PVOID mem); -PVOID GlobalLock(HANDLE mem); -void GlobalMemoryStatus(MEMORYSTATUS &buffer); -HANDLE GlobalReAlloc(HANDLE mem,ulong bytes,uint flags); -ulong GlobalSize(HANDLE mem); -void GlobalUnfix(HANDLE mem); -int GlobalUnlock(HANDLE mem); -int GlobalUnWire(HANDLE mem); -PVOID GlobalWire(HANDLE mem); -int InitAtomTable(uint size); -int InitializeContext(uchar &Buffer[],uint ContextFlags,CONTEXT &Context,uint &ContextLength); -int InitializeContext(PVOID Buffer,uint ContextFlags,CONTEXT &Context,uint &ContextLength); -int IsBadCodePtr(PVOID lpfn); -int IsBadHugeReadPtr(PVOID lp,ulong ucb); -int IsBadHugeWritePtr(PVOID lp,ulong ucb); -int IsBadReadPtr(PVOID lp,ulong ucb); -int IsBadStringPtrW(const string lpsz,ulong max); -int IsBadWritePtr(PVOID lp,ulong ucb); -int IsNativeVhdBoot(int &NativeVhdBoot); -int IsSystemResumeAutomatic(void); -HANDLE LoadPackagedLibrary(const string lib_file_name,uint Reserved); -HANDLE LocalAlloc(uint flags,ulong bytes); -ulong LocalCompact(uint min_free); -uint LocalFlags(HANDLE mem); -HANDLE LocalFree(HANDLE mem); -HANDLE LocalHandle(const PVOID mem); -PVOID LocalLock(HANDLE mem); -HANDLE LocalReAlloc(HANDLE mem,ulong bytes,uint flags); -ulong LocalShrink(HANDLE mem,uint new_size); -ulong LocalSize(HANDLE mem); -int LocalUnlock(HANDLE mem); -PVOID LocateXStateFeature(CONTEXT &Context,uint FeatureId,uint &Length); -string lstrcatW(ushort &string1[],const string string2); -int lstrcmpiW(const string string1,const string string2); -int lstrcmpW(const string string1,const string string2); -string lstrcpynW(ushort &string1[],const string string2,int max_length); -string lstrcpyW(ushort &string1[],const string string2); -int lstrlenW(const string str); -int MapUserPhysicalPagesScatter(PVOID &VirtualAddresses[],ulong NumberOfPages,ulong &PageArray[]); -PVOID MapViewOfFileExNuma(HANDLE file_mapping_object,uint desired_access,uint file_offset_high,uint file_offset_low,ulong number_of_bytes_to_map,PVOID base_address,uint preferred); -int MoveFileExW(const string existing_file_name,const string new_file_name,uint flags); -int MoveFileTransactedW(const string existing_file_name,const string new_file_name,PVOID progress_routine,PVOID data,uint flags,HANDLE transaction); -int MoveFileW(const string existing_file_name,const string new_file_name); -int MoveFileWithProgressW(const string existing_file_name,const string new_file_name,PVOID progress_routine,PVOID data,uint flags); -int MulDiv(int number,int numerator,int denominator); -HANDLE OpenFileById(HANDLE volume_hint,FILE_ID_DESCRIPTOR &file_id,uint desired_access,uint share_mode,PVOID security_attributes,uint flags_and_attributes); -int PowerClearRequest(HANDLE PowerRequest,POWER_REQUEST_TYPE RequestType); -HANDLE PowerCreateRequest(REASON_CONTEXT &Context); -int PowerSetRequest(HANDLE PowerRequest,POWER_REQUEST_TYPE RequestType); -uint PrepareTape(HANDLE device,uint operation,int immediate); -int PulseEvent(HANDLE event); -int PurgeComm(HANDLE file,uint flags); -int QueryActCtxSettingsW(uint flags,HANDLE act_ctx,const string name_space,const string name,string buffer,ulong buffer,ulong &written_or_required); -int QueryActCtxSettingsW(uint flags,ACTCTXW &act_ctx,const string name_space,const string name,string buffer,ulong buffer,ulong &written_or_required); -int QueryActCtxW(uint flags,HANDLE act_ctx,PVOID sub_instance,uint info_class,PVOID buffer,ulong buffer,ulong &written_or_required); -int QueryActCtxW(uint flags,ACTCTXW &act_ctx,PVOID sub_instance,uint info_class,PVOID buffer,ulong buffer,ulong &written_or_required); -int QueryFullProcessImageNameW(HANDLE process,uint flags,string exe_name,uint &size); -uint QueryThreadProfiling(HANDLE ThreadHandle,uchar &Enabled); -int QueryUmsThreadInformation(PVOID UmsThread,RTL_UMS_THREAD_INFO_CLASS UmsThreadInfoClass,PVOID UmsThreadInformation,uint UmsThreadInformationLength,uint &ReturnLength); -int ReadDirectoryChangesExW(HANDLE directory,PVOID buffer,uint buffer_length,int watch_subtree,uint notify_filter,uint &bytes_returned,OVERLAPPED &overlapped,PVOID completion_routine,READ_DIRECTORY_NOTIFY_INFORMATION_CLASS ReadDirectoryNotifyInformationClass); -int ReadDirectoryChangesW(HANDLE directory,PVOID buffer,uint buffer_length,int watch_subtree,uint notify_filter,uint &bytes_returned,OVERLAPPED &overlapped,PVOID completion_routine); -uint ReadThreadProfilingData(HANDLE PerformanceDataHandle,uint Flags,PERFORMANCE_DATA &PerformanceData); -int RegisterApplicationRecoveryCallback(PVOID recovey_callback,PVOID parameter,uint ping_interval,uint flags); -int RegisterApplicationRestart(const string commandline,uint flags); -int RegisterWaitForSingleObject(HANDLE &new_wait_object,HANDLE object,PVOID Callback,PVOID Context,uint milliseconds,uint flags); -void ReleaseActCtx(HANDLE act_ctx); -void ReleaseActCtx(ACTCTXW &act_ctx); -int RemoveDirectoryTransactedW(const string path_name,HANDLE transaction); -int RemoveSecureMemoryCacheCallback(PVOID call_back); -HANDLE ReOpenFile(HANDLE original_file,uint desired_access,uint share_mode,uint flags_and_attributes); -int ReplaceFileW(const string replaced_file_name,const string replacement_file_name,const string backup_file_name,uint replace_flags,PVOID exclude,PVOID reserved); -int ReplacePartitionUnit(string TargetPartition,string SparePartition,uint Flags); -int RequestDeviceWakeup(HANDLE device); -int RequestWakeupLatency(LATENCY_TIME latency); -void RestoreLastError(uint err_code); -int SetCommBreak(HANDLE file); -int SetCommConfig(HANDLE comm_dev,COMMCONFIG &lpCC,uint size); -int SetCommMask(HANDLE file,uint evt_mask); -int SetCommState(HANDLE file,DCB &lpDCB); -int SetCommTimeouts(HANDLE file,COMMTIMEOUTS &comm_timeouts); -int SetDefaultCommConfigW(const string name,COMMCONFIG &lpCC,uint size); -int SetDllDirectoryW(const string path_name); -int SetFileAttributesTransactedW(const string file_name,uint file_attributes,HANDLE transaction); -int SetFileBandwidthReservation(HANDLE file,uint period_milliseconds,uint bytes_per_period,int discardable,uint &transfer_size,uint &num_outstanding_requests); -int SetFileCompletionNotificationModes(HANDLE FileHandle,uchar Flags); -int SetFileShortNameW(HANDLE file,const string short_name); -int SetFirmwareEnvironmentVariableExW(const string name,const string guid,PVOID value,uint size,uint attributes); -int SetFirmwareEnvironmentVariableW(const string name,const string guid,PVOID value,uint size); -uint SetHandleCount(uint number); -int SetMailslotInfo(HANDLE mailslot,uint read_timeout); -int SetMessageWaitingIndicator(HANDLE msg_indicator,uint msg_count); -int SetProcessAffinityMask(HANDLE process,PVOID process_affinity_mask); -int SetProcessDEPPolicy(uint flags); -int SetProcessWorkingSetSize(HANDLE process,ulong minimum_working_set_size,ulong maximum_working_set_size); -int SetSearchPathMode(uint flags); -int SetSystemPowerState(int suspend,int force); -uint SetTapeParameters(HANDLE device,uint operation,PVOID tape_information); -uint SetTapePosition(HANDLE device,uint position_method,uint partition,uint offset_low,uint offset_high,int immediate); -PVOID SetThreadAffinityMask(HANDLE thread,PVOID thread_affinity_mask); -uint SetThreadExecutionState(uint flags); -HANDLE SetTimerQueueTimer(HANDLE TimerQueue,PVOID Callback,PVOID Parameter,uint DueTime,uint Period,int PreferIo); -int SetUmsThreadInformation(PVOID UmsThread,RTL_UMS_THREAD_INFO_CLASS UmsThreadInfoClass,PVOID UmsThreadInformation,uint UmsThreadInformationLength); -int SetupComm(HANDLE file,uint in_queue,uint out_queue); -int SetVolumeLabelW(const string root_path_name,const string volume_name); -int SetVolumeMountPointW(const string volume_mount_point,const string volume_name); -int SetXStateFeaturesMask(CONTEXT &Context,ulong FeatureMask); -uint SignalObjectAndWait(HANDLE object_to_signal,HANDLE object_to_wait_on,uint milliseconds,int alertable); -void SwitchToFiber(PVOID fiber); -int TransmitCommChar(HANDLE file,char symbol); -int UmsThreadYield(PVOID SchedulerParam); -int UnregisterApplicationRecoveryCallback(void); -int UnregisterApplicationRestart(void); -int UnregisterWait(HANDLE WaitHandle); -int UpdateResourceW(HANDLE update,const string type,const string name,ushort &language,PVOID data,uint cb); -int VerifyVersionInfoW(OSVERSIONINFOEXW &version_information,uint type_mask,ulong condition_mask); -int WaitCommEvent(HANDLE file,uint &evt_mask,OVERLAPPED &overlapped); -uchar Wow64EnableWow64FsRedirection(uchar Wow64FsEnableRedirection); -int Wow64GetThreadContext(HANDLE thread,CONTEXT &context); -int Wow64GetThreadSelectorEntry(HANDLE thread,uint selector,LDT_ENTRY &selector_entry); -int Wow64SetThreadContext(HANDLE thread,CONTEXT &context); -uint Wow64SuspendThread(HANDLE thread); -int WritePrivateProfileSectionW(const string app_name,const string str,const string file_name); -int WritePrivateProfileStringW(const string app_name,const string key_name,const string str,const string file_name); -int WritePrivateProfileStructW(const string section,const string key,PVOID struct_obj,uint size_struct,const string file); -int WriteProfileSectionW(const string app_name,const string str); -int WriteProfileStringW(const string app_name,const string key_name,const string str); -uint WriteTapemark(HANDLE device,uint tapemark_type,uint tapemark_count,int immediate); -uint WTSGetActiveConsoleSessionId(void); -int ZombifyActCtx(HANDLE act_ctx); -int ZombifyActCtx(ACTCTXW &act_ctx); -#import - -#import "advapi32.dll" -int AddConditionalAce(ACL &acl,uint ace_revision,uint AceFlags,uchar AceType,uint AccessMask,SID &sid,string ConditionStr,uint &ReturnLength); -int BackupEventLogW(HANDLE event_log,const string backup_file_name); -int ClearEventLogW(HANDLE event_log,const string backup_file_name); -void CloseEncryptedFileRaw(PVOID context); -int CloseEventLog(HANDLE event_log); -int DecryptFileW(const string file_name,uint reserved); -int DeregisterEventSource(HANDLE event_log); -int EncryptFileW(const string file_name); -int FileEncryptionStatusW(const string file_name,uint &status); -int GetCurrentHwProfileW(HW_PROFILE_INFOW &hw_profile_info); -int GetEventLogInformation(HANDLE event_log,uint info_level,PVOID buffer,uint buf_size,uint &bytes_needed); -int GetNumberOfEventLogRecords(HANDLE event_log,uint &NumberOfRecords); -int GetOldestEventLogRecord(HANDLE event_log,uint &OldestRecord); -int GetUserNameW(string buffer,uint &buffer); -int IsTextUnicode(PVOID lpv,int size,int &result); -int IsTokenUntrusted(HANDLE TokenHandle); -int LogonUserExW(const string username,const string domain,const string password,uint logon_type,uint logon_provider,HANDLE &token,PVOID &logon_sid,PVOID &profile_buffer,uint &profile_length,QUOTA_LIMITS "a_limits); -int LogonUserW(const string username,const string domain,const string password,uint logon_type,uint logon_provider,HANDLE &token); -int LookupAccountNameW(const string system_name,const string account_name,SID &Sid,uint &sid,string ReferencedDomainName,uint &referenced_domain_name,SID_NAME_USE &use); -int LookupAccountSidW(const string system_name,SID &Sid,string Name,uint &name,string ReferencedDomainName,uint &referenced_domain_name,SID_NAME_USE &use); -int LookupPrivilegeDisplayNameW(const string system_name,const string name,string display_name,uint &display_name,uint &language_id); -int LookupPrivilegeNameW(const string system_name,LUID &luid,string name,uint &name); -int LookupPrivilegeValueW(const string system_name,const string name,LUID &luid); -int NotifyChangeEventLog(HANDLE event_log,HANDLE event); -HANDLE OpenBackupEventLogW(const string lpUNCServerName,const string file_name); -uint OpenEncryptedFileRawW(const string file_name,uint flags,PVOID &context); -HANDLE OpenEventLogW(const string lpUNCServerName,const string source_name); -int OperationEnd(OPERATION_END_PARAMETERS &OperationEndParams); -int OperationStart(OPERATION_START_PARAMETERS &OperationStartParams); -uint ReadEncryptedFileRaw(PVOID export_callback,PVOID callback_context,PVOID context); -int ReadEventLogW(HANDLE event_log,uint read_flags,uint record_offset,PVOID buffer,uint number_of_bytes_to_read,uint &bytes_read,uint &min_number_of_bytes_needed); -HANDLE RegisterEventSourceW(const string lpUNCServerName,const string source_name); -int ReportEventW(HANDLE event_log,ushort &type,ushort &category,uint dwEventID,SID &user_sid,ushort &num_strings,uint data_size,const string &strings[],PVOID raw_data); -uint WriteEncryptedFileRaw(PVOID import_callback,PVOID callback_context,PVOID context); -#import -//+------------------------------------------------------------------+ diff --git a/Include/WinAPI/windef.mqh b/Include/WinAPI/windef.mqh deleted file mode 100644 index bac0fbc..0000000 --- a/Include/WinAPI/windef.mqh +++ /dev/null @@ -1,325 +0,0 @@ -//+------------------------------------------------------------------+ -//| windef.mqh | -//| Copyright 2018, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#define HANDLE long -#define PVOID long -//--- -#define ANYSIZE_ARRAY 1 -#define MAX_BREAKPOINTS 8 -#define MAX_WATCHPOINTS 2 -#define MAX_HW_COUNTERS 16 -#define MAX_PATH 260 -#define EXCEPTION_MAXIMUM_PARAMETERS 15 - -//--- -enum LATENCY_TIME - { - LT_DONT_CARE, - LT_LOWEST_LATENCY - }; -//--- -enum GET_FILEEX_INFO_LEVELS - { - GetFileExInfoStandard, - GetFileExMaxInfoLevel - }; -//--- -enum FINDEX_INFO_LEVELS - { - FindExInfoStandard, - FindExInfoBasic, - FindExInfoMaxInfoLevel - }; -//--- -enum FINDEX_SEARCH_OPS - { - FindExSearchNameMatch, - FindExSearchLimitToDirectories, - FindExSearchLimitToDevices, - FindExSearchMaxSearchOp - }; -//--- -enum DPI_AWARENESS - { - DPI_AWARENESS_INVALID=-1, - DPI_AWARENESS_UNAWARE=0, - DPI_AWARENESS_SYSTEM_AWARE=1, - DPI_AWARENESS_PER_MONITOR_AWARE=2 - }; -//--- -enum DPI_HOSTING_BEHAVIOR - { - DPI_HOSTING_BEHAVIOR_INVALID=-1, - DPI_HOSTING_BEHAVIOR_DEFAULT=0, - DPI_HOSTING_BEHAVIOR_MIXED=1 - }; -//--- -enum FILE_INFO_BY_HANDLE_CLASS - { - FileBasicInfo=0, - FileStandardInfo=1, - FileNameInfo=2, - FileRenameInfo=3, - FileDispositionInfo= 4, - FileAllocationInfo = 5, - FileEndOfFileInfo=6, - FileStreamInfo=7, - FileCompressionInfo=8, - FileAttributeTagInfo=9, - FileIdBothDirectoryInfo=10, - FileIdBothDirectoryRestartInfo=11, - FileIoPriorityHintInfo = 12, - FileRemoteProtocolInfo = 13, - FileFullDirectoryInfo=14, - FileFullDirectoryRestartInfo=15, - FileStorageInfo=16, - FileAlignmentInfo=17, - FileIdInfo=18, - FileIdExtdDirectoryInfo=19, - FileIdExtdDirectoryRestartInfo=20, - MaximumFileInfoByHandlesClass - }; -//--- -enum READ_DIRECTORY_NOTIFY_INFORMATION_CLASS - { - ReadDirectoryNotifyInformation=1, - ReadDirectoryNotifyExtendedInformation - }; -//--- -enum WELL_KNOWN_SID_TYPE - { - WinNullSid=0, - WinWorldSid= 1, - WinLocalSid= 2, - WinCreatorOwnerSid= 3, - WinCreatorGroupSid= 4, - WinCreatorOwnerServerSid=5, - WinCreatorGroupServerSid= 6, - WinNtAuthoritySid=7, - WinDialupSid=8, - WinNetworkSid=9, - WinBatchSid=10, - WinInteractiveSid=11, - WinServiceSid=12, - WinAnonymousSid=13, - WinProxySid=14, - WinEnterpriseControllersSid=15, - WinSelfSid=16, - WinAuthenticatedUserSid=17, - WinRestrictedCodeSid= 18, - WinTerminalServerSid= 19, - WinRemoteLogonIdSid=20, - WinLogonIdsSid=21, - WinLocalSystemSid=22, - WinLocalServiceSid=23, - WinNetworkServiceSid=24, - WinBuiltinDomainSid=25, - WinBuiltinAdministratorsSid=26, - WinBuiltinUsersSid=27, - WinBuiltinGuestsSid=28, - WinBuiltinPowerUsersSid=29, - WinBuiltinAccountOperatorsSid=30, - WinBuiltinSystemOperatorsSid=31, - WinBuiltinPrintOperatorsSid=32, - WinBuiltinBackupOperatorsSid=33, - WinBuiltinReplicatorSid=34, - WinBuiltinPreWindows2000CompatibleAccessSid=35, - WinBuiltinRemoteDesktopUsersSid=36, - WinBuiltinNetworkConfigurationOperatorsSid=37, - WinAccountAdministratorSid=38, - WinAccountGuestSid=39, - WinAccountKrbtgtSid=40, - WinAccountDomainAdminsSid=41, - WinAccountDomainUsersSid=42, - WinAccountDomainGuestsSid=43, - WinAccountComputersSid=44, - WinAccountControllersSid=45, - WinAccountCertAdminsSid=46, - WinAccountSchemaAdminsSid=47, - WinAccountEnterpriseAdminsSid=48, - WinAccountPolicyAdminsSid=49, - WinAccountRasAndIasServersSid=50, - WinNTLMAuthenticationSid=51, - WinDigestAuthenticationSid=52, - WinSChannelAuthenticationSid=53, - WinThisOrganizationSid=54, - WinOtherOrganizationSid=55, - WinBuiltinIncomingForestTrustBuildersSid=56, - WinBuiltinPerfMonitoringUsersSid=57, - WinBuiltinPerfLoggingUsersSid=58, - WinBuiltinAuthorizationAccessSid=59, - WinBuiltinTerminalServerLicenseServersSid=60, - WinBuiltinDCOMUsersSid=61, - WinBuiltinIUsersSid=62, - WinIUserSid=63, - WinBuiltinCryptoOperatorsSid=64, - WinUntrustedLabelSid=65, - WinLowLabelSid=66, - WinMediumLabelSid=67, - WinHighLabelSid=68, - WinSystemLabelSid=69, - WinWriteRestrictedCodeSid=70, - WinCreatorOwnerRightsSid=71, - WinCacheablePrincipalsGroupSid=72, - WinNonCacheablePrincipalsGroupSid=73, - WinEnterpriseReadonlyControllersSid=74, - WinAccountReadonlyControllersSid=75, - WinBuiltinEventLogReadersGroup=76, - WinNewEnterpriseReadonlyControllersSid=77, - WinBuiltinCertSvcDComAccessGroup=78, - WinMediumPlusLabelSid=79, - WinLocalLogonSid=80, - WinConsoleLogonSid=81, - WinThisOrganizationCertificateSid= 82, - WinApplicationPackageAuthoritySid= 83, - WinBuiltinAnyPackageSid=84, - WinCapabilityInternetClientSid=85, - WinCapabilityInternetClientServerSid=86, - WinCapabilityPrivateNetworkClientServerSid=87, - WinCapabilityPicturesLibrarySid=88, - WinCapabilityVideosLibrarySid=89, - WinCapabilityMusicLibrarySid=90, - WinCapabilityDocumentsLibrarySid=91, - WinCapabilitySharedUserCertificatesSid=92, - WinCapabilityEnterpriseAuthenticationSid=93, - WinCapabilityRemovableStorageSid=94, - WinBuiltinRDSRemoteAccessServersSid=95, - WinBuiltinRDSEndpointServersSid=96, - WinBuiltinRDSManagementServersSid=97, - WinUserModeDriversSid=98, - WinBuiltinHyperVAdminsSid=99, - WinAccountCloneableControllersSid=100, - WinBuiltinAccessControlAssistanceOperatorsSid=101, - WinBuiltinRemoteManagementUsersSid=102, - WinAuthenticationAuthorityAssertedSid=103, - WinAuthenticationServiceAssertedSid=104, - WinLocalAccountSid=105, - WinLocalAccountAndAdministratorSid=106, - WinAccountProtectedUsersSid=107, - WinCapabilityAppointmentsSid=108, - WinCapabilityContactsSid=109, - WinAccountDefaultSystemManagedSid=110, - WinBuiltinDefaultSystemManagedGroupSid=111, - WinBuiltinStorageReplicaAdminsSid=112, - WinAccountKeyAdminsSid=113, - WinAccountEnterpriseKeyAdminsSid=114, - WinAuthenticationKeyTrustSid=115, - WinAuthenticationKeyPropertyMFASid=116, - WinAuthenticationKeyPropertyAttestationSid=117, - WinAuthenticationFreshKeyAuthSid=118, - WinBuiltinDeviceOwnersSid=119 - }; -//--- -union FILE_SEGMENT_ELEMENT - { - PVOID Buffer; - ulong Alignment; - }; -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -//--- -struct REASON_CONTEXT - { - uint Version; - uint Flags; - PVOID Reason; - }; -//--- -struct OVERLAPPED - { - PVOID Internal; - PVOID InternalHigh; - uint Offset; - uint OffsetHigh; - HANDLE hEvent; - }; -//--- -struct LDT_ENTRY - { - ushort LimitLow; - ushort BaseLow; - uchar BaseMid; - uchar Flags1; - uchar Flags2; - uchar BaseHi; - }; -//--- -struct GUID - { - ulong Data1; - ushort Data2; - ushort Data3; - uchar Data4[8]; - }; -//--- -struct FILETIME - { - uint dwLowDateTime; - uint dwHighDateTime; - }; -//--- -struct POINT - { - int x; - int y; - }; -//--- -struct POINTL - { - int x; - int y; - }; -//--- -struct POINTS - { - short x; - short y; - }; -//--- -struct RECT - { - int left; - int top; - int right; - int bottom; - }; -//--- -struct RECTL - { - int left; - int top; - int right; - int bottom; - }; -//--- -struct SIZE - { - int cx; - int cy; - }; -//--- -struct FILE_INFO - { - }; -//--- -struct CLAIM_SECURITY_ATTRIBUTE_V1 - { - PVOID Name; - ushort ValueType; - ushort Reserved; - uint Flags; - uint ValueCount; - PVOID Values; - }; -//--- -struct CLAIM_SECURITY_ATTRIBUTES_INFORMATION - { - ushort Version; - ushort Reserved; - uint AttributeCount; - PVOID Attribute; - }; -//+------------------------------------------------------------------+ diff --git a/Include/WinAPI/wingdi.mqh b/Include/WinAPI/wingdi.mqh deleted file mode 100644 index 81ffe5c..0000000 --- a/Include/WinAPI/wingdi.mqh +++ /dev/null @@ -1,2080 +0,0 @@ -//+------------------------------------------------------------------+ -//| wingdi.mqh | -//| Copyright 2020, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include -#include - -//--- -#define MM_MAX_AXES_NAMELEN 16 -#define MM_MAX_NUMAXES 16 -#define CCHDEVICENAME 32 -#define LF_FACESIZE 32 -#define LF_FULLFACESIZE 64 -#define ELF_VENDOR_SIZE 4 -#define CCHFORMNAME 32 - -//--- -enum DISPLAYCONFIG_COLOR_ENCODING - { - DISPLAYCONFIG_COLOR_ENCODING_RGB=0, - DISPLAYCONFIG_COLOR_ENCODING_YCBCR444=1, - DISPLAYCONFIG_COLOR_ENCODING_YCBCR422=2, - DISPLAYCONFIG_COLOR_ENCODING_YCBCR420=3, - DISPLAYCONFIG_COLOR_ENCODING_INTENSITY=4, - DISPLAYCONFIG_COLOR_ENCODING_FORCE_UINT32=0xFFFFFFFF - }; -//--- -enum DISPLAYCONFIG_DEVICE_INFO_TYPE - { - DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME=1, - DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME=2, - DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE=3, - DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME=4, - DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE=5, - DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE=6, - DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION=7, - DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION=8, - DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO=9, - DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE=10, - DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL=11, - DISPLAYCONFIG_DEVICE_INFO_FORCE_UINT32=0xFFFFFFFF - }; -//--- -enum DISPLAYCONFIG_MODE_INFO_TYPE - { - DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE=1, - DISPLAYCONFIG_MODE_INFO_TYPE_TARGET=2, - DISPLAYCONFIG_MODE_INFO_TYPE_DESKTOP_IMAGE=3, - DISPLAYCONFIG_MODE_INFO_TYPE_FORCE_UINT32=0xFFFFFFFF - }; -//--- -enum DISPLAYCONFIG_PIXELFORMAT - { - DISPLAYCONFIG_PIXELFORMAT_8BPP=1, - DISPLAYCONFIG_PIXELFORMAT_16BPP=2, - DISPLAYCONFIG_PIXELFORMAT_24BPP=3, - DISPLAYCONFIG_PIXELFORMAT_32BPP=4, - DISPLAYCONFIG_PIXELFORMAT_NONGDI=5, - DISPLAYCONFIG_PIXELFORMAT_FORCE_UINT32=0xffffffff - }; -//--- -enum DISPLAYCONFIG_ROTATION - { - DISPLAYCONFIG_ROTATION_IDENTITY=1, - DISPLAYCONFIG_ROTATION_ROTATE90=2, - DISPLAYCONFIG_ROTATION_ROTATE180=3, - DISPLAYCONFIG_ROTATION_ROTATE270=4, - DISPLAYCONFIG_ROTATION_FORCE_UINT32=0xFFFFFFFF - }; -//--- -enum DISPLAYCONFIG_SCALING - { - DISPLAYCONFIG_SCALING_IDENTITY=1, - DISPLAYCONFIG_SCALING_CENTERED=2, - DISPLAYCONFIG_SCALING_STRETCHED=3, - DISPLAYCONFIG_SCALING_ASPECTRATIOCENTEREDMAX=4, - DISPLAYCONFIG_SCALING_CUSTOM=5, - DISPLAYCONFIG_SCALING_PREFERRED=128, - DISPLAYCONFIG_SCALING_FORCE_UINT32=0xFFFFFFFF - }; -//--- -enum DISPLAYCONFIG_SCANLINE_ORDERING - { - DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED=0, - DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE=1, - DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED=2, - DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_UPPERFIELDFIRST=DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED, - DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_LOWERFIELDFIRST=3, - DISPLAYCONFIG_SCANLINE_ORDERING_FORCE_UINT32=0xFFFFFFFF - }; -//--- -enum DISPLAYCONFIG_TOPOLOGY_ID - { - DISPLAYCONFIG_TOPOLOGY_INTERNAL=0x00000001, - DISPLAYCONFIG_TOPOLOGY_CLONE=0x00000002, - DISPLAYCONFIG_TOPOLOGY_EXTEND=0x00000004, - DISPLAYCONFIG_TOPOLOGY_EXTERNAL=0x00000008, - DISPLAYCONFIG_TOPOLOGY_FORCE_UINT32=0xFFFFFFFF - }; -//--- -enum DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY - { - DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER=-1, - DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15=0, - DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SVIDEO=1, - DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPOSITE_VIDEO=2, - DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPONENT_VIDEO=3, - DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DVI=4, - DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDMI=5, - DISPLAYCONFIG_OUTPUT_TECHNOLOGY_LVDS=6, - DISPLAYCONFIG_OUTPUT_TECHNOLOGY_D_JPN=8, - DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDI=9, - DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL=10, - DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED=11, - DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EXTERNAL=12, - DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EMBEDDED=13, - DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDTVDONGLE=14, - DISPLAYCONFIG_OUTPUT_TECHNOLOGY_MIRACAST=15, - DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INDIRECT_WIRED=16, - DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL=0x80000000, - DISPLAYCONFIG_OUTPUT_TECHNOLOGY_FORCE_UINT32=0xFFFFFFFF - }; -//--- -struct ABC - { - int abcA; - uint abcB; - int abcC; - }; -//--- -struct ABCFLOAT - { - float abcfA; - float abcfB; - float abcfC; - }; -//--- -struct AXISINFOW - { - int axMinValue; - int axMaxValue; - short axAxisName[MM_MAX_AXES_NAMELEN]; - }; -//--- -struct AXESLISTW - { - uint axlReserved; - uint axlNumAxes; - AXISINFOW axlAxisInfo[MM_MAX_NUMAXES]; - }; -//--- -struct BITMAP - { - int bmType; - int bmWidth; - int bmHeight; - int bmWidthBytes; - ushort bmPlanes; - ushort bmBitsPixel; - PVOID bmBits; - }; -//--- -struct BITMAPCOREHEADER - { - uint bcSize; - ushort bcWidth; - ushort bcHeight; - ushort bcPlanes; - ushort bcBitCount; - }; -//--- -struct BITMAPFILEHEADER - { - ushort bfType; - uint bfSize; - ushort bfReserved1; - ushort bfReserved2; - uint bfOffBits; - }; -//--- -struct RGBTRIPLE - { - uchar rgbtBlue; - uchar rgbtGreen; - uchar rgbtRed; - }; -//--- -struct BITMAPCOREINFO - { - BITMAPCOREHEADER bmciHeader; - RGBTRIPLE bmciColors[1]; - }; -//--- -struct BITMAPINFOHEADER - { - uint biSize; - int biWidth; - int biHeight; - ushort biPlanes; - ushort biBitCount; - uint biCompression; - uint biSizeImage; - int biXPelsPerMeter; - int biYPelsPerMeter; - uint biClrUsed; - uint biClrImportant; - }; -//--- -struct RGBQUAD - { - uchar rgbBlue; - uchar rgbGreen; - uchar rgbRed; - uchar rgbReserved; - }; -//--- -struct BITMAPINFO - { - BITMAPINFOHEADER bmiHeader; - RGBQUAD bmiColors[1]; - }; -//--- -struct CIEXYZ - { - int ciexyzX; - int ciexyzY; - int ciexyzZ; - }; -//--- -struct CIEXYZTRIPLE - { - CIEXYZ ciexyzRed; - CIEXYZ ciexyzGreen; - CIEXYZ ciexyzBlue; - }; -//--- -struct BITMAPV4HEADER - { - uint bV4Size; - int bV4Width; - int bV4Height; - ushort bV4Planes; - ushort bV4BitCount; - uint bV4V4Compression; - uint bV4SizeImage; - int bV4XPelsPerMeter; - int bV4YPelsPerMeter; - uint bV4ClrUsed; - uint bV4ClrImportant; - uint bV4RedMask; - uint bV4GreenMask; - uint bV4BlueMask; - uint bV4AlphaMask; - uint bV4CSType; - CIEXYZTRIPLE bV4Endpoints; - uint bV4GammaRed; - uint bV4GammaGreen; - uint bV4GammaBlue; - }; -//--- -struct BITMAPV5HEADER - { - uint bV5Size; - int bV5Width; - int bV5Height; - ushort bV5Planes; - ushort bV5BitCount; - uint bV5Compression; - uint bV5SizeImage; - int bV5XPelsPerMeter; - int bV5YPelsPerMeter; - uint bV5ClrUsed; - uint bV5ClrImportant; - uint bV5RedMask; - uint bV5GreenMask; - uint bV5BlueMask; - uint bV5AlphaMask; - uint bV5CSType; - CIEXYZTRIPLE bV5Endpoints; - uint bV5GammaRed; - uint bV5GammaGreen; - uint bV5GammaBlue; - uint bV5Intent; - uint bV5ProfileData; - uint bV5ProfileSize; - uint bV5Reserved; - }; -//--- -struct BLENDFUNCTION - { - uchar BlendOp; - uchar BlendFlags; - uchar SourceConstantAlpha; - uchar AlphaFormat; - }; -//--- -struct FONTSIGNATURE - { - uint fsUsb[4]; - uint fsCsb[2]; - }; -//--- -struct CHARSETINFO - { - uint ciCharset; - uint ciACP; - FONTSIGNATURE fs; - }; -//--- -struct COLORADJUSTMENT - { - ushort caSize; - ushort caFlags; - ushort caIlluminantIndex; - ushort caRedGamma; - ushort caGreenGamma; - ushort caBlueGamma; - ushort caReferenceBlack; - ushort caReferenceWhite; - short caContrast; - short caBrightness; - short caColorfulness; - short caRedGreenTint; - }; -//--- -struct DESIGNVECTOR - { - uint dvReserved; - uint dvNumAxes; - int dvValues[MM_MAX_NUMAXES]; - }; -//--- -struct DIBSECTION - { - BITMAP dsBm; - BITMAPINFOHEADER dsBmih; - uint dsBitfields[3]; - HANDLE dshSection; - uint dsOffset; - }; -//--- -struct DISPLAY_DEVICEA - { - uint cb; - char DeviceName[32]; - char DeviceString[128]; - uint StateFlags; - char DeviceID[128]; - char DeviceKey[128]; - }; -//--- -struct DISPLAY_DEVICEW - { - uint cb; - short DeviceName[32]; - short DeviceString[128]; - uint StateFlags; - short DeviceID[128]; - short DeviceKey[128]; - }; -//--- -struct DISPLAYCONFIG_2DREGION - { - uint cx; - uint cy; - }; -//--- -struct DISPLAYCONFIG_DEVICE_INFO_HEADER - { - DISPLAYCONFIG_DEVICE_INFO_TYPE type; - uint size; - LUID adapterId; - uint id; - }; -//--- -struct DISPLAYCONFIG_ADAPTER_NAME - { - DISPLAYCONFIG_DEVICE_INFO_HEADER header; - short adapterDevicePath[128]; - }; -//--- -struct DISPLAYCONFIG_DESKTOP_IMAGE_INFO - { - POINTL PathSourceSize; - RECTL DesktopImageRegion; - RECTL DesktopImageClip; - }; -//--- -struct DISPLAYCONFIG_PATH_SOURCE_INFO - { - LUID adapterId; - uint id; - uint modeInfoIdx; - uint statusFlags; - }; -//--- -struct DISPLAYCONFIG_RATIONAL - { - uint Numerator; - uint Denominator; - }; -//--- -struct DISPLAYCONFIG_PATH_TARGET_INFO - { - LUID adapterId; - uint id; - uint modeInfoIdx; - DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology; - DISPLAYCONFIG_ROTATION rotation; - DISPLAYCONFIG_SCALING scaling; - DISPLAYCONFIG_RATIONAL refreshRate; - DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering; - int targetAvailable; - uint statusFlags; - }; -//--- -struct DISPLAYCONFIG_PATH_INFO - { - DISPLAYCONFIG_PATH_SOURCE_INFO sourceInfo; - DISPLAYCONFIG_PATH_TARGET_INFO targetInfo; - uint flags; - }; -//--- -struct DISPLAYCONFIG_SDR_WHITE_LEVEL - { - DISPLAYCONFIG_DEVICE_INFO_HEADER header; - uint SDRWhiteLevel; - }; -//--- -struct DISPLAYCONFIG_SOURCE_DEVICE_NAME - { - DISPLAYCONFIG_DEVICE_INFO_HEADER header; - short viewGdiDeviceName[CCHDEVICENAME]; - }; -//--- -struct DISPLAYCONFIG_SOURCE_MODE - { - uint width; - uint height; - DISPLAYCONFIG_PIXELFORMAT pixelFormat; - POINTL position; - }; -//--- -struct DISPLAYCONFIG_TARGET_BASE_TYPE - { - DISPLAYCONFIG_DEVICE_INFO_HEADER header; - DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY baseOutputTechnology; - }; -//--- -struct DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS - { - uint value; - }; -//--- -struct DISPLAYCONFIG_TARGET_DEVICE_NAME - { - DISPLAYCONFIG_DEVICE_INFO_HEADER header; - DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS flags; - DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology; - ushort edidManufactureId; - ushort edidProductCodeId; - uint connectorInstance; - short monitorFriendlyDeviceName[64]; - short monitorDevicePath[128]; - }; -//--- -struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO - { - ulong pixelRate; - DISPLAYCONFIG_RATIONAL hSyncFreq; - DISPLAYCONFIG_RATIONAL vSyncFreq; - DISPLAYCONFIG_2DREGION activeSize; - DISPLAYCONFIG_2DREGION totalSize; - uint videoStandard; - DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering; - }; -//--- -struct DISPLAYCONFIG_TARGET_MODE - { - DISPLAYCONFIG_VIDEO_SIGNAL_INFO targetVideoSignalInfo; - }; -//--- -struct DISPLAYCONFIG_TARGET_PREFERRED_MODE - { - DISPLAYCONFIG_DEVICE_INFO_HEADER header; - uint width; - uint height; - DISPLAYCONFIG_TARGET_MODE targetMode; - }; -//--- -struct DOCINFOW - { - int cbSize; - const string lpszDocName; - const string lpszOutput; - const string lpszDatatype; - uint fwType; - }; -//--- -struct DRAWPATRECT - { - POINT ptPosition; - POINT ptSize; - ushort wStyle; - ushort wPattern; - }; -//--- -struct EMR - { - uint iType; - uint nSize; - }; -//--- -struct EMRABORTPATH - { - EMR emr; - }; -//--- -struct XFORM - { - float eM11; - float eM12; - float eM21; - float eM22; - float eDx; - float eDy; - }; -//--- -struct EMRALPHABLEND - { - EMR emr; - RECTL rclBounds; - int xDest; - int yDest; - int cxDest; - int cyDest; - uint dwRop; - int xSrc; - int ySrc; - XFORM xformSrc; - uint crBkColorSrc; - uint iUsageSrc; - uint offBmiSrc; - uint cbBmiSrc; - uint offBitsSrc; - uint cbBitsSrc; - int cxSrc; - int cySrc; - }; -//--- -struct EMRANGLEARC - { - EMR emr; - POINTL ptlCenter; - uint nRadius; - float eStartAngle; - float eSweepAngle; - }; -//--- -struct EMRARC - { - EMR emr; - RECTL rclBox; - POINTL ptlStart; - POINTL ptlEnd; - }; -//--- -struct EMRBITBLT - { - EMR emr; - RECTL rclBounds; - int xDest; - int yDest; - int cxDest; - int cyDest; - uint dwRop; - int xSrc; - int ySrc; - XFORM xformSrc; - uint crBkColorSrc; - uint iUsageSrc; - uint offBmiSrc; - uint cbBmiSrc; - uint offBitsSrc; - uint cbBitsSrc; - }; -//--- -struct EMRCOLORCORRECTPALETTE - { - EMR emr; - uint ihPalette; - uint nFirstEntry; - uint nPalEntries; - uint nReserved; - }; -//--- -struct EMRCOLORMATCHTOTARGET - { - EMR emr; - uint dwAction; - uint dwFlags; - uint cbName; - uint cbData; - uchar Data[1]; - }; -//--- -struct LOGBRUSH - { - uint lbStyle; - uint lbColor; - ulong lbHatch; - }; -//--- -struct EMRCREATEBRUSHINDIRECT - { - EMR emr; - uint ihBrush; - LOGBRUSH lb; - }; -//--- -struct LOGCOLORSPACEW - { - uint lcsSignature; - uint lcsVersion; - uint lcsSize; - int lcsCSType; - int lcsIntent; - CIEXYZTRIPLE lcsEndpoints; - uint lcsGammaRed; - uint lcsGammaGreen; - uint lcsGammaBlue; - short lcsFilename[MAX_PATH]; - }; -//--- -struct EMRCREATECOLORSPACEW - { - EMR emr; - uint ihCS; - LOGCOLORSPACEW lcs; - uint dwFlags; - uint cbData; - uchar Data[1]; - }; -//--- -struct EMRCREATEDIBPATTERNBRUSHPT - { - EMR emr; - uint ihBrush; - uint iUsage; - uint offBmi; - uint cbBmi; - uint offBits; - uint cbBits; - }; -//--- -struct EMRCREATEMONOBRUSH - { - EMR emr; - uint ihBrush; - uint iUsage; - uint offBmi; - uint cbBmi; - uint offBits; - uint cbBits; - }; -//--- -struct LOGPALETTE - { - ushort palVersion; - ushort palNumEntries; - }; -//--- -struct LOGPEN - { - uint lopnStyle; - POINT lopnWidth; - uint lopnColor; - }; -//--- -struct EMRCREATEPALETTE - { - EMR emr; - uint ihPal; - LOGPALETTE lgpl; - }; -//--- -struct EMRCREATEPEN - { - EMR emr; - uint ihPen; - LOGPEN lopn; - }; -//--- -struct EMRELLIPSE - { - EMR emr; - RECTL rclBox; - }; -//--- -struct EMREOF - { - EMR emr; - uint nPalEntries; - uint offPalEntries; - uint nSizeLast; - }; -//--- -struct EMREXCLUDECLIPRECT - { - EMR emr; - RECTL rclClip; - }; -//--- -struct LOGFONTW - { - int lfHeight; - int lfWidth; - int lfEscapement; - int lfOrientation; - int lfWeight; - uchar lfItalic; - uchar lfUnderline; - uchar lfStrikeOut; - uchar lfCharSet; - uchar lfOutPrecision; - uchar lfClipPrecision; - uchar lfQuality; - uchar lfPitchAndFamily; - short lfFaceName[LF_FACESIZE]; - }; -//--- -struct PANOSE - { - uchar bFamilyType; - uchar bSerifStyle; - uchar bWeight; - uchar bProportion; - uchar bContrast; - uchar bStrokeVariation; - uchar bArmStyle; - uchar bLetterform; - uchar bMidline; - uchar bXHeight; - }; -//--- -struct EXTLOGFONTW - { - LOGFONTW elfLogFont; - short elfFullName[LF_FULLFACESIZE]; - short elfStyle[LF_FACESIZE]; - uint elfVersion; - uint elfStyleSize; - uint elfMatch; - uint elfReserved; - uchar elfVendorId[ELF_VENDOR_SIZE]; - uint elfCulture; - PANOSE elfPanose; - }; -//--- -struct EMREXTCREATEFONTINDIRECTW - { - EMR emr; - uint ihFont; - EXTLOGFONTW elfw; - }; -//--- -struct EXTLOGPEN - { - uint elpPenStyle; - uint elpWidth; - uint elpBrushStyle; - uint elpColor; - ulong elpHatch; - uint elpNumEntries; - uint elpStyleEntry[1]; - }; -//--- -struct EMREXTCREATEPEN - { - EMR emr; - uint ihPen; - uint offBmi; - uint cbBmi; - uint offBits; - uint cbBits; - EXTLOGPEN elp; - }; -//--- -struct EMREXTESCAPE - { - EMR emr; - int iEscape; - int cbEscData; - uchar EscData[1]; - }; -//--- -struct EMREXTFLOODFILL - { - EMR emr; - POINTL ptlStart; - uint crColor; - uint iMode; - }; -//--- -struct EMREXTSELECTCLIPRGN - { - EMR emr; - uint cbRgnData; - uint iMode; - uchar RgnData[1]; - }; -//--- -struct EMRTEXT - { - POINTL ptlReference; - uint nChars; - uint offString; - uint fOptions; - RECTL rcl; - uint offDx; - }; -//--- -struct EMREXTTEXTOUTA - { - EMR emr; - RECTL rclBounds; - uint iGraphicsMode; - float exScale; - float eyScale; - EMRTEXT emrtext; - }; -//--- -struct EMRFILLPATH - { - EMR emr; - RECTL rclBounds; - }; -//--- -struct EMRFILLRGN - { - EMR emr; - RECTL rclBounds; - uint cbRgnData; - uint ihBrush; - uchar RgnData[1]; - }; -//--- -struct EMRFORMAT - { - uint dSignature; - uint nVersion; - uint cbData; - uint offData; - }; -//--- -struct EMRFRAMERGN - { - EMR emr; - RECTL rclBounds; - uint cbRgnData; - uint ihBrush; - SIZE szlStroke; - uchar RgnData[1]; - }; -//--- -struct EMRGDICOMMENT - { - EMR emr; - uint cbData; - uchar Data[1]; - }; -//--- -struct EMRGLSBOUNDEDRECORD - { - EMR emr; - RECTL rclBounds; - uint cbData; - uchar Data[1]; - }; -//--- -struct EMRGLSRECORD - { - EMR emr; - uint cbData; - uchar Data[1]; - }; -//--- -struct PIXELFORMATDESCRIPTOR - { - ushort nSize; - ushort nVersion; - uint dwFlags; - uchar iPixelType; - uchar cColorBits; - uchar cRedBits; - uchar cRedShift; - uchar cGreenBits; - uchar cGreenShift; - uchar cBlueBits; - uchar cBlueShift; - uchar cAlphaBits; - uchar cAlphaShift; - uchar cAccumBits; - uchar cAccumRedBits; - uchar cAccumGreenBits; - uchar cAccumBlueBits; - uchar cAccumAlphaBits; - uchar cDepthBits; - uchar cStencilBits; - uchar cAuxBuffers; - uchar iLayerType; - uchar bReserved; - uint dwLayerMask; - uint dwVisibleMask; - uint dwDamageMask; - }; -//--- -struct TRIVERTEX - { - int x; - int y; - ushort red; - ushort green; - ushort blue; - ushort alpha; - }; -//--- -struct EMRGRADIENTFILL - { - EMR emr; - RECTL rclBounds; - uint nVer; - uint nTri; - uint ulMode; - TRIVERTEX Ver[1]; - }; -//--- -struct EMRINVERTRGN - { - EMR emr; - RECTL rclBounds; - uint cbRgnData; - uchar RgnData[1]; - }; -//--- -struct EMRLINETO - { - EMR emr; - POINTL ptl; - }; -//--- -struct EMRMASKBLT - { - EMR emr; - RECTL rclBounds; - int xDest; - int yDest; - int cxDest; - int cyDest; - uint dwRop; - int xSrc; - int ySrc; - XFORM xformSrc; - uint crBkColorSrc; - uint iUsageSrc; - uint offBmiSrc; - uint cbBmiSrc; - uint offBitsSrc; - uint cbBitsSrc; - int xMask; - int yMask; - uint iUsageMask; - uint offBmiMask; - uint cbBmiMask; - uint offBitsMask; - uint cbBitsMask; - }; -//--- -struct EMRMODIFYWORLDTRANSFORM - { - EMR emr; - XFORM xform; - uint iMode; - }; -//--- -struct EMRNAMEDESCAPE - { - EMR emr; - int iEscape; - int cbDriver; - int cbEscData; - uchar EscData[1]; - }; -//--- -struct EMROFFSETCLIPRGN - { - EMR emr; - POINTL ptlOffset; - }; -//--- -struct EMRPIXELFORMAT - { - EMR emr; - PIXELFORMATDESCRIPTOR pfd; - }; -//--- -struct EMRPLGBLT - { - EMR emr; - RECTL rclBounds; - POINTL aptlDest[3]; - int xSrc; - int ySrc; - int cxSrc; - int cySrc; - XFORM xformSrc; - uint crBkColorSrc; - uint iUsageSrc; - uint offBmiSrc; - uint cbBmiSrc; - uint offBitsSrc; - uint cbBitsSrc; - int xMask; - int yMask; - uint iUsageMask; - uint offBmiMask; - uint cbBmiMask; - uint offBitsMask; - uint cbBitsMask; - }; -//--- -struct EMRPOLYDRAW - { - EMR emr; - RECTL rclBounds; - uint cptl; - POINTL aptl[1]; - uchar abTypes[1]; - }; -//--- -struct EMRPOLYDRAW16 - { - EMR emr; - RECTL rclBounds; - uint cpts; - POINTS apts[1]; - uchar abTypes[1]; - }; -//--- -struct EMRPOLYLINE - { - EMR emr; - RECTL rclBounds; - uint cptl; - POINTL aptl[1]; - }; -//--- -struct EMRPOLYLINE16 - { - EMR emr; - RECTL rclBounds; - uint cpts; - POINTS apts[1]; - }; -//--- -struct EMRPOLYPOLYLINE - { - EMR emr; - RECTL rclBounds; - uint nPolys; - uint cptl; - uint aPolyCounts[1]; - POINTL aptl[1]; - }; -//--- -struct EMRPOLYPOLYLINE16 - { - EMR emr; - RECTL rclBounds; - uint nPolys; - uint cpts; - uint aPolyCounts[1]; - POINTS apts[1]; - }; -//--- -struct EMRPOLYTEXTOUTW - { - EMR emr; - RECTL rclBounds; - uint iGraphicsMode; - float exScale; - float eyScale; - int cStrings; - EMRTEXT aemrtext[1]; - }; -//--- -struct EMRRESIZEPALETTE - { - EMR emr; - uint ihPal; - uint cEntries; - }; -//--- -struct EMRRESTOREDC - { - EMR emr; - int iRelative; - }; -//--- -struct EMRROUNDRECT - { - EMR emr; - RECTL rclBox; - SIZE szlCorner; - }; -//--- -struct EMRSCALEVIEWPORTEXTEX - { - EMR emr; - int xNum; - int xDenom; - int yNum; - int yDenom; - }; -//--- -struct EMRSELECTCLIPPATH - { - EMR emr; - uint iMode; - }; -//--- -struct EMRSELECTOBJECT - { - EMR emr; - uint ihObject; - }; -//--- -struct EMRSELECTPALETTE - { - EMR emr; - uint ihPal; - }; -//--- -struct EMRSETARCDIRECTION - { - EMR emr; - uint iArcDirection; - }; -//--- -struct EMRSETBKCOLOR - { - EMR emr; - uint crColor; - }; -//--- -struct EMRSETCOLORADJUSTMENT - { - EMR emr; - COLORADJUSTMENT ColorAdjustment; - }; -//--- -struct EMRSETCOLORSPACE - { - EMR emr; - uint ihCS; - }; -//--- -struct EMRSETDIBITSTODEVICE - { - EMR emr; - RECTL rclBounds; - int xDest; - int yDest; - int xSrc; - int ySrc; - int cxSrc; - int cySrc; - uint offBmiSrc; - uint cbBmiSrc; - uint offBitsSrc; - uint cbBitsSrc; - uint iUsageSrc; - uint iStartScan; - uint cScans; - }; -//--- -struct EMRSETICMPROFILE - { - EMR emr; - uint dwFlags; - uint cbName; - uint cbData; - uchar Data[1]; - }; -//--- -struct EMRSETMAPPERFLAGS - { - EMR emr; - uint dwFlags; - }; -//--- -struct EMRSETMITERLIMIT - { - EMR emr; - float eMiterLimit; - }; -//--- -struct PALETTEENTRY - { - uchar red; - uchar green; - uchar blue; - uchar flags; - }; -//--- -struct EMRSETPALETTEENTRIES - { - EMR emr; - uint ihPal; - uint iStart; - uint cEntries; - PALETTEENTRY aPalEntries[1]; - }; -//--- -struct EMRSETPIXELV - { - EMR emr; - POINTL ptlPixel; - uint crColor; - }; -//--- -struct EMRSETVIEWPORTEXTEX - { - EMR emr; - SIZE szlExtent; - }; -//--- -struct EMRSETVIEWPORTORGEX - { - EMR emr; - POINTL ptlOrigin; - }; -//--- -struct EMRSETWORLDTRANSFORM - { - EMR emr; - XFORM xform; - }; -//--- -struct EMRSTRETCHBLT - { - EMR emr; - RECTL rclBounds; - int xDest; - int yDest; - int cxDest; - int cyDest; - uint dwRop; - int xSrc; - int ySrc; - XFORM xformSrc; - uint crBkColorSrc; - uint iUsageSrc; - uint offBmiSrc; - uint cbBmiSrc; - uint offBitsSrc; - uint cbBitsSrc; - int cxSrc; - int cySrc; - }; -//--- -struct EMRSTRETCHDIBITS - { - EMR emr; - RECTL rclBounds; - int xDest; - int yDest; - int xSrc; - int ySrc; - int cxSrc; - int cySrc; - uint offBmiSrc; - uint cbBmiSrc; - uint offBitsSrc; - uint cbBitsSrc; - uint iUsageSrc; - uint dwRop; - int cxDest; - int cyDest; - }; -//--- -struct EMRTRANSPARENTBLT - { - EMR emr; - RECTL rclBounds; - int xDest; - int yDest; - int cxDest; - int cyDest; - uint dwRop; - int xSrc; - int ySrc; - XFORM xformSrc; - uint crBkColorSrc; - uint iUsageSrc; - uint offBmiSrc; - uint cbBmiSrc; - uint offBitsSrc; - uint cbBitsSrc; - int cxSrc; - int cySrc; - }; -//--- -struct ENHMETAHEADER - { - uint iType; - uint nSize; - RECTL rclBounds; - RECTL rclFrame; - uint dSignature; - uint nVersion; - uint nBytes; - uint nRecords; - ushort nHandles; - ushort sReserved; - uint nDescription; - uint offDescription; - uint nPalEntries; - SIZE szlDevice; - SIZE szlMillimeters; - uint cbPixelFormat; - uint offPixelFormat; - uint bOpenGL; - SIZE szlMicrometers; - }; -//--- -struct ENHMETARECORD - { - uint iType; - uint nSize; - uint dParm[1]; - }; -//--- -struct ENUMLOGFONTEXW - { - LOGFONTW elfLogFont; - short elfFullName[LF_FULLFACESIZE]; - short elfStyle[LF_FACESIZE]; - short elfScript[LF_FACESIZE]; - }; -//--- -struct ENUMLOGFONTEXDVW - { - ENUMLOGFONTEXW elfEnumLogfontEx; - DESIGNVECTOR elfDesignVector; - }; -//--- -struct ENUMLOGFONTW - { - LOGFONTW elfLogFont; - short elfFullName[LF_FULLFACESIZE]; - short elfStyle[LF_FACESIZE]; - }; -//--- -struct NEWTEXTMETRICW - { - int tmHeight; - int tmAscent; - int tmDescent; - int tmInternalLeading; - int tmExternalLeading; - int tmAveCharWidth; - int tmMaxCharWidth; - int tmWeight; - int tmOverhang; - int tmDigitizedAspectX; - int tmDigitizedAspectY; - short tmFirstChar; - short tmLastChar; - short tmDefaultChar; - short tmBreakChar; - uchar tmItalic; - uchar tmUnderlined; - uchar tmStruckOut; - uchar tmPitchAndFamily; - uchar tmCharSet; - uint ntmFlags; - uint ntmSizeEM; - uint ntmCellHeight; - uint ntmAvgWidth; - }; -//--- -struct NEWTEXTMETRICEXW - { - NEWTEXTMETRICW ntmTm; - FONTSIGNATURE ntmFontSig; - }; -//--- -struct ENUMTEXTMETRICW - { - NEWTEXTMETRICEXW etmNewTextMetricEx; - AXESLISTW etmAxesList; - }; -//--- -struct FIXED - { - ushort fract; - short value; - }; -//--- -struct POINTFLOAT - { - float x; - float y; - }; -//--- -struct GCP_RESULTSW - { - uint lStructSize; - string lpOutString; - PVOID lpOrder; - PVOID lpDx; - PVOID lpCaretPos; - PVOID lpClass; - PVOID lpGlyphs; - uint nGlyphs; - int nMaxFit; - }; -//--- -struct GLYPHMETRICS - { - uint gmBlackBoxX; - uint gmBlackBoxY; - POINT gmptGlyphOrigin; - short gmCellIncX; - short gmCellIncY; - }; -//--- -struct GLYPHMETRICSFLOAT - { - float gmfBlackBoxX; - float gmfBlackBoxY; - POINTFLOAT gmfptGlyphOrigin; - float gmfCellIncX; - float gmfCellIncY; - }; -//--- -struct WCRANGE - { - short wcLow; - ushort cGlyphs; - }; -//--- -struct GLYPHSET - { - uint cbThis; - uint flAccel; - uint cGlyphsSupported; - uint cRanges; - WCRANGE ranges[1]; - }; -//--- -struct GRADIENT_RECT - { - uint UpperLeft; - uint LowerRight; - }; -//--- -struct GRADIENT_TRIANGLE - { - uint Vertex1; - uint Vertex2; - uint Vertex3; - }; -//--- -struct HANDLETABLE - { - PVOID objectHandle[1]; - }; -//--- -struct KERNINGPAIR - { - ushort wFirst; - ushort wSecond; - int iKernAmount; - }; -//--- -struct LAYERPLANEDESCRIPTOR - { - ushort nSize; - ushort nVersion; - uint dwFlags; - uchar iPixelType; - uchar cColorBits; - uchar cRedBits; - uchar cRedShift; - uchar cGreenBits; - uchar cGreenShift; - uchar cBlueBits; - uchar cBlueShift; - uchar cAlphaBits; - uchar cAlphaShift; - uchar cAccumBits; - uchar cAccumRedBits; - uchar cAccumGreenBits; - uchar cAccumBlueBits; - uchar cAccumAlphaBits; - uchar cDepthBits; - uchar cStencilBits; - uchar cAuxBuffers; - uchar iLayerPlane; - uchar bReserved; - uint crTransparent; - }; -//--- -struct LOCALESIGNATURE - { - uint lsUsb[4]; - uint lsCsbDefault[2]; - uint lsCsbSupported[2]; - }; -//--- -struct MAT2 - { - FIXED eM11; - FIXED eM12; - FIXED eM21; - FIXED eM22; - }; -//--- -struct METAFILEPICT - { - int mm; - int xExt; - int yExt; - HANDLE hMF; - }; -//--- -struct METAHEADER - { - ushort mtType; - ushort mtHeaderSize; - ushort mtVersion; - uint mtSize; - ushort mtNoObjects; - uint mtMaxRecord; - ushort mtNoParameters; - }; -//--- -struct METARECORD - { - uint rdSize; - ushort rdFunction; - ushort rdParm[1]; - }; -//--- -struct TEXTMETRICW - { - int tmHeight; - int tmAscent; - int tmDescent; - int tmInternalLeading; - int tmExternalLeading; - int tmAveCharWidth; - int tmMaxCharWidth; - int tmWeight; - int tmOverhang; - int tmDigitizedAspectX; - int tmDigitizedAspectY; - short tmFirstChar; - short tmLastChar; - short tmDefaultChar; - short tmBreakChar; - uchar tmItalic; - uchar tmUnderlined; - uchar tmStruckOut; - uchar tmPitchAndFamily; - uchar tmCharSet; - }; -//--- -struct OUTLINETEXTMETRICW - { - uint otmSize; - TEXTMETRICW otmTextMetrics; - uchar otmFiller; - PANOSE otmPanoseNumber; - uint otmfsSelection; - uint otmfsType; - int otmsCharSlopeRise; - int otmsCharSlopeRun; - int otmItalicAngle; - uint otmEMSquare; - int otmAscent; - int otmDescent; - uint otmLineGap; - uint otmsCapEmHeight; - uint otmsXHeight; - RECT otmrcFontBox; - int otmMacAscent; - int otmMacDescent; - uint otmMacLineGap; - uint otmusMinimumPPEM; - POINT otmptSubscriptSize; - POINT otmptSubscriptOffset; - POINT otmptSuperscriptSize; - POINT otmptSuperscriptOffset; - uint otmsStrikeoutSize; - int otmsStrikeoutPosition; - int otmsUnderscoreSize; - int otmsUnderscorePosition; - PVOID otmpFamilyName; //char otmpFamilyName[]; - PVOID otmpFaceName; //char otmpFaceName[]; - PVOID otmpStyleName; //char otmpStyleName[]; - PVOID otmpFullName; //char otmpFullName[]; - }; -//--- -struct PELARRAY - { - int paXCount; - int paYCount; - int paXExt; - int paYExt; - uchar paRGBs; - }; -//--- -struct POINTFX - { - FIXED x; - FIXED y; - }; -//--- -struct POLYTEXTW - { - int x; - int y; - uint n; - const string lpstr; - uint uiFlags; - RECT rcl; - PVOID pdx; - }; -//--- -struct PSFEATURE_CUSTPAPER - { - int lOrientation; - int lWidth; - int lHeight; - int lWidthOffset; - int lHeightOffset; - }; -//--- -struct PSFEATURE_OUTPUT - { - int bPageIndependent; - int bSetPageDevice; - }; -//--- -struct PSINJECTDATA - { - uint DataBytes; - ushort InjectionPoint; - ushort PageNumber; - }; -//--- -struct RASTERIZER_STATUS - { - short nSize; - short wFlags; - short nLanguageID; - }; -//--- -struct RGNDATAHEADER - { - uint dwSize; - uint iType; - uint nCount; - uint nRgnSize; - RECT rcBound; - }; -//--- -struct RGNDATA - { - RGNDATAHEADER rdh; - char Buffer[1]; - }; -//--- -struct TTPOLYCURVE - { - ushort wType; - ushort cpfx; - POINTFX apfx[1]; - }; -//--- -struct TTPOLYGONHEADER - { - uint cb; - uint dwType; - POINTFX pfxStart; - }; -//--- -struct DEVMODEW - { - short dmDeviceName[CCHDEVICENAME]; - ushort dmSpecVersion; - ushort dmDriverVersion; - ushort dmSize; - ushort dmDriverExtra; - uint dmFields; - short dmOrientation; - short dmPaperSize; - short dmPaperLength; - short dmPaperWidth; - short dmScale; - short dmCopies; - short dmDefaultSource; - short dmPrintQuality; - short dmColor; - short dmDuplex; - short dmYResolution; - short dmTTOption; - short dmCollate; - short dmFormName[CCHFORMNAME]; - ushort dmLogPixels; - uint dmBitsPerPel; - uint dmPelsWidth; - uint dmPelsHeight; - uint dmDisplayFlags; - uint dmDisplayFrequency; - uint dmICMMethod; - uint dmICMIntent; - uint dmMediaType; - uint dmDitherType; - uint dmReserved1; - uint dmReserved2; - uint dmPanningWidth; - uint dmPanningHeight; - }; -//--- -struct WGLSWAP - { - HANDLE hdc; - uint uiFlags; - }; -//--- -union DISPLAYCONFIG_MODE - { - DISPLAYCONFIG_TARGET_MODE targetMode; - DISPLAYCONFIG_SOURCE_MODE sourceMode; - DISPLAYCONFIG_DESKTOP_IMAGE_INFO desktopImageInfo; - }; -//--- -struct DISPLAYCONFIG_MODE_INFO - { - DISPLAYCONFIG_MODE_INFO_TYPE infoType; - uint id; - LUID adapterId; - DISPLAYCONFIG_MODE mode; - }; -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -#import "gdi32.dll" -int AbortDoc(HANDLE hdc); -int AbortPath(HANDLE hdc); -HANDLE AddFontMemResourceEx(PVOID file_view,uint size,PVOID resrved,uint &num_fonts); -int AddFontResourceExW(const string name,uint fl,PVOID res); -int AddFontResourceW(string); -int AngleArc(HANDLE hdc,int x,int y,uint r,float StartAngle,float SweepAngle); -int AnimatePalette(HANDLE pal,uint start_index,uint entries,PALETTEENTRY &ppe); -int Arc(HANDLE hdc,int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4); -int ArcTo(HANDLE hdc,int left,int top,int right,int bottom,int xr1,int yr1,int xr2,int yr2); -int BeginPath(HANDLE hdc); -int BitBlt(HANDLE hdc,int x,int y,int cx,int cy,HANDLE src,int x1,int y1,uint rop); -int CancelDC(HANDLE hdc); -int CheckColorsInGamut(HANDLE hdc,RGBTRIPLE &lpRGBTriple,PVOID buffer,uint count); -int ChoosePixelFormat(HANDLE hdc,PIXELFORMATDESCRIPTOR &ppfd); -int Chord(HANDLE hdc,int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4); -HANDLE CloseEnhMetaFile(HANDLE hdc); -int CloseFigure(HANDLE hdc); -HANDLE CloseMetaFile(HANDLE hdc); -int ColorCorrectPalette(HANDLE hdc,HANDLE pal,uint first,uint num); -int ColorMatchToTarget(HANDLE hdc,HANDLE target,uint action); -int CombineRgn(HANDLE dst,HANDLE src1,HANDLE src2,int mode); -int CombineTransform(XFORM &out,XFORM &lpxf1,XFORM &lpxf2); -HANDLE CopyEnhMetaFileW(HANDLE enh,const string file_name); -HANDLE CopyMetaFileW(HANDLE,string LPCWSTR); -HANDLE CreateBitmap(int width,int height,uint planes,uint bit_count,PVOID bits); -HANDLE CreateBitmap(int width,int height,uint planes,uint bit_count,char &bits[]); -HANDLE CreateBitmapIndirect(BITMAP &pbm); -HANDLE CreateBrushIndirect(LOGBRUSH &plbrush); -HANDLE CreateColorSpaceW(LOGCOLORSPACEW &lplcs); -HANDLE CreateCompatibleBitmap(HANDLE hdc,int cx,int cy); -HANDLE CreateCompatibleDC(HANDLE hdc); -HANDLE CreateDCW(const string driver,const string device,const string port,DEVMODEW &pdm); -HANDLE CreateDIBitmap(HANDLE hdc,BITMAPINFOHEADER &pbmih,uint init,PVOID bits,BITMAPINFO &pbmi,uint usage); -HANDLE CreateDIBPatternBrush(HANDLE h,uint usage); -HANDLE CreateDIBPatternBrushPt(PVOID lpPackedDIB,uint usage); -HANDLE CreateDIBSection(HANDLE hdc,BITMAPINFO &pbmi,uint usage,PVOID bits,HANDLE section,uint offset); -HANDLE CreateDiscardableBitmap(HANDLE hdc,int cx,int cy); -HANDLE CreateEllipticRgn(int x1,int y1,int x2,int y2); -HANDLE CreateEllipticRgnIndirect(RECT &lprect); -HANDLE CreateEnhMetaFileW(HANDLE hdc,const string filename,RECT &lprc,const string desc); -HANDLE CreateFontIndirectExW(ENUMLOGFONTEXDVW &); -HANDLE CreateFontIndirectW(LOGFONTW &lplf); -HANDLE CreateFontW(int height,int width,int escapement,int orientation,int weight,uint italic,uint underline,uint strike_out,uint char_set,uint out_precision,uint clip_precision,uint quality,uint pitch_and_family,const string face_name); -HANDLE CreateHalftonePalette(HANDLE hdc); -HANDLE CreateHatchBrush(int hatch,uint clr); -HANDLE CreateICW(const string driver,const string device,const string port,DEVMODEW &pdm); -HANDLE CreateMetaFileW(const string file); -HANDLE CreatePalette(LOGPALETTE &plpal); -HANDLE CreatePatternBrush(HANDLE hbm); -HANDLE CreatePen(int style,int width,uint clr); -HANDLE CreatePenIndirect(LOGPEN &plpen); -HANDLE CreatePolygonRgn(POINT &pptl[],int point,int mode); -HANDLE CreatePolyPolygonRgn(const POINT &pptl[],const int &pc[],int poly,int mode); -HANDLE CreateRectRgn(int x1,int y1,int x2,int y2); -HANDLE CreateRectRgnIndirect(RECT &lprect); -HANDLE CreateRoundRectRgn(int x1,int y1,int x2,int y2,int w,int h); -int CreateScalableFontResourceW(uint hidden,const string font,const string file,const string path); -HANDLE CreateSolidBrush(uint clr); -int DeleteColorSpace(HANDLE hcs); -int DeleteDC(HANDLE hdc); -int DeleteEnhMetaFile(HANDLE hmf); -int DeleteMetaFile(HANDLE hmf); -int DeleteObject(PVOID ho); -int DescribePixelFormat(HANDLE hdc,int pixel_format,uint bytes,PIXELFORMATDESCRIPTOR &ppfd); -int DPtoLP(HANDLE hdc,POINT &lppt,int c); -int DrawEscape(HANDLE hdc,int escape,int in,uchar &in[]); -int Ellipse(HANDLE hdc,int left,int top,int right,int bottom); -int EndDoc(HANDLE hdc); -int EndPage(HANDLE hdc); -int EndPath(HANDLE hdc); -int EnumEnhMetaFile(HANDLE hdc,HANDLE hmf,PVOID proc,PVOID param,RECT &rect); -int EnumFontFamiliesExW(HANDLE hdc,LOGFONTW &logfont,PVOID proc,PVOID param,uint flags); -int EnumFontFamiliesW(HANDLE hdc,const string logfont,PVOID proc,PVOID param); -int EnumFontsW(HANDLE hdc,const string logfont,PVOID proc,PVOID param); -int EnumICMProfilesW(HANDLE hdc,PVOID proc,PVOID param); -int EnumMetaFile(HANDLE hdc,HANDLE hmf,PVOID proc,PVOID param); -int EnumObjects(HANDLE hdc,int type,PVOID func,PVOID param); -int EqualRgn(HANDLE hrgn1,HANDLE hrgn2); -int Escape(HANDLE hdc,int escape,int in,uchar &in[],PVOID out); -int ExcludeClipRect(HANDLE hdc,int left,int top,int right,int bottom); -HANDLE ExtCreatePen(uint pen_style,uint width,LOGBRUSH &plbrush,uint style,const uint &pstyle[]); -HANDLE ExtCreateRegion(XFORM &lpx,uint count,RGNDATA &data); -int ExtEscape(HANDLE hdc,int escape,int inp,uchar &in_data[],int output,uchar &out_data[]); -int ExtFloodFill(HANDLE hdc,int x,int y,uint clr,uint type); -int ExtSelectClipRgn(HANDLE hdc,HANDLE hrgn,int mode); -int ExtTextOutW(HANDLE hdc,int x,int y,uint options,const RECT &lprect,const string str,uint c,const int &dx[]); -int FillPath(HANDLE hdc); -int FillRgn(HANDLE hdc,HANDLE hrgn,HANDLE hbr); -int FixBrushOrgEx(HANDLE hdc,int x,int y,POINT &ptl); -int FlattenPath(HANDLE hdc); -int FloodFill(HANDLE hdc,int x,int y,uint clr); -int FrameRgn(HANDLE hdc,HANDLE hrgn,HANDLE hbr,int w,int h); -int GdiAlphaBlend(HANDLE dest,int dest,int dest,int dest,int dest,HANDLE src,int src,int src,int src,int src,BLENDFUNCTION &ftn); -int GdiComment(HANDLE hdc,uint size,const uchar &data[]); -int GdiFlush(void); -uint GdiGetBatchLimit(void); -int GdiGradientFill(HANDLE hdc,TRIVERTEX &vertex,uint vertex,PVOID mesh,uint count,uint mode); -uint GdiSetBatchLimit(uint dw); -int GdiTransparentBlt(HANDLE dest,int dest,int dest,int dest,int dest,HANDLE src,int src,int src,int src,int src,uint transparent); -int GetArcDirection(HANDLE hdc); -int GetAspectRatioFilterEx(HANDLE hdc,SIZE &lpsize); -int GetBitmapBits(HANDLE hbit,int cb,PVOID bits); -int GetBitmapDimensionEx(HANDLE hbit,SIZE &lpsize); -uint GetBkColor(HANDLE hdc); -int GetBkMode(HANDLE hdc); -uint GetBoundsRect(HANDLE hdc,RECT &lprect,uint flags); -int GetBrushOrgEx(HANDLE hdc,POINT &lppt); -int GetCharABCWidthsFloatW(HANDLE hdc,uint first,uint last,ABCFLOAT &lpABC[]); -int GetCharABCWidthsI(HANDLE hdc,uint first,uint cgi,ushort &pgi[],ABC &pabc[]); -int GetCharABCWidthsW(HANDLE hdc,uint first,uint last,ABC &lpABC[]); -uint GetCharacterPlacementW(HANDLE hdc,const string str,int count,int mex_extent,GCP_RESULTSW &results,uint flags); -int GetCharWidthFloatW(HANDLE hdc,uint first,uint last,float &buffer[]); -int GetCharWidthI(HANDLE hdc,uint first,uint cgi,ushort &pgi[],int &widths[]); -int GetCharWidthW(HANDLE hdc,uint first,uint last,int &buffer[]); -int GetClipBox(HANDLE hdc,RECT &lprect); -int GetClipRgn(HANDLE hdc,HANDLE hrgn); -int GetColorAdjustment(HANDLE hdc,COLORADJUSTMENT &lpca); -HANDLE GetColorSpace(HANDLE hdc); -PVOID GetCurrentObject(HANDLE hdc,uint type); -int GetCurrentPositionEx(HANDLE hdc,POINT &lppt); -uint GetDCBrushColor(HANDLE hdc); -int GetDCOrgEx(HANDLE hdc,POINT &lppt); -uint GetDCPenColor(HANDLE hdc); -int GetDeviceCaps(HANDLE hdc,int index); -int GetDeviceGammaRamp(HANDLE hdc,PVOID ramp); -int GetDeviceGammaRamp(HANDLE hdc,ushort &ramp[]); -uint GetDIBColorTable(HANDLE hdc,uint start,uint entries,RGBQUAD &prgbq[]); -int GetDIBits(HANDLE hdc,HANDLE hbm,uint start,uint lines,PVOID bits,BITMAPINFO &lpbmi,uint usage); -uint GetEnhMetaFileBits(HANDLE hEMF,uint size,uchar &data[]); -uint GetEnhMetaFileDescriptionW(HANDLE hemf,uint buffer,string description); -uint GetEnhMetaFileHeader(HANDLE hemf,uint size,ENHMETAHEADER &enh_meta_header); -uint GetEnhMetaFilePaletteEntries(HANDLE hemf,uint num_entries,PALETTEENTRY &palette_entries); -uint GetEnhMetaFilePixelFormat(HANDLE hemf,uint buffer,PIXELFORMATDESCRIPTOR &ppfd); -HANDLE GetEnhMetaFileW(const string name); -uint GetFontData(HANDLE hdc,uint table,uint offset,PVOID buffer,uint buffer); -uint GetFontLanguageInfo(HANDLE hdc); -uint GetFontUnicodeRanges(HANDLE hdc,PVOID lpgs); -uint GetFontUnicodeRanges(HANDLE hdc,GLYPHSET &lpgs); -uint GetGlyphIndicesW(HANDLE hdc,const string lpstr,int c,ushort &pgi[],uint fl); -uint GetGlyphOutlineW(HANDLE hdc,uint symbol,uint format,GLYPHMETRICS &lpgm,uint buffer,PVOID buffer,MAT2 &lpmat2); -int GetGraphicsMode(HANDLE hdc); -int GetICMProfileW(HANDLE hdc,uint &buf_size,ushort &filename[]); -uint GetKerningPairsW(HANDLE hdc,uint pairs,KERNINGPAIR &kern_pair); -uint GetLayout(HANDLE hdc); -int GetLogColorSpaceW(HANDLE color_space,LOGCOLORSPACEW &buffer,uint size); -int GetMapMode(HANDLE hdc); -uint GetMetaFileBitsEx(HANDLE hMF,uint buffer,PVOID data); -HANDLE GetMetaFileW(const string name); -int GetMetaRgn(HANDLE hdc,HANDLE hrgn); -int GetMiterLimit(HANDLE hdc,float &plimit); -uint GetNearestColor(HANDLE hdc,uint clr); -uint GetNearestPaletteIndex(HANDLE h,uint clr); -uint GetObjectType(PVOID h); -int GetObjectW(HANDLE h,int c,PVOID pv); -uint GetOutlineTextMetricsW(HANDLE hdc,uint copy,OUTLINETEXTMETRICW &potm); -uint GetPaletteEntries(HANDLE hpal,uint start,uint entries,PALETTEENTRY &pal_entries); -int GetPath(HANDLE hdc,POINT &apt,uchar &aj,int cpt); -uint GetPixel(HANDLE hdc,int x,int y); -int GetPixelFormat(HANDLE hdc); -int GetPolyFillMode(HANDLE hdc); -int GetRandomRgn(HANDLE hdc,HANDLE hrgn,int i); -int GetRasterizerCaps(RASTERIZER_STATUS &lpraststat,uint bytes); -uint GetRegionData(HANDLE hrgn,uint count,RGNDATA &rgn_data); -uint GetRegionData(HANDLE hrgn,uint count,PVOID rgn_data); -int GetRgnBox(HANDLE hrgn,RECT &lprc); -int GetROP2(HANDLE hdc); -PVOID GetStockObject(int i); -int GetStretchBltMode(HANDLE hdc); -uint GetSystemPaletteEntries(HANDLE hdc,uint start,uint entries,PALETTEENTRY &pal_entries); -uint GetSystemPaletteUse(HANDLE hdc); -uint GetTextAlign(HANDLE hdc); -int GetTextCharacterExtra(HANDLE hdc); -int GetTextCharset(HANDLE hdc); -int GetTextCharsetInfo(HANDLE hdc,FONTSIGNATURE &sig,uint flags); -uint GetTextColor(HANDLE hdc); -int GetTextExtentExPointI(HANDLE hdc,ushort &str[],int str_size,int max_extent,int &fit,int &dx[],SIZE &size); -int GetTextExtentExPointW(HANDLE hdc,const string str,int str,int max_extent,int &fit,int &dx[],SIZE &size); -int GetTextExtentPoint32W(HANDLE hdc,const string str,int c,SIZE &psizl); -int GetTextExtentPointI(HANDLE hdc,ushort &in[],int cgi,SIZE &psize); -int GetTextExtentPointW(HANDLE hdc,const string str,int c,SIZE &lpsz); -int GetTextFaceW(HANDLE hdc,int c,ushort &name[]); -int GetTextMetricsW(HANDLE hdc,TEXTMETRICW &lptm); -int GetViewportExtEx(HANDLE hdc,SIZE &lpsize); -int GetViewportOrgEx(HANDLE hdc,POINT &lppoint); -int GetWindowExtEx(HANDLE hdc,SIZE &lpsize); -int GetWindowOrgEx(HANDLE hdc,POINT &lppoint); -uint GetWinMetaFileBits(HANDLE hemf,uint data16,uchar &data16,int map_mode,HANDLE ref); -int GetWorldTransform(HANDLE hdc,XFORM &lpxf); -int IntersectClipRect(HANDLE hdc,int left,int top,int right,int bottom); -int InvertRgn(HANDLE hdc,HANDLE hrgn); -int LineTo(HANDLE hdc,int x,int y); -int LPtoDP(HANDLE hdc,POINT &lppt[],int c); -int MaskBlt(HANDLE dest,int dest,int dest,int width,int height,HANDLE src,int src,int src,HANDLE mask,int mask,int mask,uint rop); -int ModifyWorldTransform(HANDLE hdc,XFORM &lpxf,uint mode); -int MoveToEx(HANDLE hdc,int x,int y,POINT &lppt); -int OffsetClipRgn(HANDLE hdc,int x,int y); -int OffsetRgn(HANDLE hrgn,int x,int y); -int OffsetViewportOrgEx(HANDLE hdc,int x,int y,POINT &lppt); -int OffsetWindowOrgEx(HANDLE hdc,int x,int y,POINT &lppt); -int PaintRgn(HANDLE hdc,HANDLE hrgn); -int PatBlt(HANDLE hdc,int x,int y,int w,int h,uint rop); -HANDLE PathToRegion(HANDLE hdc); -int Pie(HANDLE hdc,int left,int top,int right,int bottom,int xr1,int yr1,int xr2,int yr2); -int PlayEnhMetaFile(HANDLE hdc,HANDLE hmf,RECT &lprect); -int PlayEnhMetaFileRecord(HANDLE hdc,HANDLETABLE &pht,ENHMETARECORD &pmr,uint cht); -int PlayMetaFile(HANDLE hdc,HANDLE hmf); -int PlayMetaFileRecord(HANDLE hdc,HANDLETABLE &handle_table,METARECORD &lpMR,uint objs); -int PlgBlt(HANDLE dest,POINT &point,HANDLE src,int src,int src,int width,int height,HANDLE mask,int mask,int mask); -int PolyBezier(HANDLE hdc,POINT &apt,uint cpt); -int PolyBezierTo(HANDLE hdc,POINT &apt,uint cpt); -int PolyDraw(HANDLE hdc,const POINT &apt,const uchar &aj[],int cpt); -int Polygon(HANDLE hdc,const POINT &apt,int cpt); -int Polyline(HANDLE hdc,const POINT &apt,int cpt); -int PolylineTo(HANDLE hdc,const POINT &apt,uint cpt); -int PolyPolygon(HANDLE hdc,const POINT &apt,int &asz[],int csz); -int PolyPolyline(HANDLE hdc,const POINT &apt,uint &asz[],uint csz); -int PolyTextOutW(HANDLE hdc,POLYTEXTW &ppt,int nstrings); -int PtInRegion(HANDLE hrgn,int x,int y); -int PtVisible(HANDLE hdc,int x,int y); -uint RealizePalette(HANDLE hdc); -int Rectangle(HANDLE hdc,int left,int top,int right,int bottom); -int RectInRegion(HANDLE hrgn,RECT &lprect); -int RectVisible(HANDLE hdc,RECT &lprect); -int RemoveFontMemResourceEx(HANDLE h); -int RemoveFontResourceExW(const string name,uint fl,PVOID pdv); -int RemoveFontResourceW(const string file_name); -HANDLE ResetDCW(HANDLE hdc,DEVMODEW &lpdm); -int ResizePalette(HANDLE hpal,uint n); -int RestoreDC(HANDLE hdc,int nSavedDC); -int RoundRect(HANDLE hdc,int left,int top,int right,int bottom,int width,int height); -int SaveDC(HANDLE hdc); -int ScaleViewportExtEx(HANDLE hdc,int xn,int dx,int yn,int yd,SIZE &lpsz); -int ScaleWindowExtEx(HANDLE hdc,int xn,int xd,int yn,int yd,SIZE &lpsz); -int SelectClipPath(HANDLE hdc,int mode); -int SelectClipRgn(HANDLE hdc,HANDLE hrgn); -PVOID SelectObject(HANDLE hdc,PVOID h); -HANDLE SelectPalette(HANDLE hdc,HANDLE pal,int force_bkgd); -int SetAbortProc(HANDLE hdc,PVOID proc); -int SetArcDirection(HANDLE hdc,int dir); -int SetBitmapBits(HANDLE hbm,uint cb,const uchar &bits[]); -int SetBitmapDimensionEx(HANDLE hbm,int w,int h,SIZE &lpsz); -uint SetBkColor(HANDLE hdc,uint clr); -int SetBkMode(HANDLE hdc,int mode); -uint SetBoundsRect(HANDLE hdc,RECT &lprect,uint flags); -int SetBrushOrgEx(HANDLE hdc,int x,int y,POINT &lppt); -int SetColorAdjustment(HANDLE hdc,COLORADJUSTMENT &lpca); -HANDLE SetColorSpace(HANDLE hdc,HANDLE hcs); -uint SetDCBrushColor(HANDLE hdc,uint clr); -uint SetDCPenColor(HANDLE hdc,uint clr); -int SetDeviceGammaRamp(HANDLE hdc,PVOID ramp); -uint SetDIBColorTable(HANDLE hdc,uint start,uint entries,RGBQUAD &prgbq); -int SetDIBits(HANDLE hdc,HANDLE hbm,uint start,uint lines,PVOID bits,BITMAPINFO &lpbmi,uint ColorUse); -int SetDIBitsToDevice(HANDLE hdc,int dest,int dest,uint w,uint h,int src,int src,uint StartScan,uint lines,PVOID bits,BITMAPINFO &lpbmi,uint ColorUse); -HANDLE SetEnhMetaFileBits(uint size,const uchar &pb[]); -int SetGraphicsMode(HANDLE hdc,int mode); -int SetICMMode(HANDLE hdc,int mode); -int SetICMProfileW(HANDLE hdc,string file_name); -uint SetLayout(HANDLE hdc,uint l); -int SetMapMode(HANDLE hdc,int mode); -uint SetMapperFlags(HANDLE hdc,uint flags); -HANDLE SetMetaFileBitsEx(uint buffer,const uchar &data[]); -int SetMetaRgn(HANDLE hdc); -int SetMiterLimit(HANDLE hdc,float limit,float &old); -uint SetPaletteEntries(HANDLE hpal,uint start,uint entries,PALETTEENTRY &pal_entries); -uint SetPixel(HANDLE hdc,int x,int y,uint clr); -int SetPixelFormat(HANDLE hdc,int format,PIXELFORMATDESCRIPTOR &ppfd); -int SetPixelV(HANDLE hdc,int x,int y,uint clr); -int SetPolyFillMode(HANDLE hdc,int mode); -int SetRectRgn(HANDLE hrgn,int left,int top,int right,int bottom); -int SetROP2(HANDLE hdc,int rop2); -int SetStretchBltMode(HANDLE hdc,int mode); -uint SetSystemPaletteUse(HANDLE hdc,uint use); -uint SetTextAlign(HANDLE hdc,uint align); -int SetTextCharacterExtra(HANDLE hdc,int extra); -uint SetTextColor(HANDLE hdc,uint clr); -int SetTextJustification(HANDLE hdc,int extra,int count); -int SetViewportExtEx(HANDLE hdc,int x,int y,SIZE &lpsz); -int SetViewportOrgEx(HANDLE hdc,int x,int y,POINT &lppt); -int SetWindowExtEx(HANDLE hdc,int x,int y,SIZE &lpsz); -int SetWindowOrgEx(HANDLE hdc,int x,int y,POINT &lppt); -HANDLE SetWinMetaFileBits(uint size,const uchar &lpMeta16Data[],HANDLE ref,const METAFILEPICT &lpMFP); -int SetWorldTransform(HANDLE hdc,XFORM &lpxf); -int StartDocW(HANDLE hdc,DOCINFOW &lpdi); -int StartPage(HANDLE hdc); -int StretchBlt(HANDLE dest,int dest,int dest,int dest,int dest,HANDLE src,int src,int src,int src,int src,uint rop); -int StretchDIBits(HANDLE hdc,int dest,int dest,int DestWidth,int DestHeight,int src,int src,int SrcWidth,int SrcHeight,PVOID bits,BITMAPINFO &lpbmi,uint usage,uint rop); -int StrokeAndFillPath(HANDLE hdc); -int StrokePath(HANDLE hdc); -int SwapBuffers(HANDLE); -int TextOutW(HANDLE hdc,int x,int y,const string str,int c); -int TranslateCharsetInfo(PVOID src,CHARSETINFO &cs,uint flags); -int UnrealizeObject(PVOID h); -int UpdateColors(HANDLE hdc); -int UpdateICMRegKeyW(uint reserved,string lpszCMID,string file_name,uint command); -int WidenPath(HANDLE hdc); -#import - -#import "Opengl32.dll" -int wglCopyContext(HANDLE,HANDLE,uint); -HANDLE wglCreateContext(HANDLE); -HANDLE wglCreateLayerContext(HANDLE,int); -int wglDeleteContext(HANDLE); -int wglDescribeLayerPlane(HANDLE,int,int,uint,LAYERPLANEDESCRIPTOR &); -HANDLE wglGetCurrentContext(void); -HANDLE wglGetCurrentDC(void); -int wglGetLayerPaletteEntries(HANDLE,int,int,int,const uint &[]); -PVOID wglGetProcAddress(string); -int wglMakeCurrent(HANDLE,HANDLE); -int wglRealizeLayerPalette(HANDLE,int,int); -int wglSetLayerPaletteEntries(HANDLE,int,int,int,const uint &[]); -int wglShareLists(HANDLE,HANDLE); -int wglSwapLayerBuffers(HANDLE,uint); -uint wglSwapMultipleBuffers(uint,WGLSWAP &); -int wglUseFontBitmapsW(HANDLE,uint,uint,uint); -int wglUseFontOutlinesW(HANDLE,uint,uint,uint,float,float,int,GLYPHMETRICSFLOAT &); -#import -//+------------------------------------------------------------------+ \ No newline at end of file diff --git a/Include/WinAPI/winnt.mqh b/Include/WinAPI/winnt.mqh deleted file mode 100644 index a282c00..0000000 --- a/Include/WinAPI/winnt.mqh +++ /dev/null @@ -1,3642 +0,0 @@ -//+------------------------------------------------------------------+ -//| winnt.mqh | -//| Copyright 2018, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include - -//--- -#define UNWIND_HISTORY_TABLE_SIZE 12 -#define SIZE_OF_80387_REGISTERS 80 -#define MAXIMUM_SUPPORTED_EXTENSION 512 -#define WOW64_SIZE_OF_80387_REGISTERS 80 -#define WOW64_MAXIMUM_SUPPORTED_EXTENSION 512 -#define SID_HASH_SIZE 32 -#define POLICY_AUDIT_SUBCATEGORY_COUNT 59 -#define TOKEN_SOURCE_LENGTH 8 -#define MAXIMUM_XSTATE_FEATURES 64 -#define POWER_SYSTEM_MAXIMUM 7 -#define NUM_DISCHARGE_POLICIES 4 -#define HIBERFILE_TYPE_MAX 0x03 -#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 -#define IMAGE_SIZEOF_SHORT_NAME 8 -#define IMAGE_ENCLAVE_LONG_ID_LENGTH 32 -#define IMAGE_ENCLAVE_SHORT_ID_LENGTH 16 -#define RTL_CORRELATION_VECTOR_STRING_LENGTH 129 - -//--- -enum SID_NAME_USE - { - SidTypeUser=1, - SidTypeGroup, - SidTypeDomain, - SidTypeAlias, - SidTypeWellKnownGroup, - SidTypeDeletedAccount, - SidTypeInvalid, - SidTypeUnknown, - SidTypeComputer, - SidTypeLabel, - SidTypeLogonSession - }; -//--- -enum ACL_INFORMATION_CLASS - { - AclRevisionInformation=1, - AclSizeInformation - }; -//--- -enum AUDIT_EVENT_TYPE - { - AuditEventObjectAccess, - AuditEventDirectoryServiceAccess - }; -//--- -enum ACCESS_REASON_TYPE - { - AccessReasonNone=0x00000000, - AccessReasonAllowedAce=0x00010000, - AccessReasonDeniedAce=0x00020000, - AccessReasonAllowedParentAce=0x00030000, - AccessReasonDeniedParentAce=0x00040000, - AccessReasonNotGrantedByCape=0x00050000, - AccessReasonNotGrantedByParentCape=0x00060000, - AccessReasonNotGrantedToAppContainer=0x00070000, - AccessReasonMissingPrivilege=0x00100000, - AccessReasonFromPrivilege=0x00200000, - AccessReasonIntegrityLevel=0x00300000, - AccessReasonOwnership=0x00400000, - AccessReasonNullDacl=0x00500000, - AccessReasonEmptyDacl=0x00600000, - AccessReasonNoSD=0x00700000, - AccessReasonNoGrant=0x00800000, - AccessReasonTrustLabel=0x00900000, - AccessReasonFilterAce=0x00a00000 - }; -//--- -enum SECURITY_IMPERSONATION_LEVEL - { - SecurityAnonymous, - SecurityIdentification, - SecurityImpersonation, - SecurityDelegation - }; -//--- -enum TOKEN_TYPE - { - TokenPrimary=1, - TokenImpersonation - }; -//--- -enum TOKEN_ELEVATION_TYPE - { - TokenElevationTypeDefault=1, - TokenElevationTypeFull, - TokenElevationTypeLimited - }; -//--- -enum TOKEN_INFORMATION_CLASS - { - TokenUser=1, - TokenGroups, - TokenPrivileges, - TokenOwner, - TokenPrimaryGroup, - TokenDefaultDacl, - TokenSource, - TokenType, - TokenImpersonationLevel, - TokenStatistics, - TokenRestrictedSids, - TokenSessionId, - TokenGroupsAndPrivileges, - TokenSessionReference, - TokenSandBoxInert, - TokenAuditPolicy, - TokenOrigin, - TokenElevationType, - TokenLinkedToken, - TokenElevation, - TokenHasRestrictions, - TokenAccessInformation, - TokenVirtualizationAllowed, - TokenVirtualizationEnabled, - TokenIntegrityLevel, - TokenUIAccess, - TokenMandatoryPolicy, - TokenLogonSid, - TokenIsAppContainer, - TokenCapabilities, - TokenAppContainerSid, - TokenAppContainerNumber, - TokenUserClaimAttributes, - TokenDeviceClaimAttributes, - TokenRestrictedUserClaimAttributes, - TokenRestrictedDeviceClaimAttributes, - TokenDeviceGroups, - TokenRestrictedDeviceGroups, - TokenSecurityAttributes, - TokenIsRestricted, - TokenProcessTrustLevel, - TokenPrivateNameSpace, - TokenSingletonAttributes, - TokenBnoIsolation, - TokenChildProcessFlags, - MaxTokenInfoClass - }; -//--- -enum MANDATORY_LEVEL - { - MandatoryLevelUntrusted=0, - MandatoryLevelLow, - MandatoryLevelMedium, - MandatoryLevelHigh, - MandatoryLevelSystem, - MandatoryLevelSecureProcess, - MandatoryLevelCount - }; -//--- -enum SE_IMAGE_SIGNATURE_TYPE - { - SeImageSignatureNone=0, - SeImageSignatureEmbedded, - SeImageSignatureCache, - SeImageSignatureCatalogCached, - SeImageSignatureCatalogNotCached, - SeImageSignatureCatalogHint, - SeImageSignaturePackageCatalog - }; -//--- -enum SE_LEARNING_MODE_DATA_TYPE - { - SeLearningModeInvalidType=0, - SeLearningModeSettings, - SeLearningModeMax - }; -//--- -enum HARDWARE_COUNTER_TYPE - { - PMCCounter, - MaxHardwareCounterType - }; -//--- -enum PROCESS_MITIGATION_POLICY - { - ProcessDEPPolicy, - ProcessASLRPolicy, - ProcessDynamicCodePolicy, - ProcessStrictHandleCheckPolicy, - ProcessSystemCallDisablePolicy, - ProcessMitigationOptionsMask, - ProcessExtensionPointDisablePolicy, - ProcessControlFlowGuardPolicy, - ProcessSignaturePolicy, - ProcessFontDisablePolicy, - ProcessImageLoadPolicy, - ProcessSystemCallFilterPolicy, - ProcessPayloadRestrictionPolicy, - ProcessChildProcessPolicy, - MaxProcessMitigationPolicy - }; -//--- -enum JOBOBJECT_RATE_CONTROL_TOLERANCE - { - ToleranceLow=1, - ToleranceMedium, - ToleranceHigh - }; -//--- -enum JOBOBJECT_RATE_CONTROL_TOLERANCE_INTERVAL - { - ToleranceIntervalShort=1, - ToleranceIntervalMedium, - ToleranceIntervalLong - }; -//--- -enum JOB_OBJECT_NET_RATE_CONTROL_FLAGS - { - JOB_OBJECT_NET_RATE_CONTROL_ENABLE=0x1, - JOB_OBJECT_NET_RATE_CONTROL_MAX_BANDWIDTH=0x2, - JOB_OBJECT_NET_RATE_CONTROL_DSCP_TAG=0x4, - JOB_OBJECT_NET_RATE_CONTROL_VALID_FLAGS=0x7 - }; -//--- -enum JOB_OBJECT_IO_RATE_CONTROL_FLAGS - { - JOB_OBJECT_IO_RATE_CONTROL_ENABLE=0x1, - JOB_OBJECT_IO_RATE_CONTROL_STANDALONE_VOLUME=0x2, - JOB_OBJECT_IO_RATE_CONTROL_FORCE_UNIT_ACCESS_ALL=0x4, - JOB_OBJECT_IO_RATE_CONTROL_FORCE_UNIT_ACCESS_ON_SOFT_CAP=0x8, - JOB_OBJECT_IO_RATE_CONTROL_VALID_FLAGS=JOB_OBJECT_IO_RATE_CONTROL_ENABLE| - JOB_OBJECT_IO_RATE_CONTROL_STANDALONE_VOLUME| - JOB_OBJECT_IO_RATE_CONTROL_FORCE_UNIT_ACCESS_ALL| - JOB_OBJECT_IO_RATE_CONTROL_FORCE_UNIT_ACCESS_ON_SOFT_CAP - }; -//--- -enum JOBOBJECT_IO_ATTRIBUTION_CONTROL_FLAGS - { - JOBOBJECT_IO_ATTRIBUTION_CONTROL_ENABLE=0x1, - JOBOBJECT_IO_ATTRIBUTION_CONTROL_DISABLE=0x2, - JOBOBJECT_IO_ATTRIBUTION_CONTROL_VALID_FLAGS=0x3 - }; -//--- -enum JOBOBJECTINFOCLASS - { - JobObjectBasicAccountingInformation=1, - JobObjectBasicLimitInformation, - JobObjectBasicProcessIdList, - JobObjectBasicUIRestrictions, - JobObjectSecurityLimitInformation, - JobObjectEndOfJobTimeInformation, - JobObjectAssociateCompletionPortInformation, - JobObjectBasicAndIoAccountingInformation, - JobObjectExtendedLimitInformation, - JobObjectJobSetInformation, - JobObjectGroupInformation, - JobObjectNotificationLimitInformation, - JobObjectLimitViolationInformation, - JobObjectGroupInformationEx, - JobObjectCpuRateControlInformation, - JobObjectCompletionFilter, - JobObjectCompletionCounter, - JobObjectReserved1Information=18, - JobObjectReserved2Information, - JobObjectReserved3Information, - JobObjectReserved4Information, - JobObjectReserved5Information, - JobObjectReserved6Information, - JobObjectReserved7Information, - JobObjectReserved8Information, - JobObjectReserved9Information, - JobObjectReserved10Information, - JobObjectReserved11Information, - JobObjectReserved12Information, - JobObjectReserved13Information, - JobObjectReserved14Information=31, - JobObjectNetRateControlInformation, - JobObjectNotificationLimitInformation2, - JobObjectLimitViolationInformation2, - JobObjectCreateSilo, - JobObjectSiloBasicInformation, - JobObjectReserved15Information=37, - JobObjectReserved16Information=38, - JobObjectReserved17Information=39, - JobObjectReserved18Information=40, - JobObjectReserved19Information=41, - JobObjectReserved20Information=42, - JobObjectReserved21Information=43, - JobObjectReserved22Information=44, - JobObjectReserved23Information=45, - JobObjectReserved24Information=46, - JobObjectReserved25Information=47, - MaxJobObjectInfoClass - }; -//--- -enum SERVERSILO_STATE - { - SERVERSILO_INITING=0, - SERVERSILO_STARTED, - SERVERSILO_SHUTTING_DOWN, - SERVERSILO_TERMINATING, - SERVERSILO_TERMINATED - }; -//--- -enum FIRMWARE_TYPE - { - FirmwareTypeUnknown, - FirmwareTypeBios, - FirmwareTypeUefi, - FirmwareTypeMax - }; -//--- -enum LOGICAL_PROCESSOR_RELATIONSHIP - { - RelationProcessorCore, - RelationNumaNode, - RelationCache, - RelationProcessorPackage, - RelationGroup, - RelationAll=0xffff - }; -//--- -enum PROCESSOR_CACHE_TYPE - { - CacheUnified, - CacheInstruction, - CacheData, - CacheTrace - }; -//--- -enum CPU_SET_INFORMATION_TYPE - { - CpuSetInformation - }; -//--- -enum MEM_EXTENDED_PARAMETER_TYPE - { - MemExtendedParameterInvalidType=0, - MemExtendedParameterAddressRequirements, - MemExtendedParameterNumaNode, - MemExtendedParameterPartitionHandle, - MemExtendedParameterMax - }; -//--- -enum SharedVirtualDiskSupportType - { - SharedVirtualDisksUnsupported=0, - SharedVirtualDisksSupported=1, - SharedVirtualDiskSnapshotsSupported=3, - SharedVirtualDiskCDPSnapshotsSupported=7 - }; -//--- -enum SharedVirtualDiskHandleState - { - SharedVirtualDiskHandleStateNone=0, - SharedVirtualDiskHandleStateFileShared=1, - SharedVirtualDiskHandleStateHandleShared=3 - }; -//--- -enum SYSTEM_POWER_STATE - { - PowerSystemUnspecified=0, - PowerSystemWorking=1, - PowerSystemSleeping1=2, - PowerSystemSleeping2=3, - PowerSystemSleeping3=4, - PowerSystemHibernate=5, - PowerSystemShutdown=6, - PowerSystemMaximum=7 - }; -//--- -enum DEVICE_POWER_STATE - { - PowerDeviceUnspecified=0, - PowerDeviceD0, - PowerDeviceD1, - PowerDeviceD2, - PowerDeviceD3, - PowerDeviceMaximum - }; -//--- -enum MONITOR_DISPLAY_STATE - { - PowerMonitorOff=0, - PowerMonitorOn, - PowerMonitorDim - }; -//--- -enum USER_ACTIVITY_PRESENCE - { - PowerUserPresent=0, - PowerUserNotPresent, - PowerUserInactive, - PowerUserMaximum, - PowerUserInvalid=PowerUserMaximum - }; -//--- -enum POWER_REQUEST_TYPE - { - PowerRequestDisplayRequired, - PowerRequestSystemRequired, - PowerRequestAwayModeRequired, - PowerRequestExecutionRequired - }; -//--- -enum POWER_MONITOR_REQUEST_TYPE - { - MonitorRequestTypeOff, - MonitorRequestTypeOnAndPresent, - MonitorRequestTypeToggleOn - }; -//--- -enum POWER_PLATFORM_ROLE - { - PlatformRoleUnspecified=0, - PlatformRoleDesktop, - PlatformRoleMobile, - PlatformRoleWorkstation, - PlatformRoleEnterpriseServer, - PlatformRoleSOHOServer, - PlatformRoleAppliancePC, - PlatformRolePerformanceServer, - PlatformRoleSlate, - PlatformRoleMaximum - }; -//--- -enum HIBERFILE_BUCKET_SIZE - { - HiberFileBucket1GB=0, - HiberFileBucket2GB, - HiberFileBucket4GB, - HiberFileBucket8GB, - HiberFileBucket16GB, - HiberFileBucket32GB, - HiberFileBucketUnlimited, - HiberFileBucketMax - }; -//--- -enum IMAGE_AUX_SYMBOL_TYPE - { - IMAGE_AUX_SYMBOL_TYPE_TOKEN_DEF=1 - }; -//--- -enum IMPORT_OBJECT_TYPE - { - IMPORT_OBJECT_CODE=0, - IMPORT_OBJECT_DATA=1, - IMPORT_OBJECT_CONST=2 - }; -//--- -enum IMPORT_OBJECT_NAME_TYPE - { - IMPORT_OBJECT_ORDINAL=0, - IMPORT_OBJECT_NAME=1, - IMPORT_OBJECT_NAME_NO_PREFIX=2, - IMPORT_OBJECT_NAME_UNDECORATE=3, - IMPORT_OBJECT_NAME_EXPORTAS=4 - }; -//--- -enum ReplacesCorHdrNumericDefines - { - COMIMAGE_FLAGS_ILONLY=0x00000001, - COMIMAGE_FLAGS_32BITREQUIRED=0x00000002, - COMIMAGE_FLAGS_IL_LIBRARY=0x00000004, - COMIMAGE_FLAGS_STRONGNAMESIGNED=0x00000008, - COMIMAGE_FLAGS_NATIVE_ENTRYPOINT=0x00000010, - COMIMAGE_FLAGS_TRACKDEBUGDATA=0x00010000, - COMIMAGE_FLAGS_32BITPREFERRED=0x00020000, - COR_VERSION_MAJOR_V2=2, - COR_VERSION_MAJOR=COR_VERSION_MAJOR_V2, - COR_VERSION_MINOR=5, - COR_DELETED_NAME_LENGTH=8, - COR_VTABLEGAP_NAME_LENGTH=8, - NATIVE_TYPE_MAX_CB=1, - COR_ILMETHOD_SECT_SMALL_MAX_DATASIZE=0xFF, - IMAGE_COR_MIH_METHODRVA=0x01, - IMAGE_COR_MIH_EHRVA=0x02, - IMAGE_COR_MIH_BASICBLOCK=0x08, - COR_VTABLE_32BIT=0x01, - COR_VTABLE_64BIT=0x02, - COR_VTABLE_FROM_UNMANAGED=0x04, - COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN=0x08, - COR_VTABLE_CALL_MOST_DERIVED=0x10, - IMAGE_COR_EATJ_THUNK_SIZE=32, - MAX_CLASS_NAME=1024, - MAX_PACKAGE_NAME=1024 - }; -//--- -enum RTL_UMS_THREAD_INFO_CLASS - { - UmsThreadInvalidInfoClass=0, - UmsThreadUserContext, - UmsThreadPriority, - UmsThreadAffinity, - UmsThreadTeb, - UmsThreadIsSuspended, - UmsThreadIsTerminated, - UmsThreadMaxInfoClass - }; -//--- -enum RTL_UMS_SCHEDULER_REASON - { - UmsSchedulerStartup=0, - UmsSchedulerThreadBlocked, - UmsSchedulerThreadYield - }; -//--- -enum OS_DEPLOYEMENT_STATE_VALUES - { - OS_DEPLOYMENT_STANDARD=1, - OS_DEPLOYMENT_COMPACT - }; -//--- -enum IMAGE_POLICY_ENTRY_TYPE - { - ImagePolicyEntryTypeNone=0, - ImagePolicyEntryTypeBool, - ImagePolicyEntryTypeInt8, - ImagePolicyEntryTypeUInt8, - ImagePolicyEntryTypeInt16, - ImagePolicyEntryTypeUInt16, - ImagePolicyEntryTypeInt32, - ImagePolicyEntryTypeUInt32, - ImagePolicyEntryTypeInt64, - ImagePolicyEntryTypeUInt64, - ImagePolicyEntryTypeAnsiString, - ImagePolicyEntryTypeUnicodeString, - ImagePolicyEntryTypeOverride, - ImagePolicyEntryTypeMaximum - }; -//--- -enum IMAGE_POLICY_ID - { - ImagePolicyIdNone=0, - ImagePolicyIdEtw, - ImagePolicyIdDebug, - ImagePolicyIdCrashDump, - ImagePolicyIdCrashDumpKey, - ImagePolicyIdCrashDumpKeyGuid, - ImagePolicyIdParentSd, - ImagePolicyIdParentSdRev, - ImagePolicyIdSvn, - ImagePolicyIdDeviceId, - ImagePolicyIdCapability, - ImagePolicyIdScenarioId, - ImagePolicyIdMaximum - }; -//--- -enum HEAP_INFORMATION_CLASS - { - HeapCompatibilityInformation=0, - HeapEnableTerminationOnCorruption=1, - HeapOptimizeResources=3 - }; -//--- -enum ACTIVATION_CONTEXT_INFO_CLASS - { - ActivationContextBasicInformation=1, - ActivationContextDetailedInformation=2, - AssemblyDetailedInformationInActivationContext=3, - FileInformationInAssemblyOfAssemblyInActivationContext=4, - RunlevelInformationInActivationContext=5, - CompatibilityInformationInActivationContext=6, - ActivationContextManifestResourceName=7, - MaxActivationContextInfoClass, - AssemblyDetailedInformationInActivationContxt=3, - FileInformationInAssemblyOfAssemblyInActivationContxt=4 - }; -//--- -enum SERVICE_NODE_TYPE - { - DriverType=0x00000001, - FileSystemType=0x00000002, - Win32ServiceOwnProcess=0x00000010, - Win32ServiceShareProcess=0x00000020, - AdapterType=0x00000004, - RecognizerType=0x00000008 - }; -//--- -enum SERVICE_LOAD_TYPE - { - BootLoad=0x00000000, - SystemLoad=0x00000001, - AutoLoad=0x00000002, - DemandLoad=0x00000003, - DisableLoad=0x00000004 - }; -//--- -enum SERVICE_ERROR_TYPE - { - IgnoreError=0x00000000, - NormalError=0x00000001, - SevereError=0x00000002, - CriticalError=0x00000003 - }; -//--- -enum TAPE_DRIVE_PROBLEM_TYPE - { - TapeDriveProblemNone, - TapeDriveReadWriteWarning, - TapeDriveReadWriteError, - TapeDriveReadWarning, - TapeDriveWriteWarning, - TapeDriveReadError, - TapeDriveWriteError, - TapeDriveHardwareError, - TapeDriveUnsupportedMedia, - TapeDriveScsiConnectionError, - TapeDriveTimetoClean, - TapeDriveCleanDriveNow, - TapeDriveMediaLifeExpired, - TapeDriveSnappedTape - }; -//--- -enum TRANSACTION_OUTCOME - { - TransactionOutcomeUndetermined=1, - TransactionOutcomeCommitted, - TransactionOutcomeAborted - }; -//--- -enum TRANSACTION_STATE - { - TransactionStateNormal=1, - TransactionStateIndoubt, - TransactionStateCommittedNotify - }; -//--- -enum TRANSACTION_INFORMATION_CLASS - { - TransactionBasicInformation, - TransactionPropertiesInformation, - TransactionEnlistmentInformation, - TransactionSuperiorEnlistmentInformation, - TransactionBindInformation, - TransactionDTCPrivateInformation - }; -//--- -enum TRANSACTIONMANAGER_INFORMATION_CLASS - { - TransactionManagerBasicInformation, - TransactionManagerLogInformation, - TransactionManagerLogPathInformation, - TransactionManagerRecoveryInformation=4, - TransactionManagerOnlineProbeInformation=3, - TransactionManagerOldestTransactionInformation=5 - }; -//--- -enum RESOURCEMANAGER_INFORMATION_CLASS - { - ResourceManagerBasicInformation, - ResourceManagerCompletionInformation - }; -//--- -enum ENLISTMENT_INFORMATION_CLASS - { - EnlistmentBasicInformation, - EnlistmentRecoveryInformation, - EnlistmentCrmInformation - }; -//--- -enum KTMOBJECT_TYPE - { - KTMOBJECT_TRANSACTION, - KTMOBJECT_TRANSACTION_MANAGER, - KTMOBJECT_RESOURCE_MANAGER, - KTMOBJECT_ENLISTMENT, - KTMOBJECT_INVALID - }; -//--- -enum TP_CALLBACK_PRIORITY - { - TP_CALLBACK_PRIORITY_HIGH, - TP_CALLBACK_PRIORITY_NORMAL, - TP_CALLBACK_PRIORITY_LOW, - TP_CALLBACK_PRIORITY_INVALID, - TP_CALLBACK_PRIORITY_COUNT=TP_CALLBACK_PRIORITY_INVALID - }; -//--- -enum POWER_USER_PRESENCE_TYPE - { - UserNotPresent=0, - UserPresent=1, - UserUnknown=0xff - }; -//--- -enum POWER_MONITOR_REQUEST_REASON - { - MonitorRequestReasonUnknown, - MonitorRequestReasonPowerButton, - MonitorRequestReasonRemoteConnection, - MonitorRequestReasonScMonitorpower, - MonitorRequestReasonUserInput, - MonitorRequestReasonAcDcDisplayBurst, - MonitorRequestReasonUserDisplayBurst, - MonitorRequestReasonPoSetSystemState, - MonitorRequestReasonSetThreadExecutionState, - MonitorRequestReasonFullWake, - MonitorRequestReasonSessionUnlock, - MonitorRequestReasonScreenOffRequest, - MonitorRequestReasonIdleTimeout, - MonitorRequestReasonPolicyChange, - MonitorRequestReasonSleepButton, - MonitorRequestReasonLid, - MonitorRequestReasonBatteryCountChange, - MonitorRequestReasonGracePeriod, - MonitorRequestReasonPnP, - MonitorRequestReasonDP, - MonitorRequestReasonSxTransition, - MonitorRequestReasonSystemIdle, - MonitorRequestReasonNearProximity, - MonitorRequestReasonThermalStandby, - MonitorRequestReasonResumePdc, - MonitorRequestReasonResumeS4, - MonitorRequestReasonTerminal, - MonitorRequestReasonPdcSignal, - MonitorRequestReasonAcDcDisplayBurstSuppressed, - MonitorRequestReasonSystemStateEntered, - MonitorRequestReasonWinrt, - MonitorRequestReasonUserInputKeyboard, - MonitorRequestReasonUserInputMouse, - MonitorRequestReasonUserInputTouch, - MonitorRequestReasonUserInputPen, - MonitorRequestReasonUserInputAccelerometer, - MonitorRequestReasonUserInputHid, - MonitorRequestReasonUserInputPoUserPresent, - MonitorRequestReasonUserInputSessionSwitch, - MonitorRequestReasonUserInputInitialization, - MonitorRequestReasonPdcSignalWindowsMobilePwrNotif, - MonitorRequestReasonPdcSignalWindowsMobileShell, - MonitorRequestReasonPdcSignalHeyCortana, - MonitorRequestReasonPdcSignalHolographicShell, - MonitorRequestReasonPdcSignalFingerprint, - MonitorRequestReasonMax - }; -//--- -enum POWER_ACTION - { - PowerActionNone=0, - PowerActionReserved, - PowerActionSleep, - PowerActionHibernate, - PowerActionShutdown, - PowerActionShutdownReset, - PowerActionShutdownOff, - PowerActionWarmEject, - PowerActionDisplayOff - }; -//--- -enum ACTCTX_REQUESTED_RUN_LEVEL - { - ACTCTX_RUN_LEVEL_UNSPECIFIED=0, - ACTCTX_RUN_LEVEL_AS_INVOKER, - ACTCTX_RUN_LEVEL_HIGHEST_AVAILABLE, - ACTCTX_RUN_LEVEL_REQUIRE_ADMIN, - ACTCTX_RUN_LEVEL_NUMBERS - }; -//--- -enum ACTCTX_COMPATIBILITY_ELEMENT_TYPE - { - ACTCTX_COMPATIBILITY_ELEMENT_TYPE_UNKNOWN=0, - ACTCTX_COMPATIBILITY_ELEMENT_TYPE_OS, - ACTCTX_COMPATIBILITY_ELEMENT_TYPE_MITIGATION - }; -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -//--- -struct PROCESSOR_NUMBER - { - ushort Group; - uchar Number; - uchar Reserved; - }; -//--- -struct GROUP_AFFINITY - { - ulong Mask; - ushort Group; - ushort Reserved[3]; - }; -//--- -struct FLOAT128 - { - long LowPart; - long HighPart; - }; -//--- -struct LARGE_INTEGER - { - long QuadPart; - }; -//--- -struct ULARGE_INTEGER - { - ulong QuadPart; - }; -//--- -struct LUID - { - uint LowPart; - int HighPart; - }; -//--- -struct LIST_ENTRY - { - PVOID Flink; - PVOID Blink; - }; -//--- -struct SINGLE_LIST_ENTRY - { - PVOID Next; - }; -//--- -struct LIST_ENTRY32 - { - uint Flink; - uint Blink; - }; -//--- -struct LIST_ENTRY64 - { - ulong Flink; - ulong Blink; - }; -//--- -struct OBJECTID - { - GUID Lineage; - uint Uniquifier; - }; -//--- -struct M128A - { - ulong Low; - long High; - }; -//--- -struct XSAVE_FORMAT - { - ushort Controlushort; - ushort Statusushort; - uchar Tagushort; - uchar Reserved1; - ushort ErrorOpcode; - uint ErrorOffset; - ushort ErrorSelector; - ushort Reserved2; - uint DataOffset; - ushort DataSelector; - ushort Reserved3; - uint MxCsr; - uint MxCsr_Mask; - M128A FloatRegisters[8]; - M128A XmmRegisters[16]; - uchar Reserved4[96]; - }; -//--- -struct XSAVE_AREA_HEADER - { - ulong Mask; - ulong CompactionMask; - ulong Reserved2[6]; - }; -//--- -struct XSAVE_AREA - { - XSAVE_FORMAT LegacyState; - XSAVE_AREA_HEADER Header; - }; -//--- -struct XSTATE_CONTEXT - { - ulong Mask; - uint Length; - uint Reserved1; - PVOID Area; - uint Reserved2; - PVOID Buffer; - uint Reserved3; - }; -//--- -struct SCOPE_TABLE_AMD64 - { - uint Count; - uint BeginAddress; - uint EndAddress; - uint HandlerAddress; - uint JumpTarget; - }; -//--- -struct UNWIND_HISTORY_TABLE_ENTRY - { - ulong ImageBase; - PVOID FunctionEntry; - }; -//--- -struct UNWIND_HISTORY_TABLE - { - uint Count; - uchar LocalHint; - uchar GlobalHint; - uchar Search; - uchar Once; - ulong LowAddress; - ulong HighAddress; - UNWIND_HISTORY_TABLE_ENTRY Entry[UNWIND_HISTORY_TABLE_SIZE]; - }; -//--- -struct SCOPE_TABLE_ARM64 - { - uint Count; - uint BeginAddress; - uint EndAddress; - uint HandlerAddress; - uint JumpTarget; - }; -//--- -struct NEON128 - { - ulong Low; - long High; - }; -//--- -struct DISPATCHER_CONTEXT - { - uint ControlPc; - uint ImageBase; - PVOID FunctionEntry; - uint EstablisherFrame; - uint TargetPc; - PVOID ContextRecord; - PVOID LanguageHandler; - PVOID HandlerData; - PVOID HistoryTable; - uint ScopeIndex; - uchar ControlPcIsUnwound; - PVOID NonVolatileRegisters; - uint Reserved; - }; -//--- -struct KNONVOLATILE_CONTEXT_POINTERS - { - PVOID FloatingContext[16]; - PVOID IntegerContext[16]; - }; -//--- -struct SCOPE_TABLE_ARM - { - uint Count; - uint BeginAddress; - uint EndAddress; - uint HandlerAddress; - uint JumpTarget; - }; -//--- -struct DISPATCHER_CONTEXT_ARM64 - { - ulong ControlPc; - ulong ImageBase; - PVOID FunctionEntry; - ulong EstablisherFrame; - ulong TargetPc; - PVOID ContextRecord; - PVOID LanguageHandler; - PVOID HandlerData; - PVOID HistoryTable; - uint ScopeIndex; - uchar ControlPcIsUnwound; - PVOID NonVolatileRegisters; - }; -//--- -struct KNONVOLATILE_CONTEXT_POINTERS_ARM64 - { - PVOID X19; - PVOID X20; - PVOID X21; - PVOID X22; - PVOID X23; - PVOID X24; - PVOID X25; - PVOID X26; - PVOID X27; - PVOID X28; - PVOID Fp; - PVOID Lr; - PVOID D8; - PVOID D9; - PVOID D10; - PVOID D11; - PVOID D12; - PVOID D13; - PVOID D14; - PVOID D15; - }; -//--- -struct FLOATING_SAVE_AREA - { - uint Controlushort; - uint Statusushort; - uint Tagushort; - uint ErrorOffset; - uint ErrorSelector; - uint DataOffset; - uint DataSelector; - uchar RegisterArea[SIZE_OF_80387_REGISTERS]; - uint Spare0; - }; -//--- -struct CONTEXT - { - ulong P1Home; - ulong P2Home; - ulong P3Home; - ulong P4Home; - ulong P5Home; - ulong P6Home; - uint ContextFlags; - uint MxCsr; - ushort SegCs; - ushort SegDs; - ushort SegEs; - ushort SegFs; - ushort SegGs; - ushort SegSs; - uint EFlags; - ulong Dr0; - ulong Dr1; - ulong Dr2; - ulong Dr3; - ulong Dr6; - ulong Dr7; - ulong Rax; - ulong Rcx; - ulong Rdx; - ulong Rbx; - ulong Rsp; - ulong Rbp; - ulong Rsi; - ulong Rdi; - ulong R8; - ulong R9; - ulong R10; - ulong R11; - ulong R12; - ulong R13; - ulong R14; - ulong R15; - ulong Rip; - M128A Header[2]; - M128A Legacy[8]; - M128A Xmm0; - M128A Xmm1; - M128A Xmm2; - M128A Xmm3; - M128A Xmm4; - M128A Xmm5; - M128A Xmm6; - M128A Xmm7; - M128A Xmm8; - M128A Xmm9; - M128A Xmm10; - M128A Xmm11; - M128A Xmm12; - M128A Xmm13; - M128A Xmm14; - M128A Xmm15; - M128A VectorRegister[26]; - ulong VectorControl; - ulong DebugControl; - ulong LastBranchToRip; - ulong LastBranchFromRip; - ulong LastExceptionToRip; - ulong LastExceptionFromRip; - }; -//--- -struct WOW64_FLOATING_SAVE_AREA - { - uint Controlushort; - uint Statusushort; - uint Tagushort; - uint ErrorOffset; - uint ErrorSelector; - uint DataOffset; - uint DataSelector; - uchar RegisterArea[WOW64_SIZE_OF_80387_REGISTERS]; - uint Cr0NpxState; - }; -//--- -struct WOW64_CONTEXT - { - uint ContextFlags; - uint Dr0; - uint Dr1; - uint Dr2; - uint Dr3; - uint Dr6; - uint Dr7; - WOW64_FLOATING_SAVE_AREA FloatSave; - uint SegGs; - uint SegFs; - uint SegEs; - uint SegDs; - uint Edi; - uint Esi; - uint Ebx; - uint Edx; - uint Ecx; - uint Eax; - uint Ebp; - uint Eip; - uint SegCs; - uint EFlags; - uint Esp; - uint SegSs; - uchar ExtendedRegisters[WOW64_MAXIMUM_SUPPORTED_EXTENSION]; - }; -//--- -struct WOW64_LDT_ENTRY - { - uint LimitLow; - uint BaseLow; - uchar BaseMid; - uchar Flags1; - uchar Flags2; - uchar BaseHi; - }; -//--- -struct WOW64_DESCRIPTOR_TABLE_ENTRY - { - uint Selector; - WOW64_LDT_ENTRY Descriptor; - }; -//--- -struct EXCEPTION_RECORD - { - uint ExceptionCode; - uint ExceptionFlags; - PVOID ExceptionRecord; - PVOID ExceptionAddress; - uint NumberParameters; - PVOID ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; - }; -//--- -struct EXCEPTION_RECORD32 - { - uint ExceptionCode; - uint ExceptionFlags; - uint ExceptionRecord; - uint ExceptionAddress; - uint NumberParameters; - uint ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; - }; -//--- -struct EXCEPTION_RECORD64 - { - uint ExceptionCode; - uint ExceptionFlags; - ulong ExceptionRecord; - ulong ExceptionAddress; - uint NumberParameters; - uint __unusedAlignment; - ulong ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; - }; -//--- -struct EXCEPTION_POINTERS - { - PVOID ExceptionRecord; - PVOID ContextRecord; - }; -//--- -struct GENERIC_MAPPING - { - uint GenericRead; - uint GenericWrite; - uint GenericExecute; - uint GenericAll; - }; -//--- -struct LUID_AND_ATTRIBUTES - { - LUID Luid; - uint Attributes; - }; -//--- -struct SID_IDENTIFIER_AUTHORITY - { - uchar Value[6]; - }; -//--- -//--- -struct SID - { - uchar Revision; - uchar SubAuthorityCount; - SID_IDENTIFIER_AUTHORITY IdentifierAuthority; - uint SubAuthority[ANYSIZE_ARRAY]; - }; -//--- -struct SID_AND_ATTRIBUTES - { - SID Sid; - uint Attributes; - }; -//--- -struct SID_AND_ATTRIBUTES_HASH - { - uint SidCount; - PVOID SidAttr; - ulong Hash[SID_HASH_SIZE]; - }; -//--- -struct ACL - { - uchar AclRevision; - uchar Sbz1; - ushort AclSize; - ushort AceCount; - ushort Sbz2; - }; -//--- -struct ACE_HEADER - { - uchar AceType; - uchar AceFlags; - ushort AceSize; - }; -//--- -struct ACCESS_ALLOWED_ACE - { - ACE_HEADER Header; - uint Mask; - uint SidStart; - }; -//--- -struct ACCESS_DENIED_ACE - { - ACE_HEADER Header; - uint Mask; - uint SidStart; - }; -//--- -struct SYSTEM_AUDIT_ACE - { - ACE_HEADER Header; - uint Mask; - uint SidStart; - }; -//--- -struct SYSTEM_ALARM_ACE - { - ACE_HEADER Header; - uint Mask; - uint SidStart; - }; -//--- -struct SYSTEM_RESOURCE_ATTRIBUTE_ACE - { - ACE_HEADER Header; - uint Mask; - uint SidStart; - }; -//--- -struct SYSTEM_SCOPED_POLICY_ID_ACE - { - ACE_HEADER Header; - uint Mask; - uint SidStart; - }; -//--- -struct SYSTEM_MANDATORY_LABEL_ACE - { - ACE_HEADER Header; - uint Mask; - uint SidStart; - }; -//--- -struct SYSTEM_PROCESS_TRUST_LABEL_ACE - { - ACE_HEADER Header; - uint Mask; - uint SidStart; - }; -//--- -struct SYSTEM_ACCESS_FILTER_ACE - { - ACE_HEADER Header; - uint Mask; - uint SidStart; - }; -//--- -struct ACCESS_ALLOWED_OBJECT_ACE - { - ACE_HEADER Header; - uint Mask; - uint Flags; - GUID ObjectType; - GUID InheritedObjectType; - uint SidStart; - }; -//--- -struct ACCESS_DENIED_OBJECT_ACE - { - ACE_HEADER Header; - uint Mask; - uint Flags; - GUID ObjectType; - GUID InheritedObjectType; - uint SidStart; - }; -//--- -struct SYSTEM_AUDIT_OBJECT_ACE - { - ACE_HEADER Header; - uint Mask; - uint Flags; - GUID ObjectType; - GUID InheritedObjectType; - uint SidStart; - }; -//--- -struct SYSTEM_ALARM_OBJECT_ACE - { - ACE_HEADER Header; - uint Mask; - uint Flags; - GUID ObjectType; - GUID InheritedObjectType; - uint SidStart; - }; -//--- -struct ACCESS_ALLOWED_CALLBACK_ACE - { - ACE_HEADER Header; - uint Mask; - uint SidStart; - }; -//--- -struct ACCESS_DENIED_CALLBACK_ACE - { - ACE_HEADER Header; - uint Mask; - uint SidStart; - }; -//--- -struct SYSTEM_AUDIT_CALLBACK_ACE - { - ACE_HEADER Header; - uint Mask; - uint SidStart; - }; -//--- -struct SYSTEM_ALARM_CALLBACK_ACE - { - ACE_HEADER Header; - uint Mask; - uint SidStart; - }; -//--- -struct ACCESS_ALLOWED_CALLBACK_OBJECT_ACE - { - ACE_HEADER Header; - uint Mask; - uint Flags; - GUID ObjectType; - GUID InheritedObjectType; - uint SidStart; - }; -//--- -struct ACCESS_DENIED_CALLBACK_OBJECT_ACE - { - ACE_HEADER Header; - uint Mask; - uint Flags; - GUID ObjectType; - GUID InheritedObjectType; - uint SidStart; - }; -//--- -struct SYSTEM_AUDIT_CALLBACK_OBJECT_ACE - { - ACE_HEADER Header; - uint Mask; - uint Flags; - GUID ObjectType; - GUID InheritedObjectType; - uint SidStart; - }; -//--- -struct SYSTEM_ALARM_CALLBACK_OBJECT_ACE - { - ACE_HEADER Header; - uint Mask; - uint Flags; - GUID ObjectType; - GUID InheritedObjectType; - uint SidStart; - }; -//--- -struct ACL_REVISION_INFORMATION - { - uint AclRevision; - }; -//--- -struct ACL_SIZE_INFORMATION - { - uint AceCount; - uint AclBytesInUse; - uint AclBytesFree; - }; -//--- -struct SECURITY_DESCRIPTOR_RELATIVE - { - uchar Revision; - uchar Sbz1; - ushort Control; - uint Owner; - uint Group; - uint Sacl; - uint Dacl; - }; -//--- -struct SECURITY_DESCRIPTOR - { - uchar Revision; - uchar Sbz1; - ushort Control; - uchar offset[4]; - PVOID Owner; - PVOID Group; - PVOID Sacl; - PVOID Dacl; - }; -//--- -struct SECURITY_OBJECT_AI_PARAMS - { - uint Size; - uint ConstraintMask; - }; -//--- -struct OBJECT_TYPE_LIST - { - ushort Level; - ushort Sbz; - GUID ObjectType; - }; -//--- -struct PRIVILEGE_SET - { - uint PrivilegeCount; - uint Control; - LUID_AND_ATTRIBUTES Privilege[ANYSIZE_ARRAY]; - }; -//--- -struct ACCESS_REASONS - { - uint Data[32]; - }; -//--- -struct SE_SECURITY_DESCRIPTOR - { - uint Size; - uint Flags; - PVOID SecurityDescriptor; - }; -//--- -struct SE_ACCESS_REQUEST - { - uint Size; - PVOID SeSecurityDescriptor; - uint DesiredAccess; - uint PreviouslyGrantedAccess; - PVOID PrincipalSelfSid; - PVOID GenericMapping; - uint ObjectTypeListCount; - PVOID ObjectTypeList; - }; -//--- -struct SE_ACCESS_REPLY - { - uint Size; - uint ResultListCount; - PVOID GrantedAccess; - uint AccessStatus; - PVOID AccessReason; - PVOID Privileges; - }; -//--- -struct TOKEN_USER - { - SID_AND_ATTRIBUTES User; - }; -//--- -struct SE_TOKEN_USER - { - TOKEN_USER TokenUser; - SID Sid; - }; -//--- -struct TOKEN_GROUPS - { - uint GroupCount; - SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY]; - }; -//--- -struct TOKEN_PRIVILEGES - { - uint PrivilegeCount; - LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY]; - }; -//--- -struct TOKEN_OWNER - { - PVOID Owner; - }; -//--- -struct TOKEN_PRIMARY_GROUP - { - PVOID PrimaryGroup; - }; -//--- -struct TOKEN_DEFAULT_DACL - { - PVOID DefaultDacl; - }; -//--- -struct TOKEN_USER_CLAIMS - { - PVOID UserClaims; - }; -//--- -struct TOKEN_DEVICE_CLAIMS - { - PVOID DeviceClaims; - }; -//--- -struct TOKEN_GROUPS_AND_PRIVILEGES - { - uint SidCount; - uint SidLength; - PVOID Sids; - uint RestrictedSidCount; - uint RestrictedSidLength; - PVOID RestrictedSids; - uint PrivilegeCount; - uint PrivilegeLength; - PVOID Privileges; - LUID AuthenticationId; - }; -//--- -struct TOKEN_LINKED_TOKEN - { - HANDLE LinkedToken; - }; -//--- -struct TOKEN_ELEVATION - { - uint TokenIsElevated; - }; -//--- -struct TOKEN_MANDATORY_LABEL - { - SID_AND_ATTRIBUTES Label; - }; -//--- -struct TOKEN_MANDATORY_POLICY - { - uint Policy; - }; -//--- -struct TOKEN_ACCESS_INFORMATION - { - PVOID SidHash; - PVOID RestrictedSidHash; - PVOID Privileges; - LUID AuthenticationId; - TOKEN_TYPE TokenType; - SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; - TOKEN_MANDATORY_POLICY MandatoryPolicy; - uint Flags; - uint AppContainerNumber; - PVOID PackageSid; - PVOID CapabilitiesHash; - PVOID TrustLevelSid; - PVOID SecurityAttributes; - }; -//--- -struct TOKEN_AUDIT_POLICY - { - uchar PerUserPolicy[((POLICY_AUDIT_SUBCATEGORY_COUNT)>>1)+1]; - }; -//--- -struct TOKEN_SOURCE - { - char SourceName[TOKEN_SOURCE_LENGTH]; - LUID SourceIdentifier; - }; -//--- -struct TOKEN_STATISTICS - { - LUID TokenId; - LUID AuthenticationId; - long ExpirationTime; - TOKEN_TYPE TokenType; - SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; - uint DynamicCharged; - uint DynamicAvailable; - uint GroupCount; - uint PrivilegeCount; - LUID ModifiedId; - }; -//--- -struct TOKEN_CONTROL - { - LUID TokenId; - LUID AuthenticationId; - LUID ModifiedId; - TOKEN_SOURCE TokenSource; - }; -//--- -struct TOKEN_ORIGIN - { - LUID OriginatingLogonSession; - }; -//--- -struct TOKEN_APPCONTAINER_INFORMATION - { - PVOID TokenAppContainer; - }; -//--- -struct TOKEN_SID_INFORMATION - { - PVOID Sid; - }; -//--- -struct TOKEN_BNO_ISOLATION_INFORMATION - { - string IsolationPrefix; - uchar IsolationEnabled; - }; -//--- -struct CLAIM_SECURITY_ATTRIBUTE_FQBN_VALUE - { - ulong Version; - string Name; - }; -//--- -struct CLAIM_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE - { - PVOID pValue; - uint ValueLength; - }; -//--- -struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 - { - uint Name; - ushort ValueType; - ushort Reserved; - uint Flags; - uint ValueCount; - uint pInt64[ANYSIZE_ARRAY]; - }; -//--- -struct Attribute - { - ushort Version; - ushort Reserved; - uint AttributeCount; - PVOID pAttributeV1; - }; -//--- -struct SECURITY_QUALITY_OF_SERVICE - { - uint Length; - SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; - uchar ContextTrackingMode; - uchar EffectiveOnly; - }; -//--- -struct SE_IMPERSONATION_STATE - { - PVOID Token; - uchar CopyOnOpen; - uchar EffectiveOnly; - SECURITY_IMPERSONATION_LEVEL Level; - }; -//--- -struct SECURITY_CAPABILITIES - { - PVOID AppContainerSid; - PVOID Capabilities; - uint CapabilityCount; - uint Reserved; - }; -//--- -struct JOB_SET_ARRAY - { - HANDLE JobHandle; - uint MemberLevel; - uint Flags; - }; -//--- -struct EXCEPTION_REGISTRATION_RECORD - { - PVOID Next; - PVOID Handler; - }; -//--- -struct NT_TIB - { - PVOID ExceptionList; - PVOID StackBase; - PVOID StackLimit; - PVOID SubSystemTib; - PVOID FiberData; - PVOID ArbitraryUserPointer; - PVOID Self; - }; -//--- -struct UMS_CREATE_THREAD_ATTRIBUTES - { - uint UmsVersion; - PVOID UmsContext; - PVOID UmsCompletionList; - }; -//--- -struct WOW64_ARCHITECTURE_INFORMATION - { - uint Info; - }; -//--- -struct QUOTA_LIMITS - { - ulong PagedPoolLimit; - ulong NonPagedPoolLimit; - ulong MinimumWorkingSetSize; - ulong MaximumWorkingSetSize; - ulong PagefileLimit; - long TimeLimit; - }; -//--- -struct QUOTA_LIMITS_EX - { - ulong PagedPoolLimit; - ulong NonPagedPoolLimit; - ulong MinimumWorkingSetSize; - ulong MaximumWorkingSetSize; - ulong PagefileLimit; - long TimeLimit; - ulong WorkingSetLimit; - ulong Reserved2; - ulong Reserved3; - ulong Reserved4; - uint Flags; - uint CpuRateLimit; - }; -//--- -struct IO_COUNTERS - { - ulong ReadOperationCount; - ulong WriteOperationCount; - ulong OtherOperationCount; - ulong ReadTransferCount; - ulong WriteTransferCount; - ulong OtherTransferCount; - }; -//--- -struct JOBOBJECT_BASIC_ACCOUNTING_INFORMATION - { - long TotalUserTime; - long TotalKernelTime; - long ThisPeriodTotalUserTime; - long ThisPeriodTotalKernelTime; - uint TotalPageFaultCount; - uint TotalProcesses; - uint ActiveProcesses; - uint TotalTerminatedProcesses; - }; -//--- -struct JOBOBJECT_BASIC_LIMIT_INFORMATION - { - long PerProcessUserTimeLimit; - long PerJobUserTimeLimit; - uint LimitFlags; - ulong MinimumWorkingSetSize; - ulong MaximumWorkingSetSize; - uint ActiveProcessLimit; - ulong Affinity; - uint PriorityClass; - uint SchedulingClass; - }; -//--- -struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION - { - JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; - IO_COUNTERS IoInfo; - ulong ProcessMemoryLimit; - ulong JobMemoryLimit; - ulong PeakProcessMemoryUsed; - ulong PeakJobMemoryUsed; - }; -//--- -struct JOBOBJECT_BASIC_PROCESS_ID_LIST - { - uint NumberOfAssignedProcesses; - uint NumberOfProcessIdsInList; - ulong ProcessIdList[1]; - }; -//--- -struct JOBOBJECT_BASIC_UI_RESTRICTIONS - { - uint UIRestrictionsClass; - }; -//--- -struct JOBOBJECT_SECURITY_LIMIT_INFORMATION - { - uint SecurityLimitFlags; - HANDLE JobToken; - PVOID SidsToDisable; - PVOID PrivilegesToDelete; - PVOID RestrictedSids; - }; -//--- -struct JOBOBJECT_END_OF_JOB_TIME_INFORMATION - { - uint EndOfJobTimeAction; - }; -//--- -struct JOBOBJECT_ASSOCIATE_COMPLETION_PORT - { - PVOID CompletionKey; - HANDLE CompletionPort; - }; -//--- -struct JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION - { - JOBOBJECT_BASIC_ACCOUNTING_INFORMATION BasicInfo; - IO_COUNTERS IoInfo; - }; -//--- -struct JOBOBJECT_JOBSET_INFORMATION - { - uint MemberLevel; - }; -//--- -struct JOBOBJECT_NOTIFICATION_LIMIT_INFORMATION - { - ulong IoReadBytesLimit; - ulong IoWriteBytesLimit; - long PerJobUserTimeLimit; - ulong JobMemoryLimit; - JOBOBJECT_RATE_CONTROL_TOLERANCE RateControlTolerance; - JOBOBJECT_RATE_CONTROL_TOLERANCE_INTERVAL RateControlToleranceInterval; - uint LimitFlags; - }; -//--- -struct JOBOBJECT_LIMIT_VIOLATION_INFORMATION - { - uint LimitFlags; - uint ViolationLimitFlags; - ulong IoReadBytes; - ulong IoReadBytesLimit; - ulong IoWriteBytes; - ulong IoWriteBytesLimit; - long PerJobUserTime; - long PerJobUserTimeLimit; - ulong JobMemory; - ulong JobMemoryLimit; - JOBOBJECT_RATE_CONTROL_TOLERANCE RateControlTolerance; - JOBOBJECT_RATE_CONTROL_TOLERANCE RateControlToleranceLimit; - }; -//--- -struct JOBOBJECT_NET_RATE_CONTROL_INFORMATION - { - ulong MaxBandwidth; - JOB_OBJECT_NET_RATE_CONTROL_FLAGS ControlFlags; - uchar DscpTag; - }; -//--- -struct JOBOBJECT_IO_RATE_CONTROL_INFORMATION_NATIVE - { - long MaxIops; - long MaxBandwidth; - long ReservationIops; - string VolumeName; - uint BaseIoSize; - JOB_OBJECT_IO_RATE_CONTROL_FLAGS ControlFlags; - ushort VolumeNameLength; - }; -//--- -struct JOBOBJECT_IO_RATE_CONTROL_INFORMATION_NATIVE_V2 - { - long MaxIops; - long MaxBandwidth; - long ReservationIops; - string VolumeName; - uint BaseIoSize; - JOB_OBJECT_IO_RATE_CONTROL_FLAGS ControlFlags; - ushort VolumeNameLength; - long CriticalReservationIops; - long ReservationBandwidth; - long CriticalReservationBandwidth; - long MaxTimePercent; - long ReservationTimePercent; - long CriticalReservationTimePercent; - }; -//--- -struct JOBOBJECT_IO_RATE_CONTROL_INFORMATION_NATIVE_V3 - { - long MaxIops; - long MaxBandwidth; - long ReservationIops; - string VolumeName; - uint BaseIoSize; - JOB_OBJECT_IO_RATE_CONTROL_FLAGS ControlFlags; - ushort VolumeNameLength; - long CriticalReservationIops; - long ReservationBandwidth; - long CriticalReservationBandwidth; - long MaxTimePercent; - long ReservationTimePercent; - long CriticalReservationTimePercent; - long SoftMaxIops; - long SoftMaxBandwidth; - long SoftMaxTimePercent; - long LimitExcessNotifyIops; - long LimitExcessNotifyBandwidth; - long LimitExcessNotifyTimePercent; - }; -//--- -struct JOBOBJECT_IO_ATTRIBUTION_STATS - { - ulong IoCount; - ulong TotalNonOverlappedQueueTime; - ulong TotalNonOverlappedServiceTime; - ulong TotalSize; - }; -//--- -struct JOBOBJECT_IO_ATTRIBUTION_INFORMATION - { - uint ControlFlags; - JOBOBJECT_IO_ATTRIBUTION_STATS ReadStats; - JOBOBJECT_IO_ATTRIBUTION_STATS WriteStats; - }; -//--- -struct SILOOBJECT_BASIC_INFORMATION - { - uint SiloId; - uint SiloParentId; - uint NumberOfProcesses; - uchar IsInServerSilo; - uchar Reserved[3]; - }; -//--- -struct SERVERSILO_BASIC_INFORMATION - { - uint ServiceSessionId; - SERVERSILO_STATE State; - uint ExitStatus; - }; -//--- -struct CACHE_DESCRIPTOR - { - uchar Level; - uchar Associativity; - ushort LineSize; - uint Size; - PROCESSOR_CACHE_TYPE Type; - }; -//--- -struct ProcessorCore - { - ulong ProcessorMask; - LOGICAL_PROCESSOR_RELATIONSHIP Relationship; - uchar Flags; - }; -//--- -struct PROCESSOR_RELATIONSHIP - { - uchar Flags; - uchar EfficiencyClass; - uchar Reserved[20]; - ushort GroupCount; - GROUP_AFFINITY GroupMask[ANYSIZE_ARRAY]; - }; -//--- -struct NUMA_NODE_RELATIONSHIP - { - uint NodeNumber; - uchar Reserved[20]; - GROUP_AFFINITY GroupMask; - }; -//--- -struct CACHE_RELATIONSHIP - { - uchar Level; - uchar Associativity; - ushort LineSize; - uint CacheSize; - PROCESSOR_CACHE_TYPE Type; - uchar Reserved[20]; - GROUP_AFFINITY GroupMask; - }; -//--- -struct PROCESSOR_GROUP_INFO - { - uchar MaximumProcessorCount; - uchar ActiveProcessorCount; - uchar Reserved[38]; - ulong ActiveProcessorMask; - }; -//--- -struct GROUP_RELATIONSHIP - { - ushort MaximumGroupCount; - ushort ActiveGroupCount; - uchar Reserved[20]; - PROCESSOR_GROUP_INFO GroupInfo[ANYSIZE_ARRAY]; - }; -//--- -struct SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION - { - ulong CycleTime; - }; -//--- -struct XSTATE_FEATURE - { - uint Offset; - uint Size; - }; -//--- -struct XSTATE_CONFIGURATION - { - ulong EnabledFeatures; - ulong EnabledVolatileFeatures; - uint Size; - uint ControlFlags; - XSTATE_FEATURE Features[MAXIMUM_XSTATE_FEATURES]; - ulong EnabledSupervisorFeatures; - ulong AlignedFeatures; - uint AllFeatureSize; - uint AllFeatures[MAXIMUM_XSTATE_FEATURES]; - }; -//--- -struct MEMORY_BASIC_INFORMATION - { - PVOID BaseAddress; - PVOID AllocationBase; - uint AllocationProtect; - ulong RegionSize; - uint State; - uint Protect; - uint Type; - }; -//--- -struct MEMORY_BASIC_INFORMATION32 - { - uint BaseAddress; - uint AllocationBase; - uint AllocationProtect; - uint RegionSize; - uint State; - uint Protect; - uint Type; - }; -//--- -struct MEMORY_BASIC_INFORMATION64 - { - ulong BaseAddress; - ulong AllocationBase; - uint AllocationProtect; - uint __alignment1; - ulong RegionSize; - uint State; - uint Protect; - uint Type; - uint __alignment2; - }; -//--- -struct CFG_CALL_TARGET_INFO - { - ulong Offset; - ulong Flags; - }; -//--- -struct MEM_ADDRESS_REQUIREMENTS - { - PVOID LowestStartingAddress; - PVOID HighestEndingAddress; - ulong Alignment; - }; -//--- -struct ENCLAVE_CREATE_INFO_SGX - { - uchar Secs[4096]; - }; -//--- -struct ENCLAVE_INIT_INFO_SGX - { - uchar SigStruct[1808]; - uchar Reserved1[240]; - uchar EInitToken[304]; - uchar Reserved2[1744]; - }; -//--- -struct ENCLAVE_CREATE_INFO_VBS - { - uint Flags; - uchar OwnerID[32]; - }; -//--- -struct ENCLAVE_INIT_INFO_VBS - { - uint Length; - uint ThreadCount; - }; -//--- -struct FILE_ID_128 - { - uchar Identifier[16]; - }; -//--- -struct FILE_NOTIFY_INFORMATION - { - uint NextEntryOffset; - uint Action; - uint FileNameLength; - short FileName[1]; - }; -//--- -struct FILE_NOTIFY_EXTENDED_INFORMATION - { - uint NextEntryOffset; - uint Action; - long CreationTime; - long LastModificationTime; - long LastChangeTime; - long LastAccessTime; - long AllocatedLength; - long FileSize; - uint FileAttributes; - uint ReparsePointTag; - long FileId; - long ParentFileId; - uint FileNameLength; - short FileName[1]; - }; -//--- -struct GenericReparseBuffer - { - uint ReparseTag; - ushort ReparseDataLength; - ushort Reserved; - GUID ReparseGuid; - uchar DataBuffer[1]; - }; -//--- -struct SCRUB_DATA_INPUT - { - uint Size; - uint Flags; - uint MaximumIos; - uint ObjectId[4]; - uint Reserved[13]; - uchar ResumeContext[816]; - }; -//--- -struct SCRUB_PARITY_EXTENT - { - long Offset; - ulong Length; - }; -//--- -struct SCRUB_PARITY_EXTENT_DATA - { - ushort Size; - ushort Flags; - ushort NumberOfParityExtents; - ushort MaximumNumberOfParityExtents; - SCRUB_PARITY_EXTENT ParityExtents[ANYSIZE_ARRAY]; - }; -//--- -struct SCRUB_DATA_OUTPUT - { - uint Size; - uint Flags; - uint Status; - ulong ErrorFileOffset; - ulong ErrorLength; - ulong NumberOfBytesRepaired; - ulong NumberOfBytesFailed; - ulong InternalFileReference; - ushort ResumeContextLength; - ushort ParityExtentDataOffset; - uint Reserved[5]; - uchar ResumeContext[816]; - }; -//--- -struct SHARED_VIRTUAL_DISK_SUPPORT - { - SharedVirtualDiskSupportType SharedVirtualDiskSupport; - SharedVirtualDiskHandleState HandleState; - }; -//--- -struct NETWORK_APP_INSTANCE_EA - { - GUID AppInstanceID; - uint CsvFlags; - }; -//--- -struct CM_POWER_DATA - { - uint PD_Size; - DEVICE_POWER_STATE PD_MostRecentPowerState; - uint PD_Capabilities; - uint PD_D1Latency; - uint PD_D2Latency; - uint PD_D3Latency; - DEVICE_POWER_STATE PD_PowerStateMapping[POWER_SYSTEM_MAXIMUM]; - SYSTEM_POWER_STATE PD_DeepestSystemWake; - }; -//--- -struct POWER_USER_PRESENCE - { - POWER_USER_PRESENCE_TYPE UserPresence; - }; -//--- -struct POWER_SESSION_CONNECT - { - uchar Connected; - uchar Console; - }; -//--- -struct POWER_SESSION_TIMEOUTS - { - uint InputTimeout; - uint DisplayTimeout; - }; -//--- -struct POWER_SESSION_RIT_STATE - { - uchar Active; - uint LastInputTime; - }; -//--- -struct POWER_SESSION_WINLOGON - { - uint SessionId; - uchar Console; - uchar Locked; - }; -//--- -struct POWER_IDLE_RESILIENCY - { - uint CoalescingTimeout; - uint IdleResiliencyPeriod; - }; -//--- -struct POWER_MONITOR_INVOCATION - { - uchar Console; - POWER_MONITOR_REQUEST_REASON RequestReason; - }; -//--- -struct RESUME_PERFORMANCE - { - uint PostTimeMs; - ulong TotalResumeTimeMs; - ulong ResumeCompleteTimestamp; - }; -//--- -struct APPLICATIONLAUNCH_SETTING_VALUE - { - long ActivationTime; - uint Flags; - uint ButtonInstanceID; - }; -//--- -struct POWER_PLATFORM_INFORMATION - { - uchar AoAc; - }; -//--- -struct POWER_ACTION_POLICY - { - POWER_ACTION Action; - uint Flags; - uint EventCode; - }; -//--- -struct SYSTEM_POWER_LEVEL - { - uchar Enable; - uchar Spare[3]; - uint BatteryLevel; - POWER_ACTION_POLICY PowerPolicy; - SYSTEM_POWER_STATE MinSystemState; - }; -//--- -struct SYSTEM_POWER_POLICY - { - uint Revision; - POWER_ACTION_POLICY PowerButton; - POWER_ACTION_POLICY SleepButton; - POWER_ACTION_POLICY LidClose; - SYSTEM_POWER_STATE LidOpenWake; - uint Reserved; - POWER_ACTION_POLICY Idle; - uint IdleTimeout; - uchar IdleSensitivity; - uchar DynamicThrottle; - uchar Spare2[2]; - SYSTEM_POWER_STATE MinSleep; - SYSTEM_POWER_STATE MaxSleep; - SYSTEM_POWER_STATE ReducedLatencySleep; - uint WinLogonFlags; - uint Spare3; - uint DozeS4Timeout; - uint BroadcastCapacityResolution; - SYSTEM_POWER_LEVEL DischargePolicy[NUM_DISCHARGE_POLICIES]; - uint VideoTimeout; - uchar VideoDimDisplay; - uint VideoReserved[3]; - uint SpindownTimeout; - uchar OptimizeForPower; - uchar FanThrottleTolerance; - uchar ForcedThrottle; - uchar MinThrottle; - POWER_ACTION_POLICY OverThrottled; - }; -//--- -struct PROCESSOR_POWER_POLICY_INFO - { - uint TimeCheck; - uint DemoteLimit; - uint PromoteLimit; - uchar DemotePercent; - uchar PromotePercent; - uchar Spare[2]; - uint Flags; - }; -//--- -struct PROCESSOR_POWER_POLICY - { - uint Revision; - uchar DynamicThrottle; - uchar Spare[3]; - uint Flags; - uint PolicyCount; - PROCESSOR_POWER_POLICY_INFO Policy[3]; - }; -//--- -struct ADMINISTRATOR_POWER_POLICY - { - SYSTEM_POWER_STATE MinSleep; - SYSTEM_POWER_STATE MaxSleep; - uint MinVideoTimeout; - uint MaxVideoTimeout; - uint MinSpindownTimeout; - uint MaxSpindownTimeout; - }; -//--- -struct HIBERFILE_BUCKET - { - ulong MaxPhysicalMemory; - uint PhysicalMemoryPercent[HIBERFILE_TYPE_MAX]; - }; -//--- -struct IMAGE_DOS_HEADER - { - ushort e_magic; - ushort e_cblp; - ushort e_cp; - ushort e_crlc; - ushort e_cparhdr; - ushort e_minalloc; - ushort e_maxalloc; - ushort e_ss; - ushort e_sp; - ushort e_csum; - ushort e_ip; - ushort e_cs; - ushort e_lfarlc; - ushort e_ovno; - ushort e_res[4]; - ushort e_oemid; - ushort e_oeminfo; - ushort e_res2[10]; - int e_lfanew; - }; -//--- -struct IMAGE_OS2_HEADER - { - ushort ne_magic; - char ne_ver; - char ne_rev; - ushort ne_enttab; - ushort ne_cbenttab; - int ne_crc; - ushort ne_flags; - ushort ne_autodata; - ushort ne_heap; - ushort ne_stack; - int ne_csip; - int ne_sssp; - ushort ne_cseg; - ushort ne_cmod; - ushort ne_cbnrestab; - ushort ne_segtab; - ushort ne_rsrctab; - ushort ne_restab; - ushort ne_modtab; - ushort ne_imptab; - int ne_nrestab; - ushort ne_cmovent; - ushort ne_align; - ushort ne_cres; - uchar ne_exetyp; - uchar ne_flagsothers; - ushort ne_pretthunks; - ushort ne_psegrefbytes; - ushort ne_swaparea; - ushort ne_expver; - }; -//--- -struct IMAGE_VXD_HEADER - { - ushort e32_magic; - uchar e32_border; - uchar e32_ushorter; - uint e32_level; - ushort e32_cpu; - ushort e32_os; - uint e32_ver; - uint e32_mflags; - uint e32_mpages; - uint e32_startobj; - uint e32_eip; - uint e32_stackobj; - uint e32_esp; - uint e32_pagesize; - uint e32_lastpagesize; - uint e32_fixupsize; - uint e32_fixupsum; - uint e32_ldrsize; - uint e32_ldrsum; - uint e32_objtab; - uint e32_objcnt; - uint e32_objmap; - uint e32_itermap; - uint e32_rsrctab; - uint e32_rsrccnt; - uint e32_restab; - uint e32_enttab; - uint e32_dirtab; - uint e32_dircnt; - uint e32_fpagetab; - uint e32_frectab; - uint e32_impmod; - uint e32_impmodcnt; - uint e32_impproc; - uint e32_pagesum; - uint e32_datapage; - uint e32_preload; - uint e32_nrestab; - uint e32_cbnrestab; - uint e32_nressum; - uint e32_autodata; - uint e32_debuginfo; - uint e32_debuglen; - uint e32_instpreload; - uint e32_instdemand; - uint e32_heapsize; - uchar e32_res3[12]; - uint e32_winresoff; - uint e32_winreslen; - ushort e32_devid; - ushort e32_ddkver; - }; -//--- -struct IMAGE_FILE_HEADER - { - ushort Machine; - ushort NumberOfSections; - uint TimeDateStamp; - uint PointerToSymbolTable; - uint NumberOfSymbols; - ushort SizeOfOptionalHeader; - ushort Characteristics; - }; -//--- -struct IMAGE_DATA_DIRECTORY - { - uint VirtualAddress; - uint Size; - }; -//--- -struct IMAGE_OPTIONAL_HEADER32 - { - ushort Magic; - uchar MajorLinkerVersion; - uchar MinorLinkerVersion; - uint SizeOfCode; - uint SizeOfInitializedData; - uint SizeOfUninitializedData; - uint AddressOfEntryPoint; - uint BaseOfCode; - uint BaseOfData; - uint ImageBase; - uint SectionAlignment; - uint FileAlignment; - ushort MajorOperatingSystemVersion; - ushort MinorOperatingSystemVersion; - ushort MajorImageVersion; - ushort MinorImageVersion; - ushort MajorSubsystemVersion; - ushort MinorSubsystemVersion; - uint Win32VersionValue; - uint SizeOfImage; - uint SizeOfHeaders; - uint CheckSum; - ushort Subsystem; - ushort DllCharacteristics; - uint SizeOfStackReserve; - uint SizeOfStackCommit; - uint SizeOfHeapReserve; - uint SizeOfHeapCommit; - uint LoaderFlags; - uint NumberOfRvaAndSizes; - IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; - }; -//--- -struct IMAGE_ROM_OPTIONAL_HEADER - { - ushort Magic; - uchar MajorLinkerVersion; - uchar MinorLinkerVersion; - uint SizeOfCode; - uint SizeOfInitializedData; - uint SizeOfUninitializedData; - uint AddressOfEntryPoint; - uint BaseOfCode; - uint BaseOfData; - uint BaseOfBss; - uint GprMask; - uint CprMask[4]; - uint GpValue; - }; -//--- -struct IMAGE_OPTIONAL_HEADER64 - { - ushort Magic; - uchar MajorLinkerVersion; - uchar MinorLinkerVersion; - uint SizeOfCode; - uint SizeOfInitializedData; - uint SizeOfUninitializedData; - uint AddressOfEntryPoint; - uint BaseOfCode; - ulong ImageBase; - uint SectionAlignment; - uint FileAlignment; - ushort MajorOperatingSystemVersion; - ushort MinorOperatingSystemVersion; - ushort MajorImageVersion; - ushort MinorImageVersion; - ushort MajorSubsystemVersion; - ushort MinorSubsystemVersion; - uint Win32VersionValue; - uint SizeOfImage; - uint SizeOfHeaders; - uint CheckSum; - ushort Subsystem; - ushort DllCharacteristics; - ulong SizeOfStackReserve; - ulong SizeOfStackCommit; - ulong SizeOfHeapReserve; - ulong SizeOfHeapCommit; - uint LoaderFlags; - uint NumberOfRvaAndSizes; - IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; - }; -//--- -struct IMAGE_NT_HEADERS64 - { - uint Signature; - IMAGE_FILE_HEADER FileHeader; - IMAGE_OPTIONAL_HEADER64 OptionalHeader; - }; -//--- -struct IMAGE_NT_HEADERS32 - { - uint Signature; - IMAGE_FILE_HEADER FileHeader; - IMAGE_OPTIONAL_HEADER32 OptionalHeader; - }; -//--- -struct IMAGE_ROM_HEADERS - { - IMAGE_FILE_HEADER FileHeader; - IMAGE_ROM_OPTIONAL_HEADER OptionalHeader; - }; -//--- -struct ANON_OBJECT_HEADER - { - ushort Sig1; - ushort Sig2; - ushort Version; - ushort Machine; - uint TimeDateStamp; - GUID ClassID; - uint SizeOfData; - }; -//--- -struct ANON_OBJECT_HEADER_V2 - { - ushort Sig1; - ushort Sig2; - ushort Version; - ushort Machine; - uint TimeDateStamp; - GUID ClassID; - uint SizeOfData; - uint Flags; - uint MetaDataSize; - uint MetaDataOffset; - }; -//--- -struct ANON_OBJECT_HEADER_BIGOBJ - { - ushort Sig1; - ushort Sig2; - ushort Version; - ushort Machine; - uint TimeDateStamp; - GUID ClassID; - uint SizeOfData; - uint Flags; - uint MetaDataSize; - uint MetaDataOffset; - uint NumberOfSections; - uint PointerToSymbolTable; - uint NumberOfSymbols; - }; -//--- -struct IMAGE_SECTION_HEADER - { - uchar Name[IMAGE_SIZEOF_SHORT_NAME]; - uint PhysicalAddress; - uint VirtualAddress; - uint SizeOfRawData; - uint PointerToRawData; - uint PointerToRelocations; - uint PointerToLinenumbers; - ushort NumberOfRelocations; - ushort NumberOfLinenumbers; - uint Characteristics; - }; -//--- -struct IMAGE_SYMBOL - { - uchar ShortName[8]; - uint Value; - short SectionNumber; - ushort Type; - uchar StorageClass; - uchar NumberOfAuxSymbols; - }; -//--- -struct IMAGE_SYMBOL_EX - { - uchar ShortName[8]; - uint Value; - int SectionNumber; - ushort Type; - uchar StorageClass; - uchar NumberOfAuxSymbols; - }; -//--- -struct IMAGE_AUX_SYMBOL_TOKEN_DEF - { - uchar bAuxType; - uchar bReserved; - uint SymbolTableIndex; - uchar rgbReserved[12]; - }; -//--- -struct IMAGE_LINENUMBER - { - uint VirtualAddress; - ushort Linenumber; - }; -//--- -struct IMAGE_BASE_RELOCATION - { - uint VirtualAddress; - uint SizeOfBlock; - }; -//--- -struct IMAGE_ARCHIVE_MEMBER_HEADER - { - uchar Name[16]; - uchar Date[12]; - uchar UserID[6]; - uchar GroupID[6]; - uchar Mode[8]; - uchar Size[10]; - uchar EndHeader[2]; - }; -//--- -struct IMAGE_EXPORT_DIRECTORY - { - uint Characteristics; - uint TimeDateStamp; - ushort MajorVersion; - ushort MinorVersion; - uint Name; - uint Base; - uint NumberOfFunctions; - uint NumberOfNames; - uint AddressOfFunctions; - uint AddressOfNames; - uint AddressOfNameOrdinals; - }; -//--- -struct IMAGE_IMPORT_BY_NAME - { - ushort Hint; - char Name[1]; - }; -//--- -struct IMAGE_THUNK_DATA64 - { - ulong Data; - }; -//--- -struct IMAGE_THUNK_DATA32 - { - uint Data; - }; -//--- -struct IMAGE_BOUND_IMPORT_DESCRIPTOR - { - uint TimeDateStamp; - ushort OffsetModuleName; - ushort NumberOfModuleForwarderRefs; - }; -//--- -struct IMAGE_BOUND_FORWARDER_REF - { - uint TimeDateStamp; - ushort OffsetModuleName; - ushort Reserved; - }; -//--- -struct IMAGE_RESOURCE_DIRECTORY - { - uint Characteristics; - uint TimeDateStamp; - ushort MajorVersion; - ushort MinorVersion; - ushort NumberOfNamedEntries; - ushort NumberOfIdEntries; - }; -//--- -struct IMAGE_RESOURCE_DIRECTORY_STRING - { - ushort Length; - char NameString[1]; - }; -//--- -struct IMAGE_RESOURCE_DIR_STRING_U - { - ushort Length; - short NameString[1]; - }; -//--- -struct IMAGE_RESOURCE_DATA_ENTRY - { - uint OffsetToData; - uint Size; - uint CodePage; - uint Reserved; - }; -//--- -struct IMAGE_LOAD_CONFIG_CODE_INTEGRITY - { - ushort Flags; - ushort Catalog; - uint CatalogOffset; - uint Reserved; - }; -//--- -struct IMAGE_DYNAMIC_RELOCATION_TABLE - { - uint Version; - uint Size; - }; -//--- -struct IMAGE_DYNAMIC_RELOCATION32 - { - uint Symbol; - uint BaseRelocSize; - }; -//--- -struct IMAGE_DYNAMIC_RELOCATION64 - { - ulong Symbol; - uint BaseRelocSize; - }; -//--- -struct IMAGE_DYNAMIC_RELOCATION32_V2 - { - uint HeaderSize; - uint FixupInfoSize; - uint Symbol; - uint SymbolGroup; - uint Flags; - }; -//--- -struct IMAGE_DYNAMIC_RELOCATION64_V2 - { - uint HeaderSize; - uint FixupInfoSize; - ulong Symbol; - uint SymbolGroup; - uint Flags; - }; -//--- -struct IMAGE_PROLOGUE_DYNAMIC_RELOCATION_HEADER - { - uchar PrologueByteCount; - }; -//--- -struct IMAGE_EPILOGUE_DYNAMIC_RELOCATION_HEADER - { - uint EpilogueCount; - uchar EpilogueByteCount; - uchar BranchDescriptorElementSize; - ushort BranchDescriptorCount; - }; -//--- -struct IMAGE_LOAD_CONFIG_DIRECTORY32 - { - uint Size; - uint TimeDateStamp; - ushort MajorVersion; - ushort MinorVersion; - uint GlobalFlagsClear; - uint GlobalFlagsSet; - uint CriticalSectionDefaultTimeout; - uint DeCommitFreeBlockThreshold; - uint DeCommitTotalFreeThreshold; - uint LockPrefixTable; - uint MaximumAllocationSize; - uint VirtualMemoryThreshold; - uint ProcessHeapFlags; - uint ProcessAffinityMask; - ushort CSDVersion; - ushort DependentLoadFlags; - uint EditList; - uint SecurityCookie; - uint SEHandlerTable; - uint SEHandlerCount; - uint GuardCFCheckFunctionPointer; - uint GuardCFDispatchFunctionPointer; - uint GuardCFFunctionTable; - uint GuardCFFunctionCount; - uint GuardFlags; - IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; - uint GuardAddressTakenIatEntryTable; - uint GuardAddressTakenIatEntryCount; - uint GuardLongJumpTargetTable; - uint GuardLongJumpTargetCount; - uint DynamicValueRelocTable; - uint CHPEMetadataPointer; - uint GuardRFFailureRoutine; - uint GuardRFFailureRoutineFunctionPointer; - uint DynamicValueRelocTableOffset; - ushort DynamicValueRelocTableSection; - ushort Reserved2; - uint GuardRFVerifyStackPointerFunctionPointer; - uint HotPatchTableOffset; - uint Reserved3; - uint EnclaveConfigurationPointer; - }; -//--- -struct IMAGE_LOAD_CONFIG_DIRECTORY64 - { - uint Size; - uint TimeDateStamp; - ushort MajorVersion; - ushort MinorVersion; - uint GlobalFlagsClear; - uint GlobalFlagsSet; - uint CriticalSectionDefaultTimeout; - ulong DeCommitFreeBlockThreshold; - ulong DeCommitTotalFreeThreshold; - ulong LockPrefixTable; - ulong MaximumAllocationSize; - ulong VirtualMemoryThreshold; - ulong ProcessAffinityMask; - uint ProcessHeapFlags; - ushort CSDVersion; - ushort DependentLoadFlags; - ulong EditList; - ulong SecurityCookie; - ulong SEHandlerTable; - ulong SEHandlerCount; - ulong GuardCFCheckFunctionPointer; - ulong GuardCFDispatchFunctionPointer; - ulong GuardCFFunctionTable; - ulong GuardCFFunctionCount; - uint GuardFlags; - IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; - ulong GuardAddressTakenIatEntryTable; - ulong GuardAddressTakenIatEntryCount; - ulong GuardLongJumpTargetTable; - ulong GuardLongJumpTargetCount; - ulong DynamicValueRelocTable; - ulong CHPEMetadataPointer; - ulong GuardRFFailureRoutine; - ulong GuardRFFailureRoutineFunctionPointer; - uint DynamicValueRelocTableOffset; - ushort DynamicValueRelocTableSection; - ushort Reserved2; - ulong GuardRFVerifyStackPointerFunctionPointer; - uint HotPatchTableOffset; - uint Reserved3; - ulong EnclaveConfigurationPointer; - }; -//--- -struct IMAGE_HOT_PATCH_INFO - { - uint Version; - uint Size; - uint SequenceNumber; - uint BaseImageList; - uint BaseImageCount; - uint BufferOffset; - }; -//--- -struct IMAGE_HOT_PATCH_BASE - { - uint SequenceNumber; - uint Flags; - uint OriginalTimeDateStamp; - uint OriginalCheckSum; - uint CodeIntegrityInfo; - uint CodeIntegritySize; - uint PatchTable; - uint BufferOffset; - }; -//--- -struct IMAGE_HOT_PATCH_HASHES - { - uchar SHA256[32]; - uchar SHA1[20]; - }; -//--- -struct IMAGE_CE_RUNTIME_FUNCTION_ENTRY - { - uint FuncStart; - uint Flags; - }; -//--- -struct IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY - { - ulong BeginAddress; - ulong EndAddress; - ulong ExceptionHandler; - ulong HandlerData; - ulong PrologEndAddress; - }; -//--- -struct IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY - { - uint BeginAddress; - uint EndAddress; - uint ExceptionHandler; - uint HandlerData; - uint PrologEndAddress; - }; -//--- -struct IMAGE_ENCLAVE_CONFIG32 - { - uint Size; - uint MinimumRequiredConfigSize; - uint PolicyFlags; - uint NumberOfImports; - uint ImportList; - uint ImportEntrySize; - uchar FamilyID[IMAGE_ENCLAVE_SHORT_ID_LENGTH]; - uchar ImageID[IMAGE_ENCLAVE_SHORT_ID_LENGTH]; - uint ImageVersion; - uint SecurityVersion; - uint EnclaveSize; - uint NumberOfThreads; - uint EnclaveFlags; - }; -//--- -struct IMAGE_ENCLAVE_CONFIG64 - { - uint Size; - uint MinimumRequiredConfigSize; - uint PolicyFlags; - uint NumberOfImports; - uint ImportList; - uint ImportEntrySize; - uchar FamilyID[IMAGE_ENCLAVE_SHORT_ID_LENGTH]; - uchar ImageID[IMAGE_ENCLAVE_SHORT_ID_LENGTH]; - uint ImageVersion; - uint SecurityVersion; - ulong EnclaveSize; - uint NumberOfThreads; - uint EnclaveFlags; - }; -//--- -struct IMAGE_ENCLAVE_IMPORT - { - uint MatchType; - uint MinimumSecurityVersion; - uchar UniqueOrAuthorID[IMAGE_ENCLAVE_LONG_ID_LENGTH]; - uchar FamilyID[IMAGE_ENCLAVE_SHORT_ID_LENGTH]; - uchar ImageID[IMAGE_ENCLAVE_SHORT_ID_LENGTH]; - uint ImportName; - uint Reserved; - }; -//--- -struct IMAGE_DEBUG_DIRECTORY - { - uint Characteristics; - uint TimeDateStamp; - ushort MajorVersion; - ushort MinorVersion; - uint Type; - uint SizeOfData; - uint AddressOfRawData; - uint PointerToRawData; - }; -//--- -struct IMAGE_COFF_SYMBOLS_HEADER - { - uint NumberOfSymbols; - uint LvaToFirstSymbol; - uint NumberOfLinenumbers; - uint LvaToFirstLinenumber; - uint RvaToFirstByteOfCode; - uint RvaToLastByteOfCode; - uint RvaToFirstByteOfData; - uint RvaToLastByteOfData; - }; -//--- -struct FPO_DATA - { - uint ulOffStart; - uint cbProcSize; - uint cdwLocals; - ushort cdwParams; - ushort data; - }; -//--- -struct IMAGE_DEBUG_MISC - { - uint DataType; - uint Length; - uchar Unicode; - uchar Reserved[3]; - uchar Data[1]; - }; -//--- -struct IMAGE_FUNCTION_ENTRY - { - uint StartingAddress; - uint EndingAddress; - uint EndOfPrologue; - }; -//--- -struct IMAGE_SEPARATE_DEBUG_HEADER - { - ushort Signature; - ushort Flags; - ushort Machine; - ushort Characteristics; - uint TimeDateStamp; - uint CheckSum; - uint ImageBase; - uint SizeOfImage; - uint NumberOfSections; - uint ExportedNamesSize; - uint DebugDirectorySize; - uint SectionAlignment; - uint Reserved[2]; - }; -//--- -struct NON_PAGED_DEBUG_INFO - { - ushort Signature; - ushort Flags; - uint Size; - ushort Machine; - ushort Characteristics; - uint TimeDateStamp; - uint CheckSum; - uint SizeOfImage; - ulong ImageBase; - }; -//--- -struct IMAGE_ARCHITECTURE_HEADER - { - int mask; - uint FirstEntryRVA; - }; -//--- -struct IMAGE_ARCHITECTURE_ENTRY - { - uint FixupInstRVA; - uint NewInst; - }; -//--- -struct SLIST_ENTRY - { - PVOID Next; - }; -//--- -struct RTL_BARRIER - { - uint Reserved1; - uint Reserved2; - ulong Reserved3[2]; - uint Reserved4; - uint Reserved5; - }; -//--- -struct MESSAGE_RESOURCE_ENTRY - { - ushort Length; - ushort Flags; - uchar Text[1]; - }; -//--- -struct MESSAGE_RESOURCE_BLOCK - { - uint LowId; - uint HighId; - uint OffsetToEntries; - }; -//--- -struct MESSAGE_RESOURCE_DATA - { - uint NumberOfBlocks; - MESSAGE_RESOURCE_BLOCK Blocks[1]; - }; -//--- -struct OSVERSIONINFOW - { - uint dwOSVersionInfoSize; - uint dwMajorVersion; - uint dwMinorVersion; - uint dwBuildNumber; - uint dwPlatformId; - ushort szCSDVersion[128]; - }; -//--- -struct OSVERSIONINFOEXW - { - uint dwOSVersionInfoSize; - uint dwMajorVersion; - uint dwMinorVersion; - uint dwBuildNumber; - uint dwPlatformId; - short szCSDVersion[128]; - ushort wServicePackMajor; - ushort wServicePackMinor; - ushort wSuiteMask; - uchar wProductType; - uchar wReserved; - }; -//--- -struct NV_MEMORY_RANGE - { - PVOID BaseAddress; - ulong Length; - }; -//--- -struct CORRELATION_VECTOR - { - char Version; - char Vector[RTL_CORRELATION_VECTOR_STRING_LENGTH]; - }; -//--- -struct CUSTOM_SYSTEM_EVENT_TRIGGER_CONFIG - { - uint Size; - const string TriggerId; - }; -//--- -struct IMAGE_POLICY_ENTRY - { - IMAGE_POLICY_ENTRY_TYPE Type; - IMAGE_POLICY_ID PolicyId; - PVOID Value; - }; -//--- -struct IMAGE_POLICY_METADATA - { - uchar Version; - uchar Reserved0[7]; - ulong ApplicationId; - IMAGE_POLICY_ENTRY Policies[]; - }; -//--- -struct RTL_CRITICAL_SECTION_DEBUG - { - ushort Type; - ushort CreatorBackTraceIndex; - PVOID CriticalSection; - LIST_ENTRY ProcessLocksList; - uint EntryCount; - uint ContentionCount; - uint Flags; - ushort CreatorBackTraceIndexHigh; - ushort Spareushort; - }; -//--- -struct RTL_CRITICAL_SECTION - { - PVOID DebugInfo; - int LockCount; - int RecursionCount; - HANDLE OwningThread; - HANDLE LockSemaphore; - ulong SpinCount; - }; -//--- -struct RTL_SRWLOCK - { - PVOID Ptr; - }; -//--- -struct RTL_CONDITION_VARIABLE - { - PVOID Ptr; - }; -//--- -struct HEAP_OPTIMIZE_RESOURCES_INFORMATION - { - uint Version; - uint Flags; - }; -//--- -struct ACTIVATION_CONTEXT_QUERY_INDEX - { - uint ulAssemblyIndex; - uint ulFileIndexInAssembly; - }; -//--- -struct ASSEMBLY_FILE_DETAILED_INFORMATION - { - uint ulFlags; - uint ulFilenameLength; - uint ulPathLength; - const string lpFileName; - const string lpFilePath; - }; -//--- -struct ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION - { - uint ulFlags; - uint ulEncodedAssemblyIdentityLength; - uint ulManifestPathType; - uint ulManifestPathLength; - long liManifestLastWriteTime; - uint ulPolicyPathType; - uint ulPolicyPathLength; - long liPolicyLastWriteTime; - uint ulMetadataSatelliteRosterIndex; - uint ulManifestVersionMajor; - uint ulManifestVersionMinor; - uint ulPolicyVersionMajor; - uint ulPolicyVersionMinor; - uint ulAssemblyDirectoryNameLength; - const string lpAssemblyEncodedAssemblyIdentity; - const string lpAssemblyManifestPath; - const string lpAssemblyPolicyPath; - const string lpAssemblyDirectoryName; - uint ulFileCount; - }; -//--- -struct ACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION - { - uint ulFlags; - ACTCTX_REQUESTED_RUN_LEVEL RunLevel; - uint UiAccess; - }; -//--- -struct COMPATIBILITY_CONTEXT_ELEMENT - { - GUID Id; - ACTCTX_COMPATIBILITY_ELEMENT_TYPE Type; - }; -//--- -struct ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION - { - uint ElementCount; - COMPATIBILITY_CONTEXT_ELEMENT Elements[]; - }; -//--- -struct SUPPORTED_OS_INFO - { - ushort MajorVersion; - ushort MinorVersion; - }; -//--- -struct ACTIVATION_CONTEXT_DETAILED_INFORMATION - { - uint dwFlags; - uint ulFormatVersion; - uint ulAssemblyCount; - uint ulRootManifestPathType; - uint ulRootManifestPathChars; - uint ulRootConfigurationPathType; - uint ulRootConfigurationPathChars; - uint ulAppDirPathType; - uint ulAppDirPathChars; - const string lpRootManifestPath; - const string lpRootConfigurationPath; - const string lpAppDirPath; - }; -//--- -struct HARDWARE_COUNTER_DATA - { - HARDWARE_COUNTER_TYPE Type; - uint Reserved; - ulong Value; - }; -//--- -struct PERFORMANCE_DATA - { - ushort Size; - uchar Version; - uchar HwCountersCount; - uint ContextSwitchCount; - ulong WaitReasonBitMap; - ulong CycleTime; - uint RetryCount; - uint Reserved; - HARDWARE_COUNTER_DATA HwCounters[MAX_HW_COUNTERS]; - }; -//--- -struct EVENTLOGRECORD - { - uint Length; - uint Reserved; - uint RecordNumber; - uint TimeGenerated; - uint TimeWritten; - uint EventID; - ushort EventType; - ushort NumStrings; - ushort EventCategory; - ushort ReservedFlags; - uint ClosingRecordNumber; - uint StringOffset; - uint UserSidLength; - uint UserSidOffset; - uint DataLength; - uint DataOffset; - }; -//--- -struct TAPE_ERASE - { - uint Type; - uchar Immediate; - }; -//--- -struct TAPE_PREPARE - { - uint Operation; - uchar Immediate; - }; -//--- -struct TAPE_WRITE_MARKS - { - uint Type; - uint Count; - uchar Immediate; - }; -//--- -struct TAPE_GET_POSITION - { - uint Type; - uint Partition; - long Offset; - }; -//--- -struct TAPE_SET_POSITION - { - uint Method; - uint Partition; - long Offset; - uchar Immediate; - }; -//--- -struct TAPE_GET_DRIVE_PARAMETERS - { - uchar ECC; - uchar Compression; - uchar DataPadding; - uchar ReportSetmarks; - uint DefaultBlockSize; - uint MaximumBlockSize; - uint MinimumBlockSize; - uint MaximumPartitionCount; - uint FeaturesLow; - uint FeaturesHigh; - uint EOTWarningZoneSize; - }; -//--- -struct TAPE_SET_DRIVE_PARAMETERS - { - uchar ECC; - uchar Compression; - uchar DataPadding; - uchar ReportSetmarks; - uint EOTWarningZoneSize; - }; -//--- -struct TAPE_GET_MEDIA_PARAMETERS - { - long Capacity; - long Remaining; - uint BlockSize; - uint PartitionCount; - uchar WriteProtected; - }; -//--- -struct TAPE_SET_MEDIA_PARAMETERS - { - uint BlockSize; - }; -//--- -struct TAPE_CREATE_PARTITION - { - uint Method; - uint Count; - uint Size; - }; -//--- -struct TAPE_WMI_OPERATIONS - { - uint Method; - uint DataBufferSize; - PVOID DataBuffer; - }; -//--- -struct TRANSACTION_BASIC_INFORMATION - { - GUID TransactionId; - uint State; - uint Outcome; - }; -//--- -struct TRANSACTIONMANAGER_BASIC_INFORMATION - { - GUID TmIdentity; - long VirtualClock; - }; -//--- -struct TRANSACTIONMANAGER_LOG_INFORMATION - { - GUID LogIdentity; - }; -//--- -struct TRANSACTIONMANAGER_LOGPATH_INFORMATION - { - uint LogPathLength; - short LogPath[1]; - }; -//--- -struct TRANSACTIONMANAGER_RECOVERY_INFORMATION - { - ulong LastRecoveredLsn; - }; -//--- -struct TRANSACTIONMANAGER_OLDEST_INFORMATION - { - GUID OldestTransactionGuid; - }; -//--- -struct TRANSACTION_PROPERTIES_INFORMATION - { - uint IsolationLevel; - uint IsolationFlags; - long Timeout; - uint Outcome; - uint DescriptionLength; - short Description[1]; - }; -//--- -struct TRANSACTION_BIND_INFORMATION - { - HANDLE TmHandle; - }; -//--- -struct TRANSACTION_ENLISTMENT_PAIR - { - GUID EnlistmentId; - GUID ResourceManagerId; - }; -//--- -struct TRANSACTION_ENLISTMENTS_INFORMATION - { - uint NumberOfEnlistments; - TRANSACTION_ENLISTMENT_PAIR EnlistmentPair[1]; - }; -//--- -struct TRANSACTION_SUPERIOR_ENLISTMENT_INFORMATION - { - TRANSACTION_ENLISTMENT_PAIR SuperiorEnlistmentPair; - }; -//--- -struct RESOURCEMANAGER_BASIC_INFORMATION - { - GUID ResourceManagerId; - uint DescriptionLength; - short Description[1]; - }; -//--- -struct RESOURCEMANAGER_COMPLETION_INFORMATION - { - HANDLE IoCompletionPortHandle; - ulong CompletionKey; - }; -//--- -struct ENLISTMENT_BASIC_INFORMATION - { - GUID EnlistmentId; - GUID TransactionId; - GUID ResourceManagerId; - }; -//--- -struct ENLISTMENT_CRM_INFORMATION - { - GUID CrmTransactionManagerId; - GUID CrmResourceManagerId; - GUID CrmEnlistmentId; - }; -//--- -struct TRANSACTION_LIST_ENTRY - { - GUID UOW; - }; -//--- -struct TRANSACTION_LIST_INFORMATION - { - uint NumberOfTransactions; - TRANSACTION_LIST_ENTRY TransactionInformation[1]; - }; -//--- -struct KTMOBJECT_CURSOR - { - GUID LastQuery; - uint ObjectIdCount; - GUID ObjectIds[1]; - }; -//--- -struct TP_POOL_STACK_INFORMATION - { - ulong StackReserve; - ulong StackCommit; - }; -//--- -struct TP_CALLBACK_ENVIRON_V3 - { - uint Version; - PVOID Pool; - PVOID CleanupGroup; - PVOID CleanupGroupCancelCallback; - PVOID RaceDll; - PVOID ActivationContext; - PVOID FinalizationCallback; - uint Flags; - TP_CALLBACK_PRIORITY CallbackPriority; - uint Size; - }; -//--- -struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION - { - ulong ProcessorMask; - LOGICAL_PROCESSOR_RELATIONSHIP Relationship; - uchar offset[4]; - ulong Reserved[2]; - }; -//--- -struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX - { - LOGICAL_PROCESSOR_RELATIONSHIP Relationship; - uint Size; - uchar info[72]; - }; -//--- -struct SYSTEM_CPU_SET_INFORMATION - { - uint Size; - CPU_SET_INFORMATION_TYPE Type; - uint Id; - ushort Group; - uchar LogicalProcessorIndex; - uchar CoreIndex; - uchar LastLevelCacheIndex; - uchar NumaNodeIndex; - uchar EfficiencyClass; - uchar AllFlags; - uint Reserved; - ulong AllocationTag; - }; -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -#import "kernel32.dll" -ushort RtlCaptureStackBackTrace(uint frames_to_skip,uint frames_to_capture,PVOID &back_trace[],uint &back_trace_hash); -ulong RtlCompareMemory(const uchar &source1[],const uchar &source2[],ulong length); -ulong VerSetConditionMask(ulong condition_mask,uint type_mask,uchar condition); -#import - -#import "Win32k.sys" -void RtlCaptureContext(PVOID context_record); -void RtlUnwind(PVOID target_frame,PVOID target_ip,EXCEPTION_RECORD &exception_record,PVOID return_value); -PVOID RtlLookupFunctionEntry(ulong control_pc,PVOID image_base,UNWIND_HISTORY_TABLE &history_table); -void RtlUnwindEx(PVOID target_frame,PVOID target_ip,EXCEPTION_RECORD &exception_record,PVOID return_value,PVOID context_record,UNWIND_HISTORY_TABLE &history_table); -PVOID RtlVirtualUnwind(uint handler_type,ulong image_base,ulong control_pc,PVOID function_entry,PVOID context_record,PVOID &handler_data,PVOID establisher_frame,KNONVOLATILE_CONTEXT_POINTERS &context_pointers); -PVOID RtlLookupFunctionEntry(ulong control_pc,uint &image_base,UNWIND_HISTORY_TABLE &history_table); -void RtlUnwindEx(PVOID target_frame,PVOID target_ip,EXCEPTION_RECORD &exception_record,PVOID return_value,PVOID context_record,UNWIND_HISTORY_TABLE &history_table); -PVOID RtlVirtualUnwind(uint handler_type,uint image_base,uint control_pc,PVOID function_entry,PVOID context_record,PVOID &handler_data,uint &establisher_frame,KNONVOLATILE_CONTEXT_POINTERS &context_pointers); -PVOID RtlLookupFunctionEntry(ulong control_pc,PVOID image_base,UNWIND_HISTORY_TABLE &history_table); -void RtlUnwindEx(PVOID target_frame,PVOID target_ip,EXCEPTION_RECORD &exception_record,PVOID return_value,PVOID context_record,UNWIND_HISTORY_TABLE &history_table); -PVOID RtlVirtualUnwind(uint handler_type,ulong image_base,ulong control_pc,PVOID function_entry,PVOID context_record,PVOID &handler_data,PVOID establisher_frame,KNONVOLATILE_CONTEXT_POINTERS &context_pointers); -void RtlUnwindEx(PVOID target_frame,PVOID target_ip,EXCEPTION_RECORD &exception_record,PVOID return_value,PVOID context_record,PVOID history_table); -PVOID RtlPcToFileHeader(PVOID pc_value,PVOID &base_of_image); -#import -//+------------------------------------------------------------------+ diff --git a/Include/WinAPI/winreg.mqh b/Include/WinAPI/winreg.mqh deleted file mode 100644 index 0e8b820..0000000 --- a/Include/WinAPI/winreg.mqh +++ /dev/null @@ -1,77 +0,0 @@ -//+------------------------------------------------------------------+ -//| winreg.mqh | -//| Copyright 2020, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include -#include - -//--- -struct VALENTW - { - PVOID ve_valuename; - uint ve_valuelen; - uchar offset1[4]; - PVOID ve_valueptr; - uint ve_type; - uchar offset2[4]; - }; -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -#import "advapi32.dll" -int AbortSystemShutdownW(string machine_name); -uint CheckForHiberboot(uchar &hiberboot,uchar clear_flag); -uint InitiateShutdownW(string machine_name,string message,uint grace_period,uint shutdown_flags,uint reason); -int InitiateSystemShutdownExW(string machine_name,string message,uint timeout,int force_apps_closed,int reboot_after_shutdown,uint reason); -int InitiateSystemShutdownW(string machine_name,string message,uint timeout,int force_apps_closed,int reboot_after_shutdown); -int RegCloseKey(HANDLE key); -int RegConnectRegistryExW(const string machine_name,HANDLE key,uint Flags,HANDLE &result); -int RegConnectRegistryW(const string machine_name,HANDLE key,HANDLE &result); -int RegCopyTreeW(HANDLE key_src,const string sub_key,HANDLE key_dest); -int RegCreateKeyExW(HANDLE key,const string sub_key,PVOID reserved,string class_name,uint options,uint desired,PVOID security_attributes,HANDLE &result,uint &disposition); -int RegCreateKeyTransactedW(HANDLE key,const string sub_key,PVOID reserved,string class_name,uint options,uint desired,PVOID security_attributes,HANDLE &result,uint &disposition,HANDLE transaction,PVOID extended_parameter); -int RegCreateKeyW(HANDLE key,const string sub_key,HANDLE &result); -int RegDeleteKeyExW(HANDLE key,const string sub_key,uint desired,PVOID reserved); -int RegDeleteKeyTransactedW(HANDLE key,const string sub_key,uint desired,PVOID reserved,HANDLE transaction,PVOID extended_parameter); -int RegDeleteKeyValueW(HANDLE key,const string sub_key,const string value_name); -int RegDeleteKeyW(HANDLE key,const string sub_key); -int RegDeleteTreeW(HANDLE key,const string sub_key); -int RegDeleteValueW(HANDLE key,const string value_name); -int RegDisablePredefinedCache(void); -int RegDisablePredefinedCacheEx(void); -int RegDisableReflectionKey(HANDLE base); -int RegEnableReflectionKey(HANDLE base); -int RegEnumKeyExW(HANDLE key,uint index,ushort &name[],uint &name_size,PVOID reserved,ushort &class_name[],uint &class_size,FILETIME &last_write_time); -int RegEnumKeyW(HANDLE key,uint index,ushort &name[],uint &name_size); -int RegEnumValueW(HANDLE key,uint index,ushort &value_name[],uint &value_name_size,PVOID reserved,uint &type,uchar &data[],uint &data_size); -int RegFlushKey(HANDLE key); -int RegGetKeySecurity(HANDLE key,uint SecurityInformation,SECURITY_DESCRIPTOR &security_descriptor,uint &security_descriptor_size); -int RegGetValueW(HANDLE key,const string sub_key,const string value,uint flags,uint &type,uchar &data[],uint &data_size); -int RegLoadAppKeyW(const string file,HANDLE &result,uint desired,uint options,PVOID reserved); -int RegLoadKeyW(HANDLE key,const string sub_key,const string file); -int RegLoadMUIStringW(HANDLE key,const string value,ushort &out_buf[],uint &out_buf_size,uint &data,uint flags,const string directory); -int RegNotifyChangeKeyValue(HANDLE key,int watch_subtree,uint notify_filter,HANDLE event,int asynchronous); -int RegOpenCurrentUser(uint desired,HANDLE &result); -int RegOpenKeyExW(HANDLE key,const string sub_key,uint options,uint desired,HANDLE &result); -int RegOpenKeyTransactedW(HANDLE key,const string sub_key,uint options,uint desired,HANDLE &result,HANDLE transaction,PVOID extended_paremeter); -int RegOpenKeyW(HANDLE key,const string sub_key,HANDLE &result); -int RegOpenUserClassesRoot(HANDLE token,uint options,uint desired,HANDLE &result); -int RegOverridePredefKey(HANDLE key,HANDLE new_key); -int RegQueryInfoKeyW(HANDLE key,string class_name,uint &class_size,PVOID reserved,uint &sub_keys,uint &max_sub_key_len,uint &max_class_len,uint &values,uint &max_value_name_len,uint &max_value_len,uint &security_descriptor,FILETIME &last_write_time); -int RegQueryMultipleValuesW(HANDLE key,VALENTW &val_list[],uint num_vals,ushort &value_buf[],uint &totsize); -int RegQueryReflectionKey(HANDLE base,int &is_reflection_disabled); -int RegQueryValueExW(HANDLE key,const string value_name,PVOID reserved,uint &type,uchar &data[],uint &data_size); -int RegQueryValueW(HANDLE key,const string sub_key,uchar &data[],uint &data_size); -int RegRenameKey(HANDLE key,const string sub_key_name,const string new_key_name); -int RegReplaceKeyW(HANDLE key,const string sub_key,const string new_file,const string old_file); -int RegRestoreKeyW(HANDLE key,const string file,uint flags); -int RegSaveKeyExW(HANDLE key,const string file,PVOID security_attributes,uint flags); -int RegSaveKeyW(HANDLE key,const string file,PVOID security_attributes); -int RegSetKeySecurity(HANDLE key,uint SecurityInformation,SECURITY_DESCRIPTOR &security_descriptor); -int RegSetKeyValueW(HANDLE key,const string sub_key,const string value_name,uint type,const uchar &data[],uint data); -int RegSetValueExW(HANDLE key,const string value_name,PVOID reserved,uint type,const uchar &data[],uint data_size); -int RegSetValueW(HANDLE key,const string sub_key,uint type,const ushort &data[],uint data_size); -int RegUnLoadKeyW(HANDLE key,const string sub_key); -#import -//+------------------------------------------------------------------+ \ No newline at end of file diff --git a/Include/WinAPI/winuser.mqh b/Include/WinAPI/winuser.mqh deleted file mode 100644 index f80c1ff..0000000 --- a/Include/WinAPI/winuser.mqh +++ /dev/null @@ -1,1825 +0,0 @@ -//+------------------------------------------------------------------+ -//| WinUser.mqh | -//| Copyright 2020, MetaQuotes Software Corp. | -//| https://www.mql5.com | -//+------------------------------------------------------------------+ -#include -#include - -//--- -#define POINTER_DEVICE_PRODUCT_STRING_MAX 520 -#define KL_NAMELENGTH 9 - -//--- -enum AR_STATE - { - AR_ENABLED=0x0, - AR_DISABLED=0x1, - AR_SUPPRESSED=0x2, - AR_REMOTESESSION=0x4, - AR_MULTIMON=0x8, - AR_NOSENSOR=0x10, - AR_NOT_SUPPORTED=0x20, - AR_DOCKED=0x40, - AR_LAPTOP=0x80 - }; -//--- -enum DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS - { - DCDC_DEFAULT=0x0000, - DCDC_DISABLE_FONT_UPDATE=0x0001, - DCDC_DISABLE_RELAYOUT=0x0002 - }; -//--- -enum DIALOG_DPI_CHANGE_BEHAVIORS - { - DDC_DEFAULT=0x0000, - DDC_DISABLE_ALL=0x0001, - DDC_DISABLE_RESIZE=0x0002, - DDC_DISABLE_CONTROL_RELAYOUT=0x0004 - }; -//--- -enum EDIT_CONTROL_FEATURE - { - EDIT_CONTROL_FEATURE_ENTERPRISE_DATA_PROTECTION_PASTE_SUPPORT=0, - EDIT_CONTROL_FEATURE_PASTE_NOTIFICATIONS=1 - }; -//--- -enum FEEDBACK_TYPE - { - FEEDBACK_TOUCH_CONTACTVISUALIZATION=1, - FEEDBACK_PEN_BARRELVISUALIZATION=2, - FEEDBACK_PEN_TAP=3, - FEEDBACK_PEN_DOUBLETAP=4, - FEEDBACK_PEN_PRESSANDHOLD=5, - FEEDBACK_PEN_RIGHTTAP=6, - FEEDBACK_TOUCH_TAP=7, - FEEDBACK_TOUCH_DOUBLETAP=8, - FEEDBACK_TOUCH_PRESSANDHOLD=9, - FEEDBACK_TOUCH_RIGHTTAP=10, - FEEDBACK_GESTURE_PRESSANDTAP=11, - FEEDBACK_MAX=0xFFFFFFFF - }; -//--- -enum HANDEDNESS - { - HANDEDNESS_LEFT=0, - HANDEDNESS_RIGHT - }; -//--- -enum INPUT_MESSAGE_DEVICE_TYPE - { - IMDT_UNAVAILABLE=0x00000000, - IMDT_KEYBOARD=0x00000001, - IMDT_MOUSE=0x00000002, - IMDT_TOUCH=0x00000004, - IMDT_PEN=0x00000008, - IMDT_TOUCHPAD=0x00000010 - }; -//--- -enum INPUT_MESSAGE_ORIGIN_ID - { - IMO_UNAVAILABLE=0x00000000, - IMO_HARDWARE=0x00000001, - IMO_INJECTED=0x00000002, - IMO_SYSTEM=0x00000004 - }; -//--- -enum ORIENTATION_PREFERENCE - { - ORIENTATION_PREFERENCE_NONE=0x0, - ORIENTATION_PREFERENCE_LANDSCAPE=0x1, - ORIENTATION_PREFERENCE_PORTRAIT=0x2, - ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED=0x4, - ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED=0x8 - }; -//--- -enum POINTER_BUTTON_CHANGE_TYPE - { - POINTER_CHANGE_NONE, - POINTER_CHANGE_FIRSTBUTTON_DOWN, - POINTER_CHANGE_FIRSTBUTTON_UP, - POINTER_CHANGE_SECONDBUTTON_DOWN, - POINTER_CHANGE_SECONDBUTTON_UP, - POINTER_CHANGE_THIRDBUTTON_DOWN, - POINTER_CHANGE_THIRDBUTTON_UP, - POINTER_CHANGE_FOURTHBUTTON_DOWN, - POINTER_CHANGE_FOURTHBUTTON_UP, - POINTER_CHANGE_FIFTHBUTTON_DOWN, - POINTER_CHANGE_FIFTHBUTTON_UP - }; -//--- -enum POINTER_DEVICE_CURSOR_TYPE - { - POINTER_DEVICE_CURSOR_TYPE_UNKNOWN=0x00000000, - POINTER_DEVICE_CURSOR_TYPE_TIP=0x00000001, - POINTER_DEVICE_CURSOR_TYPE_ERASER=0x00000002, - POINTER_DEVICE_CURSOR_TYPE_MAX=0xFFFFFFFF - }; -//--- -enum POINTER_DEVICE_TYPE - { - POINTER_DEVICE_TYPE_INTEGRATED_PEN=0x00000001, - POINTER_DEVICE_TYPE_EXTERNAL_PEN=0x00000002, - POINTER_DEVICE_TYPE_TOUCH=0x00000003, - POINTER_DEVICE_TYPE_TOUCH_PAD=0x00000004, - POINTER_DEVICE_TYPE_MAX=0xFFFFFFFF - }; -//--- -struct ACCEL - { - uchar fVirt; - ushort key; - ushort cmd; - }; -//--- -struct ACCESSTIMEOUT - { - uint cbSize; - uint dwFlags; - uint iTimeOutMSec; - }; -//--- -struct ALTTABINFO - { - uint cbSize; - int cItems; - int cColumns; - int cRows; - int iColFocus; - int iRowFocus; - int cxItem; - int cyItem; - POINT ptStart; - }; -//--- -struct ANIMATIONINFO - { - uint cbSize; - int iMinAnimate; - }; -//--- -struct AUDIODESCRIPTION - { - uint cbSize; - int Enabled; - uint Locale; - }; -//--- -struct BSMINFO - { - uint cbSize; - HANDLE hdesk; - HANDLE hwnd; - LUID luid; - }; -//--- -struct CBT_CREATEWNDA - { - HANDLE hwndInsertAfter; - }; -//--- -struct CBT_CREATEWNDW - { - HANDLE hwndInsertAfter; - }; -//--- -struct CBTACTIVATESTRUCT - { - int fMouse; - HANDLE hWndActive; - }; -//--- -struct CHANGEFILTERSTRUCT - { - uint cbSize; - uint ExtStatus; - }; -//--- -struct CLIENTCREATESTRUCT - { - HANDLE hWindowMenu; - uint idFirstChild; - }; -//--- -struct COMBOBOXINFO - { - uint cbSize; - RECT rcItem; - RECT rcButton; - uint stateButton; - HANDLE hwndCombo; - HANDLE hwndItem; - HANDLE hwndList; - }; -//--- -struct COMPAREITEMSTRUCT - { - uint CtlType; - uint CtlID; - HANDLE hwndItem; - uint itemID1; - ulong itemData1; - uint itemID2; - ulong itemData2; - uint dwLocaleId; - }; -//--- -struct COPYDATASTRUCT - { - ulong dwData; - uint cbData; - }; -//--- -struct CREATESTRUCTW pack(8) - { - PVOID lpCreateParams; - HANDLE hInstance; - HANDLE hMenu; - HANDLE hwndParent; - int cy; - int cx; - int y; - int x; - int style; - PVOID lpszName; - PVOID lpszClass; - uint dwExStyle; - }; -//--- -struct CURSORINFO - { - uint cbSize; - uint flags; - HANDLE hCursor; - POINT ptScreenPos; - }; -//--- -struct CURSORSHAPE - { - int xHotSpot; - int yHotSpot; - int cx; - int cy; - int cbWidth; - uchar Planes; - uchar BitsPixel; - }; -//--- -struct CWPRETSTRUCT - { - PVOID lResult; - PVOID lParam; - PVOID wParam; - uint message; - HANDLE hwnd; - }; -//--- -struct CWPSTRUCT - { - PVOID lParam; - PVOID wParam; - uint message; - HANDLE hwnd; - }; -//--- -struct DEBUGHOOKINFO - { - uint idThread; - uint idThreadInstaller; - PVOID lParam; - PVOID wParam; - int code; - }; -//--- -struct DELETEITEMSTRUCT - { - uint CtlType; - uint CtlID; - uint itemID; - HANDLE hwndItem; - ulong itemData; - }; -//--- -struct DLGITEMTEMPLATE - { - uint style; - uint dwExtendedStyle; - short x; - short y; - short cx; - short cy; - ushort id; - }; -//--- -struct DLGTEMPLATE - { - uint style; - uint dwExtendedStyle; - ushort cdit; - short x; - short y; - short cx; - short cy; - }; -//--- -struct DRAWITEMSTRUCT - { - uint CtlType; - uint CtlID; - uint itemID; - uint itemAction; - uint itemState; - HANDLE hwndItem; - HANDLE hDC; - RECT rcItem; - ulong itemData; - }; -//--- -struct DRAWTEXTPARAMS - { - uint cbSize; - int iTabLength; - int iLeftMargin; - int iRightMargin; - uint uiLengthDrawn; - }; -//--- -struct DROPSTRUCT - { - HANDLE hwndSource; - HANDLE hwndSink; - uint wFmt; - ulong dwData; - POINT ptDrop; - uint dwControlData; - }; -//--- -struct EVENTMSG - { - uint message; - uint paramL; - uint paramH; - uint time; - HANDLE hwnd; - }; -//--- -struct FILTERKEYS - { - uint cbSize; - uint dwFlags; - uint iWaitMSec; - uint iDelayMSec; - uint iRepeatMSec; - uint iBounceMSec; - }; -//--- -struct FLASHWINFO - { - uint cbSize; - HANDLE hwnd; - uint dwFlags; - uint uCount; - uint dwTimeout; - }; -//--- -struct GESTURECONFIG - { - uint dwID; - uint dwWant; - uint dwBlock; - }; -//--- -struct GESTUREINFO - { - uint cbSize; - uint dwFlags; - uint dwID; - HANDLE hwndTarget; - POINTS ptsLocation; - uint dwInstanceID; - uint dwSequenceID; - ulong ullArguments; - uint cbExtraArgs; - }; -//--- -struct GESTURENOTIFYSTRUCT - { - uint cbSize; - uint dwFlags; - HANDLE hwndTarget; - POINTS ptsLocation; - uint dwInstanceID; - }; -//--- -struct GUITHREADINFO - { - uint cbSize; - uint flags; - HANDLE hwndActive; - HANDLE hwndFocus; - HANDLE hwndCapture; - HANDLE hwndMenuOwner; - HANDLE hwndMoveSize; - HANDLE hwndCaret; - RECT rcCaret; - }; -//--- -struct HARDWAREHOOKSTRUCT - { - HANDLE hwnd; - uint message; - PVOID wParam; - PVOID lParam; - }; -//--- -struct HARDWAREINPUT - { - uint uMsg; - ushort wParamL; - ushort wParamH; - }; -//--- -struct HELPINFO - { - uint cbSize; - int iContextType; - int iCtrlId; - HANDLE hItemHandle; - uint dwContextId; - POINT MousePos; - }; -//--- -struct HELPWININFOA - { - int wStructSize; - int x; - int y; - int dx; - int dy; - int wMax; - char rgchMember[2]; - }; -//--- -struct HELPWININFOW - { - int wStructSize; - int x; - int y; - int dx; - int dy; - int wMax; - short rgchMember[2]; - }; -//--- -struct HIGHCONTRASTW - { - uint cbSize; - uint dwFlags; - string lpszDefaultScheme; - }; -//--- -struct ICONINFO - { - int fIcon; - uint xHotspot; - uint yHotspot; - HANDLE hbmMask; - HANDLE hbmColor; - }; -//--- -struct ICONINFOEXW - { - uint cbSize; - int fIcon; - uint xHotspot; - uint yHotspot; - HANDLE hbmMask; - HANDLE hbmColor; - ushort wResID; - short szModName[MAX_PATH]; - short szResName[MAX_PATH]; - }; -//--- -struct ICONMETRICSW - { - uint cbSize; - int iHorzSpacing; - int iVertSpacing; - int iTitleWrap; - LOGFONTW lfFont; - }; -//--- -struct INPUT_INJECTION_VALUE - { - ushort page; - ushort usage; - int value; - ushort index; - }; -//--- -struct INPUT_MESSAGE_SOURCE - { - INPUT_MESSAGE_DEVICE_TYPE deviceType; - INPUT_MESSAGE_ORIGIN_ID originId; - }; -//--- -struct KBDLLHOOKSTRUCT - { - uint vkCode; - uint scanCode; - uint flags; - uint time; - ulong dwExtraInfo; - }; -//--- -struct KEYBDINPUT - { - ushort wVk; - ushort wScan; - uint dwFlags; - uint time; - ulong dwExtraInfo; - }; -//--- -struct LASTINPUTINFO - { - uint cbSize; - uint dwTime; - }; -//--- -struct MDICREATESTRUCTW - { - PVOID szClass; - PVOID szTitle; - HANDLE hOwner; - int x; - int y; - int cx; - int cy; - uint style; - PVOID lParam; - }; -//--- -struct MDINEXTMENU - { - HANDLE hmenuIn; - HANDLE hmenuNext; - HANDLE hwndNext; - }; -//--- -struct MEASUREITEMSTRUCT - { - uint CtlType; - uint CtlID; - uint itemID; - uint itemWidth; - uint itemHeight; - ulong itemData; - }; -//--- -struct MENUBARINFO - { - uint cbSize; - RECT rcBar; - HANDLE hMenu; - HANDLE hwndMenu; - int Focused; - }; -//--- -struct MENUGETOBJECTINFO - { - uint dwFlags; - uint uPos; - HANDLE hmenu; - PVOID riid; - PVOID pvObj; - }; -//--- -struct MENUINFO - { - uint cbSize; - uint fMask; - uint dwStyle; - uint cyMax; - HANDLE hbrBack; - uint dwContextHelpID; - ulong dwMenuData; - }; -//--- -struct MENUITEMINFOW - { - uint cbSize; - uint fMask; - uint fType; - uint fState; - uint wID; - HANDLE hSubMenu; - HANDLE hbmpChecked; - HANDLE hbmpUnchecked; - ulong dwItemData; - string dwTypeData; - uint cch; - HANDLE hbmpItem; - }; -//--- -struct MENUITEMTEMPLATE - { - ushort mtOption; - ushort mtID; - short mtString[1]; - }; -//--- -struct MENUITEMTEMPLATEHEADER - { - ushort versionNumber; - ushort offset; - }; -//--- -struct MINIMIZEDMETRICS - { - uint cbSize; - int iWidth; - int iHorzGap; - int iVertGap; - int iArrange; - }; -//--- -struct MINMAXINFO - { - POINT ptReserved; - POINT ptMaxSize; - POINT ptMaxPosition; - POINT ptMinTrackSize; - POINT ptMaxTrackSize; - }; -//--- -struct MONITORINFO - { - uint cbSize; - RECT rcMonitor; - RECT rcWork; - uint dwFlags; - }; -//--- -struct MOUSEHOOKSTRUCT - { - POINT pt; - HANDLE hwnd; - uint wHitTestCode; - ulong dwExtraInfo; - }; -//--- -struct MOUSEHOOKSTRUCTEX: public MONITORINFO - { - uint mouseData; - }; -//--- -struct MOUSEINPUT pack(8) - { - int dx; - int dy; - uint mouseData; - uint dwFlags; - uint time; - ulong dwExtraInfo; - }; -//--- -struct MOUSEKEYS - { - uint cbSize; - uint dwFlags; - uint iMaxSpeed; - uint iTimeToMaxSpeed; - uint iCtrlSpeed; - uint dwReserved1; - uint dwReserved2; - }; -//--- -struct MOUSEMOVEPOINT - { - int x; - int y; - uint time; - ulong dwExtraInfo; - }; -//--- -struct MSG - { - HANDLE hwnd; - uint message; - PVOID wParam; - PVOID lParam; - uint time; - POINT pt; - uint lPrivate; - }; -//--- -struct MSGBOXPARAMSW - { - uint cbSize; - HANDLE hwndOwner; - HANDLE hInstance; - PVOID lpszText; - PVOID lpszCaption; - uint dwStyle; - PVOID lpszIcon; - uint dwContextHelpId; - PVOID lpfnMsgBoxCallback; - uint dwLanguageId; - }; -//--- -struct MSLLHOOKSTRUCT - { - POINT pt; - uint mouseData; - uint flags; - uint time; - ulong dwExtraInfo; - }; -//--- -struct MULTIKEYHELPW - { - short mkKeylist; - short szKeyphrase[1]; - }; -//--- -struct NCCALCSIZE_PARAMS - { - RECT rgrc[3]; - PVOID lppos; - }; -//--- -struct NMHDR - { - HANDLE hwndFrom; - ulong idFrom; - uint code; - }; -//--- -struct NONCLIENTMETRICSW - { - uint cbSize; - int iBorderWidth; - int iScrollWidth; - int iScrollHeight; - int iCaptionWidth; - int iCaptionHeight; - LOGFONTW lfCaptionFont; - int iSmCaptionWidth; - int iSmCaptionHeight; - LOGFONTW lfSmCaptionFont; - int iMenuWidth; - int iMenuHeight; - LOGFONTW lfMenuFont; - LOGFONTW lfStatusFont; - LOGFONTW lfMessageFont; - int iPaddedBorderWidth; - }; -//--- -struct PAINTSTRUCT - { - HANDLE hdc; - int fErase; - RECT rcPaint; - int fRestore; - int fIncUpdate; - uchar rgbReserved[32]; - }; -//--- -struct POINTER_DEVICE_CURSOR_INFO - { - uint cursorId; - POINTER_DEVICE_CURSOR_TYPE cursor; - }; -//--- -struct POINTER_DEVICE_INFO pack(8) - { - uint displayOrientation; - HANDLE device; - POINTER_DEVICE_TYPE pointerDeviceType; - HANDLE monitor; - uint startingCursorId; - ushort maxActiveContacts; - short productString[POINTER_DEVICE_PRODUCT_STRING_MAX]; - }; -//--- -struct POINTER_DEVICE_PROPERTY - { - int logicalMin; - int logicalMax; - int physicalMin; - int physicalMax; - uint unit; - uint unitExponent; - ushort usagePageId; - ushort usageId; - }; -//--- -struct POINTER_INFO - { - uint pointerType; - uint pointerId; - uint frameId; - uint pointerFlags; - HANDLE sourceDevice; - HANDLE hwndTarget; - POINT ptPixelLocation; - POINT ptHimetricLocation; - POINT ptPixelLocationRaw; - POINT ptHimetricLocationRaw; - uint dwTime; - uint historyCount; - int InputData; - uint dwKeyStates; - ulong PerformanceCount; - POINTER_BUTTON_CHANGE_TYPE ButtonChangeType; - }; -//--- -struct POINTER_PEN_INFO - { - POINTER_INFO pointerInfo; - uint penFlags; - uint penMask; - uint pressure; - uint rotation; - int tiltX; - int tiltY; - }; -//--- -struct POINTER_TOUCH_INFO - { - POINTER_INFO pointerInfo; - uint touchFlags; - uint touchMask; - RECT rcContact; - RECT rcContactRaw; - uint orientation; - uint pressure; - }; -//--- -struct POWERBROADCAST_SETTING - { - GUID PowerSetting; - uint DataLength; - uchar Data[1]; - }; -//--- -struct RAWINPUTDEVICE - { - ushort usUsagePage; - ushort usUsage; - uint dwFlags; - HANDLE hwndTarget; - }; -//--- -struct RAWINPUTDEVICELIST - { - HANDLE hDevice; - uint dwType; - }; -//--- -struct RAWINPUTHEADER - { - uint dwType; - uint dwSize; - HANDLE hDevice; - PVOID wParam; - }; -//--- -struct RID_DEVICE_INFO_HID - { - uint dwVendorId; - uint dwProductId; - uint dwVersionNumber; - ushort usUsagePage; - ushort usUsage; - }; -//--- -struct RID_DEVICE_INFO_KEYBOARD - { - uint dwType; - uint dwSubType; - uint dwKeyboardMode; - uint dwNumberOfFunctionKeys; - uint dwNumberOfIndicators; - uint dwNumberOfKeysTotal; - }; -//--- -struct RID_DEVICE_INFO_MOUSE - { - uint dwId; - uint dwNumberOfButtons; - uint dwSampleRate; - int fHasHorizontalWheel; - }; -//--- -struct SCROLLBARINFO - { - uint cbSize; - RECT rcScrollBar; - int dxyLineButton; - int xyThumbTop; - int xyThumbBottom; - int reserved; - }; -//--- -struct SCROLLINFO - { - uint cbSize; - uint fMask; - int nMin; - int nMax; - uint nPage; - int nPos; - int nTrackPos; - }; -//--- -struct SERIALKEYSW - { - uint cbSize; - uint dwFlags; - string lpszActivePort; - string lpszPort; - uint iBaudRate; - uint iPortState; - uint iActive; - }; -//--- -struct SHELLHOOKINFO - { - HANDLE hwnd; - RECT rc; - }; -//--- -struct SOUNDSENTRYW - { - uint cbSize; - uint dwFlags; - uint iFSTextEffect; - uint iFSTextEffectMSec; - uint iFSTextEffectColorBits; - uint iFSGrafEffect; - uint iFSGrafEffectMSec; - uint iFSGrafEffectColor; - uint iWindowsEffect; - uint iWindowsEffectMSec; - string lpszWindowsEffectDLL; - uint iWindowsEffectOrdinal; - }; -//--- -struct STICKYKEYS - { - uint cbSize; - uint dwFlags; - }; -//--- -struct STYLESTRUCT - { - uint styleOld; - uint styleNew; - }; -//--- -struct TITLEBARINFO - { - uint cbSize; - RECT rcTitleBar; - }; -//--- -struct TITLEBARINFOEX - { - uint cbSize; - RECT rcTitleBar; - }; -//--- -struct TOGGLEKEYS - { - uint cbSize; - uint dwFlags; - }; -//--- -struct TOUCH_HIT_TESTING_INPUT - { - uint pointerId; - POINT point; - RECT boundingBox; - RECT nonOccludedBoundingBox; - uint orientation; - }; -//--- -struct TOUCH_HIT_TESTING_PROXIMITY_EVALUATION - { - ushort score; - POINT adjustedPoint; - }; -//--- -struct TOUCHINPUT - { - int x; - int y; - HANDLE hSource; - uint dwID; - uint dwFlags; - uint dwMask; - uint dwTime; - ulong dwExtraInfo; - uint cxContact; - uint cyContact; - }; -//--- -struct TOUCHPREDICTIONPARAMETERS - { - uint cbSize; - uint dwLatency; - uint dwSampleTime; - uint bUseHWTimeStamp; - }; -//--- -struct TPMPARAMS - { - uint cbSize; - RECT rcExclude; - }; -//--- -struct TRACKMOUSEEVENT - { - uint cbSize; - uint dwFlags; - HANDLE hwndTrack; - uint dwHoverTime; - }; -//--- -struct UPDATELAYEREDWINDOWINFO - { - uint cbSize; - HANDLE hdcDst; - HANDLE hdcSrc; - uint crKey; - uint dwFlags; - }; -//--- -struct USAGE_PROPERTIES - { - ushort level; - ushort page; - ushort usage; - int logicalMinimum; - int logicalMaximum; - ushort unit; - ushort exponent; - uchar count; - int physicalMinimum; - int physicalMaximum; - }; -//--- -struct USEROBJECTFLAGS - { - int fInherit; - int fReserved; - uint dwFlags; - }; -//--- -struct WINDOWINFO - { - uint cbSize; - RECT rcWindow; - RECT rcClient; - uint dwStyle; - uint dwExStyle; - uint dwWindowStatus; - uint cxWindowBorders; - uint cyWindowBorders; - ushort atomWindowType; - ushort wCreatorVersion; - }; -//--- -struct WINDOWPLACEMENT - { - uint length; - uint flags; - uint showCmd; - POINT ptMinPosition; - POINT ptMaxPosition; - RECT rcNormalPosition; - RECT rcDevice; - }; -//--- -struct WINDOWPOS - { - HANDLE hwnd; - HANDLE hwndInsertAfter; - int x; - int y; - int cx; - int cy; - uint flags; - }; -//--- -struct WNDCLASSEXW pack(8) - { - uint cbSize; - uint style; - PVOID lpfnWndProc; - int cbClsExtra; - int cbWndExtra; - HANDLE hInstance; - HANDLE hIcon; - HANDLE hCursor; - HANDLE hbrBackground; - PVOID lpszMenuName; - PVOID lpszClassName; - HANDLE hIconSm; - }; -//--- -struct WNDCLASSW pack(8) - { - uint style; - PVOID lpfnWndProc; - int cbClsExtra; - int cbWndExtra; - HANDLE hInstance; - HANDLE hIcon; - HANDLE hCursor; - HANDLE hbrBackground; - PVOID lpszMenuName; - PVOID lpszClassName; - }; -//--- -struct WTSSESSION_NOTIFICATION - { - uint cbSize; - uint dwSessionId; - }; -//--- -struct RAWMOUSE pack(4) - { - ushort usFlags; - uint ulButtons; - uint ulRawButtons; - int lLastX; - int lLastY; - uint ulExtraInformation; - }; -//--- -struct RAWKEYBOARD - { - ushort MakeCode; - ushort Flags; - ushort Reserved; - ushort VKey; - uint Message; - uint ExtraInformation; - }; -//--- -struct RAWHID - { - uint dwSizeHid; - uint dwCount; - uchar bRawData[1]; - }; -//--- -union RAWFORMAT - { - RAWMOUSE mouse; - RAWKEYBOARD keyboard; - RAWHID hid; - }; -//--- -struct RAWINPUT - { - RAWINPUTHEADER header; - RAWFORMAT data; - }; -//--- -struct INPUT_TRANSFORM - { - float _11; - float _12; - float _13; - float _14; - float _21; - float _22; - float _23; - float _24; - float _31; - float _32; - float _33; - float _34; - float _41; - float _42; - float _43; - float _44; - }; -//--- -struct MENUITEMINFO - { - uint cbSize; - uint fMask; - uint fType; - uint fState; - uint wID; - HANDLE hSubMenu; - HANDLE hbmpChecked; - HANDLE hbmpUnchecked; - uint dwItemData; - string dwTypeData; - uint cch; - }; -//--- -union INPUT_TYPE - { - MOUSEINPUT mi; - KEYBDINPUT ki; - HARDWAREINPUT hi; - }; -//--- -struct INPUT - { - uint type; - INPUT_TYPE in; - }; -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -#import "user32.dll" -HANDLE ActivateKeyboardLayout(HANDLE hkl,uint Flags); -int AddClipboardFormatListener(HANDLE hwnd); -int AdjustWindowRect(RECT &rect,uint style,int menu); -int AdjustWindowRectEx(RECT &rect,uint style,int menu,uint ex_style); -int AdjustWindowRectExForDpi(RECT &rect,uint style,int menu,uint ex_style,uint dpi); -int AllowSetForegroundWindow(uint process_id); -int AnimateWindow(HANDLE wnd,uint time,uint flags); -int AnyPopup(void); -int AppendMenuW(HANDLE menu,uint flags,ulong uIDNewItem,const string new_item); -int AreDpiAwarenessContextsEqual(HANDLE dpiContextA,HANDLE dpiContextB); -uint ArrangeIconicWindows(HANDLE wnd); -int AttachThreadInput(uint attach,uint attach_to,int attach); -HANDLE BeginDeferWindowPos(int num_windows); -HANDLE BeginPaint(HANDLE wnd,PAINTSTRUCT &paint); -int BlockInput(int block_it); -int BringWindowToTop(HANDLE wnd); -int BroadcastSystemMessage(uint flags,uint &info,uint Msg,PVOID param,PVOID param); -int BroadcastSystemMessageExW(uint flags,uint &info,uint Msg,PVOID param,PVOID param,BSMINFO &info); -int BroadcastSystemMessageW(uint flags,uint &info,uint Msg,PVOID param,PVOID param); -int CalculatePopupWindowPosition(const POINT &point,const SIZE &size,uint flags,RECT &rect,RECT &window_position); -int CallMsgFilterW(MSG &msg,int code); -PVOID CallNextHookEx(HANDLE hhk,int code,PVOID param,PVOID param); -PVOID CallWindowProcW(PVOID prev_wnd_func,HANDLE wnd,uint Msg,PVOID param,PVOID param); -int CancelShutdown(void); -ushort CascadeWindows(HANDLE parent,uint how,const RECT &rect,uint kids,const HANDLE &kids[]); -int ChangeClipboardChain(HANDLE wnd_remove,HANDLE wnd_new_next); -int ChangeDisplaySettingsExW(const string device_name,DEVMODEW &dev_mode,HANDLE hwnd,uint dwflags,PVOID param); -int ChangeDisplaySettingsW(DEVMODEW &dev_mode,uint flags); -int ChangeMenuW(HANDLE menu,uint cmd,const string new_item,uint insert,uint flags); -int ChangeWindowMessageFilter(uint message,uint flag); -int ChangeWindowMessageFilterEx(HANDLE hwnd,uint message,uint action,CHANGEFILTERSTRUCT &change_filter_struct); -uint CharLowerBuffW(string &lpsz,uint length); -PVOID CharLowerW(string &lpsz); -PVOID CharNextW(PVOID lpsz); -PVOID CharNextW(string lpsz); -PVOID CharPrevW(const PVOID start,const PVOID current); -PVOID CharPrevW(const string start,const string current); -int CharToOemBuffW(const string src,char &dst[],uint dst_length); -int CharToOemW(const string src,char &dst[]); -uint CharUpperBuffW(string &lpsz,uint length); -PVOID CharUpperW(string &lpsz); -int CheckDlgButton(HANDLE dlg,int nIDButton,uint check); -uint CheckMenuItem(HANDLE menu,uint uIDCheckItem,uint check); -int CheckMenuRadioItem(HANDLE hmenu,uint first,uint last,uint check,uint flags); -int CheckRadioButton(HANDLE dlg,int nIDFirstButton,int nIDLastButton,int nIDCheckButton); -HANDLE ChildWindowFromPoint(HANDLE wnd_parent,POINT &point); -HANDLE ChildWindowFromPointEx(HANDLE hwnd,POINT &pt,uint flags); -int ClientToScreen(HANDLE wnd,POINT &point); -int ClipCursor(RECT &rect); -int CloseClipboard(void); -int CloseDesktop(HANDLE desktop); -int CloseGestureInfoHandle(HANDLE gesture_info); -int CloseTouchInputHandle(HANDLE touch_input); -int CloseWindow(HANDLE wnd); -int CloseWindowStation(HANDLE win_sta); -int CopyAcceleratorTableW(HANDLE accel_src,ACCEL &accel_dst,int accel_entries); -HANDLE CopyIcon(HANDLE icon); -HANDLE CopyImage(HANDLE h,uint type,int cx,int cy,uint flags); -int CopyRect(RECT &dst,RECT &src); -int CountClipboardFormats(void); -HANDLE CreateAcceleratorTableW(ACCEL &paccel,int accel); -int CreateCaret(HANDLE wnd,HANDLE bitmap,int width,int height); -HANDLE CreateCursor(HANDLE inst,int hot_spot,int hot_spot,int width,int height,PVOID pvANDPlane,PVOID pvXORPlane); -HANDLE CreateDesktopExW(const string desktop,const PVOID device,PVOID devmode,uint flags,uint desired_access,PVOID lpsa,uint heap_size,PVOID pvoid); -HANDLE CreateDesktopExW(const string desktop,const string device,PVOID devmode,uint flags,uint desired_access,PVOID lpsa,uint heap_size,PVOID pvoid); -HANDLE CreateDesktopExW(const string desktop,const PVOID device,DEVMODEW &devmode,uint flags,uint desired_access,PVOID lpsa,uint heap_size,PVOID pvoid); -HANDLE CreateDesktopExW(const string desktop,const string device,DEVMODEW &devmode,uint flags,uint desired_access,PVOID lpsa,uint heap_size,PVOID pvoid); -HANDLE CreateDesktopW(const string desktop,const PVOID device,PVOID devmode,uint flags,uint desired_access,PVOID lpsa); -HANDLE CreateDesktopW(const string desktop,const string device,PVOID devmode,uint flags,uint desired_access,PVOID lpsa); -HANDLE CreateDesktopW(const string desktop,const PVOID device,DEVMODEW &devmode,uint flags,uint desired_access,PVOID lpsa); -HANDLE CreateDesktopW(const string desktop,const string device,DEVMODEW &devmode,uint flags,uint desired_access,PVOID lpsa); -HANDLE CreateDialogIndirectParamW(HANDLE instance,const DLGTEMPLATE &dlg_template,HANDLE wnd_parent,PVOID dialog_func,PVOID init_param); -HANDLE CreateDialogParamW(HANDLE instance,const string template_name,HANDLE wnd_parent,PVOID dialog_func,PVOID init_param); -HANDLE CreateIcon(HANDLE instance,int width,int height,uchar planes,uchar bits_pixel,const uchar &lpbANDbits[],const uchar &lpbXORbits[]); -HANDLE CreateIconFromResource(uchar &presbits,uint res_size,int icon,uint ver); -HANDLE CreateIconFromResourceEx(uchar &presbits,uint res_size,int icon,uint ver,int desired,int desired,uint Flags); -HANDLE CreateIconIndirect(ICONINFO &piconinfo); -HANDLE CreateMDIWindowW(const string class_name,const string window_name,uint style,int X,int Y,int width,int height,HANDLE wnd_parent,HANDLE instance,PVOID param); -HANDLE CreateMenu(void); -HANDLE CreatePopupMenu(void); -HANDLE CreateWindowExW(uint ex_style,const PVOID class_name,const PVOID window_name,uint style,int X,int Y,int width,int height,HANDLE wnd_parent,HANDLE menu,HANDLE instance,PVOID param); -HANDLE CreateWindowExW(uint ex_style,const string class_name,const string window_name,uint style,int X,int Y,int width,int height,HANDLE wnd_parent,HANDLE menu,HANDLE instance,PVOID param); -HANDLE CreateWindowStationW(const string lpwinsta,uint flags,uint desired_access,PVOID lpsa); -PVOID DefDlgProcW(HANDLE dlg,uint Msg,PVOID param,PVOID param); -HANDLE DeferWindowPos(HANDLE win_pos_info,HANDLE wnd,HANDLE wnd_insert_after,int x,int y,int cx,int cy,uint flags); -PVOID DefFrameProcW(HANDLE wnd,HANDLE hWndMDIClient,uint msg,PVOID param,PVOID param); -PVOID DefMDIChildProcW(HANDLE wnd,uint msg,PVOID param,PVOID param); -PVOID DefRawInputProc(RAWINPUT &raw_input[],int inp,uint size_header); -PVOID DefWindowProcW(HANDLE wnd,uint Msg,PVOID param,PVOID param); -int DeleteMenu(HANDLE menu,uint position,uint flags); -int DeregisterShellHookWindow(HANDLE hwnd); -int DestroyAcceleratorTable(HANDLE accel); -int DestroyCaret(void); -int DestroyCursor(HANDLE cursor); -int DestroyIcon(HANDLE icon); -int DestroyMenu(HANDLE menu); -int DestroyWindow(HANDLE wnd); -long DialogBoxIndirectParamW(HANDLE instance,DLGTEMPLATE &dialog_template,HANDLE wnd_parent,PVOID dialog_func,PVOID init_param); -long DialogBoxParamW(HANDLE instance,const string template_name,HANDLE wnd_parent,PVOID dialog_func,PVOID init_param); -void DisableProcessWindowsGhosting(void); -PVOID DispatchMessageW(MSG &msg); -int DisplayConfigGetDeviceInfo(DISPLAYCONFIG_DEVICE_INFO_HEADER &packet); -int DisplayConfigSetDeviceInfo(DISPLAYCONFIG_DEVICE_INFO_HEADER &packet); -int DlgDirListComboBoxW(HANDLE dlg,string path_spec,int nIDComboBox,int nIDStaticPath,uint filetype); -int DlgDirListW(HANDLE dlg,string path_spec,int nIDListBox,int nIDStaticPath,uint file_type); -int DlgDirSelectComboBoxExW(HANDLE dlg,string str,int out,int combo_box); -int DlgDirSelectExW(HANDLE dlg,string str,int count,int list_box); -int DragDetect(HANDLE hwnd,POINT &pt); -uint DragObject(HANDLE parent,HANDLE from,uint fmt,ulong data,HANDLE hcur); -int DrawAnimatedRects(HANDLE hwnd,int ani,RECT &from,RECT &to); -int DrawCaption(HANDLE hwnd,HANDLE hdc,RECT &lprect,uint flags); -int DrawEdge(HANDLE hdc,RECT &qrc,uint edge,uint flags); -int DrawFocusRect(HANDLE hDC,RECT &lprc); -int DrawFrameControl(HANDLE,RECT &,uint,uint); -int DrawIcon(HANDLE hDC,int X,int Y,HANDLE icon); -int DrawIconEx(HANDLE hdc,int left,int top,HANDLE icon,int width,int width,uint if_ani_cur,HANDLE flicker_free_draw,uint flags); -int DrawMenuBar(HANDLE wnd); -int DrawStateW(HANDLE hdc,HANDLE fore,PVOID call_back,PVOID data,PVOID data,int x,int y,int cx,int cy,uint flags); -int DrawTextExW(HANDLE hdc,string text,int text,RECT &lprc,uint format,DRAWTEXTPARAMS &lpdtp); -int DrawTextW(HANDLE hdc,const string text,int text,RECT &lprc,uint format); -int EmptyClipboard(void); -int EnableMenuItem(HANDLE menu,uint uIDEnableItem,uint enable); -int EnableMouseInPointer(int enable); -int EnableNonClientDpiScaling(HANDLE hwnd); -int EnableScrollBar(HANDLE wnd,uint wSBflags,uint arrows); -int EnableWindow(HANDLE wnd,int enable); -int EndDeferWindowPos(HANDLE win_pos_info); -int EndDialog(HANDLE dlg,long result); -int EndMenu(void); -int EndPaint(HANDLE wnd,PAINTSTRUCT &paint); -int EndTask(HANDLE wnd,int shut_down,int force); -int EnumChildWindows(HANDLE wnd_parent,PVOID enum_func,PVOID param); -uint EnumClipboardFormats(uint format); -int EnumDesktopsW(HANDLE hwinsta,PVOID enum_func,PVOID param); -int EnumDesktopWindows(HANDLE desktop,PVOID lpfn,PVOID param); -int EnumDisplayDevicesW(const string device,uint dev_num,DISPLAY_DEVICEW &display_device,uint flags); -int EnumDisplayMonitors(HANDLE hdc,const RECT &clip,PVOID enum_obj,PVOID data); -int EnumDisplaySettingsExW(const string device_name,uint mode_num,DEVMODEW &dev_mode,uint flags); -int EnumDisplaySettingsW(const string device_name,uint mode_num,DEVMODEW &dev_mode); -int EnumPropsExW(HANDLE wnd,PVOID enum_func,PVOID param); -int EnumPropsW(HANDLE wnd,PVOID enum_func); -int EnumThreadWindows(uint thread_id,PVOID lpfn,PVOID param); -int EnumWindows(PVOID enum_func,PVOID param); -int EnumWindowStationsW(PVOID enum_func,PVOID param); -int EqualRect(RECT &lprc1,RECT &lprc2); -int EvaluateProximityToPolygon(uint vertices,const POINT &polygon[],const TOUCH_HIT_TESTING_INPUT &hit_testing_input[],TOUCH_HIT_TESTING_PROXIMITY_EVALUATION &proximity_eval); -int EvaluateProximityToRect(const RECT &bounding_box[],const TOUCH_HIT_TESTING_INPUT &hit_testing_input[],TOUCH_HIT_TESTING_PROXIMITY_EVALUATION &proximity_eval); -int ExcludeUpdateRgn(HANDLE hDC,HANDLE wnd); -int ExitWindowsEx(uint flags,uint reason); -int FillRect(HANDLE hDC,RECT &lprc,HANDLE hbr); -HANDLE FindWindowExW(HANDLE wnd_parent,HANDLE wnd_child_after,const string class_name,const string window); -HANDLE FindWindowW(const string class_name,const string window_name); -int FlashWindow(HANDLE wnd,int invert); -int FlashWindowEx(FLASHWINFO &pfwi); -int FrameRect(HANDLE hDC,RECT &lprc,HANDLE hbr); -HANDLE GetActiveWindow(void); -int GetAltTabInfoW(HANDLE hwnd,int item,ALTTABINFO &pati,string item_text,uint item_text); -HANDLE GetAncestor(HANDLE hwnd,uint flags); -short GetAsyncKeyState(int key); -int GetAutoRotationState(AR_STATE &state); -DPI_AWARENESS GetAwarenessFromDpiAwarenessContext(HANDLE value); -HANDLE GetCapture(void); -uint GetCaretBlinkTime(void); -int GetCaretPos(POINT &point); -int GetCIMSSM(INPUT_MESSAGE_SOURCE &message_source); -int GetClassInfoExW(HANDLE instance,const string class_name,WNDCLASSEXW &lpwcx); -int GetClassInfoW(HANDLE instance,const string class_name,WNDCLASSW &wnd_class); -ulong GetClassLongPtrW(HANDLE wnd,int index); -uint GetClassLongW(HANDLE wnd,int index); -int GetClassNameW(HANDLE wnd,ushort &class_name[],int max_count); -ushort GetClassWord(HANDLE wnd,int index); -int GetClientRect(HANDLE wnd,RECT &rect); -HANDLE GetClipboardData(uint format); -int GetClipboardFormatNameW(uint format,ushort &format_name[],int max_count); -HANDLE GetClipboardOwner(void); -uint GetClipboardSequenceNumber(void); -HANDLE GetClipboardViewer(void); -int GetClipCursor(RECT &rect); -int GetComboBoxInfo(HANDLE combo,COMBOBOXINFO &pcbi); -int GetCurrentInputMessageSource(INPUT_MESSAGE_SOURCE &message_source); -HANDLE GetCursor(void); -int GetCursorInfo(CURSORINFO &pci); -int GetCursorPos(POINT &point); -HANDLE GetDC(HANDLE wnd); -HANDLE GetDCEx(HANDLE wnd,HANDLE clip,uint flags); -HANDLE GetDesktopWindow(void); -int GetDialogBaseUnits(void); -DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS GetDialogControlDpiChangeBehavior(HANDLE wnd); -DIALOG_DPI_CHANGE_BEHAVIORS GetDialogDpiChangeBehavior(HANDLE dlg); -int GetDisplayAutoRotationPreferences(ORIENTATION_PREFERENCE &orientation); -int GetDisplayConfigBufferSizes(uint flags,uint &path_array_elements,uint &mode_info_array_elements); -int GetDlgCtrlID(HANDLE wnd); -HANDLE GetDlgItem(HANDLE dlg,int nIDDlgItem); -uint GetDlgItemInt(HANDLE dlg,int nIDDlgItem,int &translated,int signed); -uint GetDlgItemTextW(HANDLE dlg,int nIDDlgItem,string str,int max); -uint GetDoubleClickTime(void); -uint GetDpiForSystem(void); -uint GetDpiForWindow(HANDLE hwnd); -uint GetDpiFromDpiAwarenessContext(HANDLE value); -HANDLE GetFocus(void); -HANDLE GetForegroundWindow(void); -int GetGestureConfig(HANDLE hwnd,uint reserved,uint flags,uint &pcIDs,GESTURECONFIG &gesture_config[],uint size); -int GetGestureExtraArgs(HANDLE gesture_info,uint extra_args,uchar &extra_args); -int GetGestureInfo(HANDLE gesture_info,GESTUREINFO &gesture_info); -uint GetGuiResources(HANDLE process,uint flags); -int GetGUIThreadInfo(uint thread,GUITHREADINFO &pgui); -int GetIconInfo(HANDLE icon,ICONINFO &piconinfo); -int GetIconInfoExW(HANDLE hicon,ICONINFOEXW &piconinfo); -int GetInputState(void); -uint GetKBCodePage(void); -HANDLE GetKeyboardLayout(uint thread); -int GetKeyboardLayoutList(int buff,HANDLE &list[]); -int GetKeyboardLayoutNameW(ushort &pwszKLID[]); -int GetKeyboardState(uchar &key_state[]); -int GetKeyboardType(int type_flag); -int GetKeyNameTextW(long param,ushort &str[],int size); -short GetKeyState(int virt_key); -HANDLE GetLastActivePopup(HANDLE wnd); -int GetLastInputInfo(LASTINPUTINFO &plii); -int GetLayeredWindowAttributes(HANDLE hwnd,uint &key,uchar &alpha,uint &flags); -uint GetListBoxInfo(HANDLE hwnd); -HANDLE GetMenu(HANDLE wnd); -int GetMenuBarInfo(HANDLE hwnd,int object,int item,MENUBARINFO &pmbi); -int GetMenuCheckMarkDimensions(void); -uint GetMenuContextHelpId(HANDLE); -uint GetMenuDefaultItem(HANDLE menu,uint by_pos,uint flags); -int GetMenuInfo(HANDLE,MENUINFO &); -int GetMenuItemCount(HANDLE menu); -uint GetMenuItemID(HANDLE menu,int pos); -int GetMenuItemInfoW(HANDLE hmenu,uint item,int by_position,MENUITEMINFOW &lpmii); -int GetMenuItemRect(HANDLE wnd,HANDLE menu,uint item,RECT &item); -uint GetMenuState(HANDLE menu,uint id,uint flags); -int GetMenuStringW(HANDLE menu,uint uIDItem,string str,int max,uint flags); -PVOID GetMessageExtraInfo(void); -uint GetMessagePos(void); -int GetMessageTime(void); -int GetMessageW(MSG &msg,HANDLE wnd,uint msg_filter_min,uint msg_filter_max); -int GetMonitorInfoW(HANDLE monitor,MONITORINFO &lpmi); -int GetMouseMovePointsEx(uint size,MOUSEMOVEPOINT &lppt,MOUSEMOVEPOINT &buf,int buf_points,uint resolution); -HANDLE GetNextDlgGroupItem(HANDLE dlg,HANDLE ctl,int previous); -HANDLE GetNextDlgTabItem(HANDLE dlg,HANDLE ctl,int previous); -HANDLE GetOpenClipboardWindow(void); -HANDLE GetParent(HANDLE wnd); -int GetPhysicalCursorPos(POINT &point); -int GetPointerCursorId(uint pointer_id,uint &cursor_id); -int GetPointerDevice(HANDLE device,POINTER_DEVICE_INFO &device); -int GetPointerDeviceCursors(HANDLE device,uint &count,POINTER_DEVICE_CURSOR_INFO &cursors[]); -int GetPointerDeviceProperties(HANDLE device,uint &count,POINTER_DEVICE_PROPERTY &properties[]); -int GetPointerDeviceRects(HANDLE device,RECT &device_rect,RECT &rect); -int GetPointerDevices(uint &count,POINTER_DEVICE_INFO &devices[]); -int GetPointerFrameInfo(uint id,uint &count,POINTER_INFO &info[]); -int GetPointerFrameInfoHistory(uint id,uint &count,uint &count,POINTER_INFO &info[]); -int GetPointerFramePenInfo(uint id,uint &count,POINTER_PEN_INFO &info[]); -int GetPointerFramePenInfoHistory(uint id,uint &count,uint &count,POINTER_PEN_INFO &info[]); -int GetPointerFrameTouchInfo(uint id,uint &count,POINTER_TOUCH_INFO &info[]); -int GetPointerFrameTouchInfoHistory(uint id,uint &count,uint &count,POINTER_TOUCH_INFO &info[]); -int GetPointerInfo(uint id,POINTER_INFO &info[]); -int GetPointerInfoHistory(uint id,uint &count,POINTER_INFO &info[]); -int GetPointerInputTransform(uint id,uint count,INPUT_TRANSFORM &transform); -int GetPointerPenInfo(uint id,POINTER_PEN_INFO &info); -int GetPointerPenInfoHistory(uint id,uint &count,POINTER_PEN_INFO &info); -int GetPointerTouchInfo(uint id,POINTER_TOUCH_INFO &info[]); -int GetPointerTouchInfoHistory(uint id,uint &count,POINTER_TOUCH_INFO &info[]); -int GetPointerType(uint id,uint &type); -int GetPriorityClipboardFormat(uint &format_priority_list[],int formats); -int GetProcessDefaultLayout(uint &default_layout); -HANDLE GetProcessWindowStation(void); -HANDLE GetPropW(HANDLE wnd,const string str); -uint GetQueueStatus(uint flags); -uint GetRawInputBuffer(RAWINPUT &data,uint &size,uint size_header); -uint GetRawInputData(HANDLE raw_input,uint command,PVOID data,uint &size,uint size_header); -uint GetRawInputDeviceInfoW(HANDLE device,uint command,PVOID data,uint &size); -uint GetRawInputDeviceList(RAWINPUTDEVICELIST &raw_input_device_list,uint &num_devices,uint size); -int GetRawPointerDeviceData(uint id,uint count,uint count,POINTER_DEVICE_PROPERTY &properties[],int &values[]); -uint GetRegisteredRawInputDevices(RAWINPUTDEVICE &raw_input_devices,uint &num_devices,uint size); -int GetScrollBarInfo(HANDLE hwnd,int object,SCROLLBARINFO &psbi); -int GetScrollInfo(HANDLE hwnd,int bar,SCROLLINFO &lpsi); -int GetScrollPos(HANDLE wnd,int bar); -int GetScrollRange(HANDLE wnd,int bar,int &min_pos,int &max_pos); -HANDLE GetShellWindow(void); -HANDLE GetSubMenu(HANDLE menu,int pos); -uint GetSysColor(int index); -HANDLE GetSysColorBrush(int index); -uint GetSystemDpiForProcess(HANDLE process); -HANDLE GetSystemMenu(HANDLE wnd,int revert); -int GetSystemMetrics(int index); -int GetSystemMetricsForDpi(int index,uint dpi); -uint GetTabbedTextExtentW(HANDLE hdc,const string str,int count,int tab_positions,const int &tab_stop_positions[]); -HANDLE GetThreadDesktop(uint thread_id); -HANDLE GetThreadDpiAwarenessContext(void); -DPI_HOSTING_BEHAVIOR GetThreadDpiHostingBehavior(void); -int GetTitleBarInfo(HANDLE hwnd,TITLEBARINFO &pti); -HANDLE GetTopWindow(HANDLE wnd); -int GetTouchInputInfo(HANDLE touch_input,uint inputs,TOUCHINPUT &inputs,int size); -uint GetUnpredictedMessagePos(void); -int GetUpdatedClipboardFormats(uint &formats[],uint formats_number,uint &formats_out); -int GetUpdateRect(HANDLE wnd,RECT &rect,int erase); -int GetUpdateRgn(HANDLE wnd,HANDLE rgn,int erase); -int GetUserObjectInformationW(HANDLE obj,int index,PVOID info,uint length,uint &length_needed); -int GetUserObjectSecurity(HANDLE obj,uint &pSIRequested,SECURITY_DESCRIPTOR &pSID,uint length,uint &length_needed); -HANDLE GetWindow(HANDLE wnd,uint cmd); -uint GetWindowContextHelpId(HANDLE); -HANDLE GetWindowDC(HANDLE wnd); -int GetWindowDisplayAffinity(HANDLE wnd,uint &affinity); -HANDLE GetWindowDpiAwarenessContext(HANDLE hwnd); -DPI_HOSTING_BEHAVIOR GetWindowDpiHostingBehavior(HANDLE hwnd); -int GetWindowFeedbackSetting(HANDLE hwnd,FEEDBACK_TYPE feedback,uint flags,uint size,int &config); -int GetWindowInfo(HANDLE hwnd,WINDOWINFO &pwi); -long GetWindowLongPtrW(HANDLE wnd,int index); -int GetWindowLongW(HANDLE wnd,int index); -uint GetWindowModuleFileNameW(HANDLE hwnd,ushort &file_name[],uint file_name_max); -int GetWindowPlacement(HANDLE wnd,WINDOWPLACEMENT &lpwndpl); -int GetWindowRect(HANDLE wnd,RECT &rect); -int GetWindowRgn(HANDLE wnd,HANDLE rgn); -int GetWindowRgnBox(HANDLE wnd,RECT &lprc); -int GetWindowTextLengthW(HANDLE wnd); -int GetWindowTextW(HANDLE wnd,ushort &str[],int max_count); -uint GetWindowThreadProcessId(HANDLE wnd,uint &process_id); -ushort GetWindowWord(HANDLE wnd,int index); -int GrayStringW(HANDLE hDC,HANDLE brush,PVOID output_func,uchar &data[],int count,int X,int Y,int width,int height); -int GrayStringW(HANDLE hDC,HANDLE brush,PVOID output_func,PVOID data,int count,int X,int Y,int width,int height); -int HideCaret(HANDLE wnd); -int HiliteMenuItem(HANDLE wnd,HANDLE menu,uint uIDHiliteItem,uint hilite); -int InflateRect(RECT &lprc,int dx,int dy); -int InheritWindowMonitor(HANDLE hwnd,HANDLE inherit); -int InitializeTouchInjection(uint count,uint mode); -int InjectTouchInput(uint count,POINTER_TOUCH_INFO &contacts); -int InSendMessage(void); -uint InSendMessageEx(PVOID reserved); -int InsertMenuItemW(HANDLE hmenu,uint item,int by_position,const MENUITEMINFO &lpmi); -int InsertMenuW(HANDLE menu,uint position,uint flags,ulong uIDNewItem,const string new_item); -int InternalGetWindowText(HANDLE wnd,string str,int max_count); -int IntersectRect(RECT &dst,RECT &src1,RECT &src2); -int InvalidateRect(HANDLE wnd,RECT &rect,int erase); -int InvalidateRgn(HANDLE wnd,HANDLE rgn,int erase); -int InvertRect(HANDLE hDC,RECT &lprc); -int IsCharAlphaNumericW(short ch); -int IsCharAlphaW(short ch); -int IsCharLowerW(short ch); -int IsCharUpperW(short ch); -int IsChild(HANDLE wnd_parent,HANDLE wnd); -int IsClipboardFormatAvailable(uint format); -int IsDialogMessageW(HANDLE dlg,MSG &msg); -uint IsDlgButtonChecked(HANDLE dlg,int nIDButton); -int IsGUIThread(int convert); -int IsHungAppWindow(HANDLE hwnd); -int IsIconic(HANDLE wnd); -int IsImmersiveProcess(HANDLE process); -int IsMenu(HANDLE menu); -int IsMouseInPointerEnabled(void); -int IsProcessDPIAware(void); -int IsRectEmpty(RECT &lprc); -int IsTouchWindow(HANDLE hwnd,uint &flags); -int IsValidDpiAwarenessContext(HANDLE value); -int IsWindow(HANDLE wnd); -int IsWindowEnabled(HANDLE wnd); -int IsWindowUnicode(HANDLE wnd); -int IsWindowVisible(HANDLE wnd); -int IsWinEventHookInstalled(uint event); -int IsWow64Message(void); -int IsZoomed(HANDLE wnd); -void keybd_event(uchar vk,uchar scan,uint flags,ulong extra_info); -int KillTimer(HANDLE wnd,ulong uIDEvent); -HANDLE LoadAcceleratorsW(HANDLE instance,const string table_name); -HANDLE LoadBitmapW(HANDLE instance,const string bitmap_name); -HANDLE LoadCursorFromFileW(const string file_name); -HANDLE LoadCursorW(HANDLE instance,const string cursor_name); -HANDLE LoadIconW(HANDLE instance,const string icon_name); -HANDLE LoadImageW(HANDLE inst,const string name,uint type,int cx,int cy,uint load); -HANDLE LoadKeyboardLayoutW(const string pwszKLID,uint Flags); -HANDLE LoadMenuIndirectW(const PVOID menu_template); -HANDLE LoadMenuW(HANDLE instance,const string menu_name); -int LoadStringW(HANDLE instance,uint uID,string buffer,int buffer_max); -int LockSetForegroundWindow(uint lock_code); -int LockWindowUpdate(HANDLE wnd_lock); -int LockWorkStation(void); -int LogicalToPhysicalPoint(HANDLE wnd,POINT &point); -int LogicalToPhysicalPointForPerMonitorDPI(HANDLE wnd,POINT &point); -int LookupIconIdFromDirectory(uchar &presbits[],int icon); -int LookupIconIdFromDirectoryEx(uchar &presbits,int icon,int desired,int desired,uint Flags); -int MapDialogRect(HANDLE dlg,RECT &rect); -uint MapVirtualKeyExW(uint code,uint map_type,HANDLE dwhkl); -uint MapVirtualKeyW(uint code,uint map_type); -int MapWindowPoints(HANDLE wnd_from,HANDLE wnd_to,POINT &points[],uint points_count); -int MenuItemFromPoint(HANDLE wnd,HANDLE menu,POINT &screen); -int MessageBeep(uint type); -int MessageBoxExW(HANDLE wnd,const string text,const string caption,uint type,ushort language_id); -int MessageBoxIndirectW(MSGBOXPARAMSW &lpmbp); -int MessageBoxW(HANDLE wnd,const string text,const string caption,uint type); -int ModifyMenuW(HANDLE mnu,uint position,uint flags,ulong uIDNewItem,const string new_item); -HANDLE MonitorFromPoint(POINT &pt,uint flags); -HANDLE MonitorFromRect(const RECT &lprc,uint flags); -HANDLE MonitorFromWindow(HANDLE hwnd,uint flags); -void mouse_event(uint flags,uint dx,uint dy,uint data,ulong extra_info); -int MoveWindow(HANDLE wnd,int X,int Y,int width,int height,int repaint); -uint MsgWaitForMultipleObjects(uint count,const HANDLE &handles[],int wait_all,uint milliseconds,uint wake_mask); -uint MsgWaitForMultipleObjectsEx(uint count,const HANDLE &handles[],uint milliseconds,uint wake_mask,uint flags); -void NotifyWinEvent(uint event,HANDLE hwnd,int object,int child); -uint OemKeyScan(ushort oem_char); -int OemToCharBuffW(const char &src[],ushort &dst[],uint dst_length); -int OemToCharW(const char &src[],ushort &dst[]); -int OffsetRect(RECT &lprc,int dx,int dy); -int OpenClipboard(HANDLE wnd_new_owner); -HANDLE OpenDesktopW(const string desktop,uint flags,int inherit,uint desired_access); -int OpenIcon(HANDLE wnd); -HANDLE OpenInputDesktop(uint flags,int inherit,uint desired_access); -HANDLE OpenWindowStationW(const string win_sta,int inherit,uint desired_access); -PVOID PackTouchHitTestingProximityEvaluation(const TOUCH_HIT_TESTING_INPUT &hit_testing_input[],const TOUCH_HIT_TESTING_PROXIMITY_EVALUATION &proximity_eval[]); -int PaintDesktop(HANDLE hdc); -int PeekMessageW(MSG &msg,HANDLE wnd,uint msg_filter_min,uint msg_filter_max,uint remove_msg); -int PhysicalToLogicalPoint(HANDLE wnd,POINT &point); -int PhysicalToLogicalPointForPerMonitorDPI(HANDLE wnd,POINT &point); -int PostMessageW(HANDLE wnd,uint Msg,PVOID param,PVOID param); -void PostQuitMessage(int exit_code); -int PostThreadMessageW(uint thread,uint Msg,PVOID param,PVOID param); -int PrintWindow(HANDLE hwnd,HANDLE blt,uint flags); -uint PrivateExtractIconsW(const string file_name,int icon_index,int icon,int icon,HANDLE &phicon,uint &piconid,uint icons,uint flags); -int PtInRect(const RECT &lprc,long pt); -long QueryDisplayConfig(uint flags,uint &path_array_elements,DISPLAYCONFIG_PATH_INFO &array,uint &mode_info_array_elements,DISPLAYCONFIG_MODE_INFO &info_array[],DISPLAYCONFIG_TOPOLOGY_ID &topology_id); -HANDLE RealChildWindowFromPoint(HANDLE parent,long parent_client_coords); -uint RealGetWindowClassW(HANDLE hwnd,ushort &class_name[],uint class_name_max); -int RedrawWindow(HANDLE wnd,RECT &rect,HANDLE update,uint flags); -ushort RegisterClassExW(const WNDCLASSEXW &lpwcx); -ushort RegisterClassW(const WNDCLASSW &wnd_class); -uint RegisterClipboardFormatW(const string format); -PVOID RegisterDeviceNotificationW(HANDLE recipient,PVOID NotificationFilter,uint Flags); -int RegisterHotKey(HANDLE wnd,int id,uint modifiers,uint vk); -int RegisterPointerDeviceNotifications(HANDLE window,int range); -int RegisterPointerInputTarget(HANDLE hwnd,uint type); -int RegisterPointerInputTargetEx(HANDLE hwnd,uint type,int observe); -PVOID RegisterPowerSettingNotification(HANDLE recipient,const GUID &PowerSettingGuid,uint Flags); -int RegisterRawInputDevices(const RAWINPUTDEVICE &raw_input_devices[],uint num_devices,uint size); -int RegisterShellHookWindow(HANDLE hwnd); -PVOID RegisterSuspendResumeNotification(HANDLE recipient,uint Flags); -int RegisterTouchHitTestingWindow(HANDLE hwnd,uint value); -int RegisterTouchWindow(HANDLE hwnd,uint flags); -uint RegisterWindowMessageW(const string str); -int ReleaseCapture(void); -int ReleaseDC(HANDLE wnd,HANDLE hDC); -int RemoveClipboardFormatListener(HANDLE hwnd); -int RemoveMenu(HANDLE menu,uint position,uint flags); -HANDLE RemovePropW(HANDLE wnd,const string str); -int ReplyMessage(PVOID result); -int ScreenToClient(HANDLE wnd,POINT &point); -int ScrollDC(HANDLE hDC,int dx,int dy,RECT &scroll,RECT &clip,HANDLE update,RECT &update); -int ScrollWindow(HANDLE wnd,int XAmount,int YAmount,RECT &rect,RECT &clip_rect); -int ScrollWindowEx(HANDLE wnd,int dx,int dy,RECT &scroll,RECT &clip,HANDLE update,RECT &update,uint flags); -PVOID SendDlgItemMessageW(HANDLE dlg,int nIDDlgItem,uint Msg,PVOID param,PVOID param); -uint SendInput(uint inputs,INPUT &inputs[],int size); -int SendMessageCallbackW(HANDLE wnd,uint Msg,PVOID param,PVOID param,PVOID result_call_back,ulong data); -PVOID SendMessageTimeoutW(HANDLE wnd,uint Msg,PVOID param,PVOID param,uint flags,uint timeout,PVOID result); -PVOID SendMessageW(HANDLE wnd,uint Msg,PVOID param,PVOID param); -int SendNotifyMessageW(HANDLE wnd,uint Msg,PVOID param,PVOID param); -HANDLE SetActiveWindow(HANDLE wnd); -HANDLE SetCapture(HANDLE wnd); -int SetCaretBlinkTime(uint uMSeconds); -int SetCaretPos(int X,int Y); -ulong SetClassLongPtrW(HANDLE wnd,int index,long new_long); -uint SetClassLongW(HANDLE wnd,int index,int new_long); -ushort SetClassWord(HANDLE wnd,int index,ushort new_word); -HANDLE SetClipboardData(uint format,HANDLE mem); -HANDLE SetClipboardViewer(HANDLE wnd_new_viewer); -ulong SetCoalescableTimer(HANDLE wnd,ulong nIDEvent,uint elapse,PVOID timer_func,uint tolerance_delay); -HANDLE SetCursor(HANDLE cursor); -int SetCursorPos(int X,int Y); -void SetDebugErrorLevel(uint level); -int SetDialogControlDpiChangeBehavior(HANDLE wnd,DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS mask,DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS values); -int SetDialogDpiChangeBehavior(HANDLE dlg,DIALOG_DPI_CHANGE_BEHAVIORS mask,DIALOG_DPI_CHANGE_BEHAVIORS values); -int SetDisplayAutoRotationPreferences(ORIENTATION_PREFERENCE orientation); -int SetDisplayConfig(uint path_array_elements,DISPLAYCONFIG_PATH_INFO &array,uint mode_info_array_elements,DISPLAYCONFIG_MODE_INFO &info_array[],uint flags); -int SetDlgItemInt(HANDLE dlg,int nIDDlgItem,uint value,int signed); -int SetDlgItemTextW(HANDLE dlg,int nIDDlgItem,const string str); -int SetDoubleClickTime(uint); -HANDLE SetFocus(HANDLE wnd); -int SetForegroundWindow(HANDLE wnd); -int SetGestureConfig(HANDLE hwnd,uint reserved,uint cIDs,GESTURECONFIG &gesture_config[],uint size); -int SetKeyboardState(uchar &key_state[]); -void SetLastErrorEx(uint err_code,uint type); -int SetLayeredWindowAttributes(HANDLE hwnd,uint key,uchar alpha,uint flags); -int SetMenu(HANDLE wnd,HANDLE menu); -int SetMenuContextHelpId(HANDLE,uint); -int SetMenuDefaultItem(HANDLE menu,uint item,uint by_pos); -int SetMenuInfo(HANDLE,const MENUINFO &); -int SetMenuItemBitmaps(HANDLE menu,uint position,uint flags,HANDLE bitmap_unchecked,HANDLE bitmap_checked); -int SetMenuItemInfoW(HANDLE hmenu,uint item,int by_positon,const MENUITEMINFOW &lpmii); -PVOID SetMessageExtraInfo(PVOID param); -int SetMessageQueue(int messages_max); -HANDLE SetParent(HANDLE wnd_child,HANDLE wnd_new_parent); -int SetPhysicalCursorPos(int X,int Y); -int SetProcessDefaultLayout(uint default_layout); -int SetProcessDPIAware(void); -int SetProcessDpiAwarenessContext(HANDLE value); -int SetProcessRestrictionExemption(int enable_exemption); -int SetProcessWindowStation(HANDLE win_sta); -int SetPropW(HANDLE wnd,const string str,HANDLE data); -int SetRect(RECT &lprc,int left,int top,int right,int bottom); -int SetRectEmpty(RECT &lprc); -int SetScrollInfo(HANDLE hwnd,int bar,const SCROLLINFO &lpsi,int redraw); -int SetScrollPos(HANDLE wnd,int bar,int pos,int redraw); -int SetScrollRange(HANDLE wnd,int bar,int min_pos,int max_pos,int redraw); -int SetSysColors(int elements_count,int &elements[],uint &rgb_values[]); -int SetSystemCursor(HANDLE hcur,uint id); -int SetThreadDesktop(HANDLE desktop); -HANDLE SetThreadDpiAwarenessContext(HANDLE context); -DPI_HOSTING_BEHAVIOR SetThreadDpiHostingBehavior(DPI_HOSTING_BEHAVIOR value); -ulong SetTimer(HANDLE wnd,ulong nIDEvent,uint elapse,PVOID timer_func); -int SetUserObjectInformationW(HANDLE obj,int index,PVOID info,uint length); -int SetUserObjectSecurity(HANDLE obj,uint pSIRequested,SECURITY_DESCRIPTOR &pSID); -int SetWindowContextHelpId(HANDLE,uint); -int SetWindowDisplayAffinity(HANDLE wnd,uint affinity); -int SetWindowFeedbackSetting(HANDLE hwnd,FEEDBACK_TYPE feedback,uint flags,uint size,PVOID configuration); -long SetWindowLongPtrW(HANDLE wnd,int index,long new_long); -int SetWindowLongW(HANDLE wnd,int index,int new_long); -int SetWindowPlacement(HANDLE wnd,WINDOWPLACEMENT &lpwndpl); -int SetWindowPos(HANDLE wnd,HANDLE wnd_insert_after,int X,int Y,int cx,int cy,uint flags); -int SetWindowRgn(HANDLE wnd,HANDLE rgn,int redraw); -HANDLE SetWindowsHookExW(int hook,PVOID lpfn,HANDLE hmod,uint thread_id); -HANDLE SetWindowsHookW(int filter_type,PVOID filter_proc); -int SetWindowTextW(HANDLE wnd,const string str); -ushort SetWindowWord(HANDLE wnd,int index,ushort &new_word); -HANDLE SetWinEventHook(uint min,uint max,HANDLE win_event_proc,PVOID win_event_proc,uint process,uint thread,uint flags); -int ShowCaret(HANDLE wnd); -int ShowCursor(int show); -int ShowOwnedPopups(HANDLE wnd,int show); -int ShowScrollBar(HANDLE wnd,int bar,int show); -int ShowWindow(HANDLE wnd,int cmd_show); -int ShowWindowAsync(HANDLE wnd,int cmd_show); -int ShutdownBlockReasonCreate(HANDLE wnd,const string reason); -int ShutdownBlockReasonDestroy(HANDLE wnd); -int ShutdownBlockReasonQuery(HANDLE wnd,string buff,uint &buff[]); -int SkipPointerFrameMessages(uint id); -int SoundSentry(void); -int SubtractRect(RECT &dst,RECT &src1,RECT &src2); -int SwapMouseButton(int swap); -int SwitchDesktop(HANDLE desktop); -void SwitchToThisWindow(HANDLE hwnd,int unknown); -int SystemParametersInfoForDpi(uint action,uint param,PVOID param,uint win_ini,uint dpi); -int SystemParametersInfoW(uint action,uint param,PVOID param,uint win_ini); -int TabbedTextOutW(HANDLE hdc,int x,int y,const string str,int count,int tab_positions,const int &tab_stop_positions[],int tab_origin); -ushort TileWindows(HANDLE parent,uint how,const RECT &rect,uint kids,const HANDLE &kids[]); -int ToAscii(uint virt_key,uint scan_code,const uchar &key_state[],ushort &symbol,uint flags); -int ToAsciiEx(uint virt_key,uint scan_code,const uchar &key_state[],ushort &symbol,uint flags,HANDLE dwhkl); -int ToUnicode(uint virt_key,uint scan_code,const uchar &key_state[],ushort &buff[],int buff_size,uint flags); -int ToUnicodeEx(uint virt_key,uint scan_code,const uchar &key_state[],ushort &buff[],int buff_size,uint flags,HANDLE dwhkl); -int TrackMouseEvent(TRACKMOUSEEVENT &event_track); -int TrackPopupMenu(HANDLE menu,uint flags,int x,int y,int reserved,HANDLE wnd,RECT &rect); -int TrackPopupMenuEx(HANDLE menu,uint flags,int x,int y,HANDLE hwnd,TPMPARAMS &lptpm); -int TranslateAcceleratorW(HANDLE wnd,HANDLE acc_table,MSG &msg); -int TranslateMDISysAccel(HANDLE wnd_client,MSG &msg); -int TranslateMessage(MSG &msg); -int UnhookWindowsHook(int code,PVOID filter_proc); -int UnhookWindowsHookEx(HANDLE hhk); -int UnhookWinEvent(HANDLE win_event_hook); -int UnionRect(RECT &dst,RECT &src1,RECT &src2); -int UnloadKeyboardLayout(HANDLE hkl); -int UnregisterClassW(const PVOID class_name,HANDLE instance); -int UnregisterClassW(const string class_name,HANDLE instance); -int UnregisterDeviceNotification(PVOID Handle); -int UnregisterHotKey(HANDLE wnd,int id); -int UnregisterPointerInputTarget(HANDLE hwnd,uint type); -int UnregisterPointerInputTargetEx(HANDLE hwnd,uint type); -int UnregisterPowerSettingNotification(PVOID Handle); -int UnregisterSuspendResumeNotification(PVOID Handle); -int UnregisterTouchWindow(HANDLE hwnd); -int UpdateLayeredWindow(HANDLE wnd,HANDLE dst,POINT &dst,SIZE &psize,HANDLE src,POINT &src,uint key,BLENDFUNCTION &pblend,uint flags); -int UpdateLayeredWindowIndirect(HANDLE wnd,const UPDATELAYEREDWINDOWINFO &pULWInfo[]); -int UpdateWindow(HANDLE wnd); -int UserHandleGrantAccess(HANDLE user_handle,HANDLE job,int grant); -int ValidateRect(HANDLE wnd,RECT &rect); -int ValidateRgn(HANDLE wnd,HANDLE rgn); -short VkKeyScanExW(ushort ch,HANDLE dwhkl); -short VkKeyScanW(ushort ch); -uint WaitForInputIdle(HANDLE process,uint milliseconds); -int WaitMessage(void); -HANDLE WindowFromDC(HANDLE hDC); -HANDLE WindowFromPhysicalPoint(long point); -HANDLE WindowFromPoint(long point); -int WinHelpW(HANDLE wnd_main,const string help,uint command,ulong data); -int wvsprintfW(ushort &[],const string,PVOID &arglist[]); -#import -//+------------------------------------------------------------------+ diff --git a/Include/stderror.mqh b/Include/stderror.mqh deleted file mode 100644 index daa4877..0000000 --- a/Include/stderror.mqh +++ /dev/null @@ -1,99 +0,0 @@ -//+------------------------------------------------------------------+ -//| stderror.mqh | -//| Copyright © 2004-2007, MetaQuotes Software Corp. | -//| http://www.metaquotes.net/ | -//+------------------------------------------------------------------+ -//---- errors returned from trade server -#define ERR_NO_ERROR 0 -#define ERR_NO_RESULT 1 -#define ERR_COMMON_ERROR 2 -#define ERR_INVALID_TRADE_PARAMETERS 3 -#define ERR_SERVER_BUSY 4 -#define ERR_OLD_VERSION 5 -#define ERR_NO_CONNECTION 6 -#define ERR_NOT_ENOUGH_RIGHTS 7 -#define ERR_TOO_FREQUENT_REQUESTS 8 -#define ERR_MALFUNCTIONAL_TRADE 9 -#define ERR_ACCOUNT_DISABLED 64 -#define ERR_INVALID_ACCOUNT 65 -#define ERR_TRADE_TIMEOUT 128 -#define ERR_INVALID_PRICE 129 -#define ERR_INVALID_STOPS 130 -#define ERR_INVALID_TRADE_VOLUME 131 -#define ERR_MARKET_CLOSED 132 -#define ERR_TRADE_DISABLED 133 -#define ERR_NOT_ENOUGH_MONEY 134 -#define ERR_PRICE_CHANGED 135 -#define ERR_OFF_QUOTES 136 -#define ERR_BROKER_BUSY 137 -#define ERR_REQUOTE 138 -#define ERR_ORDER_LOCKED 139 -#define ERR_LONG_POSITIONS_ONLY_ALLOWED 140 -#define ERR_TOO_MANY_REQUESTS 141 -#define ERR_TRADE_MODIFY_DENIED 145 -#define ERR_TRADE_CONTEXT_BUSY 146 -#define ERR_TRADE_EXPIRATION_DENIED 147 -#define ERR_TRADE_TOO_MANY_ORDERS 148 -//---- mql4 run time errors -#define ERR_NO_MQLERROR 4000 -#define ERR_WRONG_FUNCTION_POINTER 4001 -#define ERR_ARRAY_INDEX_OUT_OF_RANGE 4002 -#define ERR_NO_MEMORY_FOR_CALL_STACK 4003 -#define ERR_RECURSIVE_STACK_OVERFLOW 4004 -#define ERR_NOT_ENOUGH_STACK_FOR_PARAM 4005 -#define ERR_NO_MEMORY_FOR_PARAM_STRING 4006 -#define ERR_NO_MEMORY_FOR_TEMP_STRING 4007 -#define ERR_NOT_INITIALIZED_STRING 4008 -#define ERR_NOT_INITIALIZED_ARRAYSTRING 4009 -#define ERR_NO_MEMORY_FOR_ARRAYSTRING 4010 -#define ERR_TOO_LONG_STRING 4011 -#define ERR_REMAINDER_FROM_ZERO_DIVIDE 4012 -#define ERR_ZERO_DIVIDE 4013 -#define ERR_UNKNOWN_COMMAND 4014 -#define ERR_WRONG_JUMP 4015 -#define ERR_NOT_INITIALIZED_ARRAY 4016 -#define ERR_DLL_CALLS_NOT_ALLOWED 4017 -#define ERR_CANNOT_LOAD_LIBRARY 4018 -#define ERR_CANNOT_CALL_FUNCTION 4019 -#define ERR_EXTERNAL_CALLS_NOT_ALLOWED 4020 -#define ERR_NO_MEMORY_FOR_RETURNED_STR 4021 -#define ERR_SYSTEM_BUSY 4022 -#define ERR_INVALID_FUNCTION_PARAMSCNT 4050 -#define ERR_INVALID_FUNCTION_PARAMVALUE 4051 -#define ERR_STRING_FUNCTION_INTERNAL 4052 -#define ERR_SOME_ARRAY_ERROR 4053 -#define ERR_INCORRECT_SERIESARRAY_USING 4054 -#define ERR_CUSTOM_INDICATOR_ERROR 4055 -#define ERR_INCOMPATIBLE_ARRAYS 4056 -#define ERR_GLOBAL_VARIABLES_PROCESSING 4057 -#define ERR_GLOBAL_VARIABLE_NOT_FOUND 4058 -#define ERR_FUNC_NOT_ALLOWED_IN_TESTING 4059 -#define ERR_FUNCTION_NOT_CONFIRMED 4060 -#define ERR_SEND_MAIL_ERROR 4061 -#define ERR_STRING_PARAMETER_EXPECTED 4062 -#define ERR_INTEGER_PARAMETER_EXPECTED 4063 -#define ERR_DOUBLE_PARAMETER_EXPECTED 4064 -#define ERR_ARRAY_AS_PARAMETER_EXPECTED 4065 -#define ERR_HISTORY_WILL_UPDATED 4066 -#define ERR_TRADE_ERROR 4067 -#define ERR_END_OF_FILE 4099 -#define ERR_SOME_FILE_ERROR 4100 -#define ERR_WRONG_FILE_NAME 4101 -#define ERR_TOO_MANY_OPENED_FILES 4102 -#define ERR_CANNOT_OPEN_FILE 4103 -#define ERR_INCOMPATIBLE_FILEACCESS 4104 -#define ERR_NO_ORDER_SELECTED 4105 -#define ERR_UNKNOWN_SYMBOL 4106 -#define ERR_INVALID_PRICE_PARAM 4107 -#define ERR_INVALID_TICKET 4108 -#define ERR_TRADE_NOT_ALLOWED 4109 -#define ERR_LONGS_NOT_ALLOWED 4110 -#define ERR_SHORTS_NOT_ALLOWED 4111 -#define ERR_OBJECT_ALREADY_EXISTS 4200 -#define ERR_UNKNOWN_OBJECT_PROPERTY 4201 -#define ERR_OBJECT_DOES_NOT_EXIST 4202 -#define ERR_UNKNOWN_OBJECT_TYPE 4203 -#define ERR_NO_OBJECT_NAME 4204 -#define ERR_OBJECT_COORDINATES_ERROR 4205 -#define ERR_NO_SPECIFIED_SUBWINDOW 4206 -#define ERR_SOME_OBJECT_ERROR 4207 diff --git a/Include/variables.mqh b/Include/variables.mqh deleted file mode 100644 index c43ae67..0000000 --- a/Include/variables.mqh +++ /dev/null @@ -1,32 +0,0 @@ -//-------------------------------------------------------------------- -// Variables.mqh -// Предназначен для использования в качестве примера в учебнике MQL4. -//--------------------------------------------------------------- 1 -- -// Описание глобальных переменных -extern double Lots =0.0; // Количество лотов -extern int Percent =0; // Процент выделенных средств -extern int StopLoss =100; // StopLoss для новых ордеров (пунктов) -extern int TakeProfit =40; // TakeProfit для новых ордеров (пунктов) -extern int TralingStop=100; // TralingStop для рыночных ордеров (пунк) -//--------------------------------------------------------------- 2 -- -int - Level_new, // Новое значение минимальной дистанции - Level_old, // Предыдущее значение минимальной дистанции - Mas_Tip[6]; // Массив типов ордеров - // [] тип орд: 0=B,1=S,2=BL,3=SL,4=BS,5=SS -//--------------------------------------------------------------- 3 -- -double - Lots_New, // Количество лотов для новых ордеров - Mas_Ord_New[31][9], // Массив ордеров текущий .. - Mas_Ord_Old[31][9]; // .. и старый - // 1й индекс = порядковый номер ордера - // [][0] не определяется - // [][1] курс откр. ордера (абс.знач.курса) - // [][2] StopLoss ордера (абс.знач.курса) - // [][3] TakeProfit ордера (абс.знач.курса) - // [][4] номер ордера - // [][5] колич. лотов орд. (абс.знач.курса) - // [][6] тип орд. 0=B,1=S,2=BL,3=SL,4=BS,5=SS - // [][7] магическое число ордера - // [][8] 0/1 факт наличия комментария -//--------------------------------------------------------------- 4 -- \ No newline at end of file